1ed97fb075
CI / test (push) Has been cancelled
CI / raft-e2e (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
Close the remaining 2026-08 findings: peer TLS on leader forward, disttxn SO_ERROR, compaction catalog order, OFFSET without LIMIT, window aggregates, WebSocket mask/size/auth, SCRAM timing and cbind, B-tree leaf left-max separators, and SQL three-valued NULL comparisons.
8.2 KiB
8.2 KiB
BaraDB — Deep Audit (август 2026)
Дата: 2026-08-02 Метод: 4 паралелни одит-агента по слоеве (Storage / Query / Core / Protocol), всеки чете всички файлове в обхвата си и проверява находките срещу реалния код. Обхват: само нови дефекти — 80-те вече оправени в
BUGS.md/BUG_AUDIT.md/BARADB_CLIENT_BUGS.mdса изключени. Общо: ~28 находки | Поправени: 28 (батч 1: 5 + батч 2: 12 + батч 3: 10 + батч 4: 2) | Остават: 0
Поправени — батч 1 (5)
| # | Severity | Проблем | Файл | Fix |
|---|---|---|---|---|
| C1 | 🔴 CRITICAL | MIGRATE handler без auth gate — неавтентикиран клиент пишеше произволни key/value в базата (handleMigrationMessage → applyMigrationBatch → storeKeys → db.put). Открито независимо от 2 агента. |
core/server.nim:682 |
Добавен if not authenticated: ... continue (като REP/DISTTXN блоковете) |
| C2 | 🔴 CRITICAL | Raft commit quorum off-by-one за even-N — (N+1) div 2 commit-ваше с малцинство при четен брой възли (N=4 → 2/4). Election-ът ползваше коректното strict majority. GA обхватът е 3-node (нечетно), където формулите съвпадат. |
core/raft.nim:653 |
let majority = (node.peers.len + 1) div 2 + 1 (съвпада с election); регресионен тест за 4-node |
| H1 | 🟠 HIGH | Pre-auth memory-exhaustion DoS — parseHeader не ограничаваше length (uint32 до ~4 GiB); recvExactWithTimeout пре-алокира преди auth check. |
core/server.nim:168 |
Reject length > uint32(MaxWireStringLen) (64 MB) преди алокация |
| H4 | 🟠 HIGH | ** и ++ се lower-ваха към equality — bkPow/bkConcat липсваха в op-mapping case-а и попадаха в else: irEq (2 ** 3 → false, 'a' ++ 'b' → false). |
query/exec/lower.nim:79 |
of bkPow: irOp = irPow, of bkConcat: irOp = irAdd; 2 регресионни теста |
| H5 | 🟠 HIGH | != не е отрицание на = — irNeq short-circuit-ваше на string inequality, така че 5 != 5.0 → true, но 5 = 5.0 → true. |
query/exec/eval.nim:438 |
irNeq numeric-first (точно допълнение на irEq); регресионен тест |
Поправени — батч 2 (12)
| # | Severity | Проблем | Файл | Fix |
|---|---|---|---|---|
| H3 | 🟠 HIGH | Semi-sync partial/zero ack — връщаше LSN дори при 0 acks | core/replication.nim |
return 0 когато connected replicas < syncReplicaCount acks; 0 connected → local-only (като sync) |
| H6 | 🟠 HIGH | COUNT/SUM/AVG(DISTINCT) игнорира DISTINCT |
query/exec/lower.nim, plan_exec.nim |
aggDistinct = node.funcDistinct; dedup с HashSet в agg пътищата |
| H7 | 🟠 HIGH | UNION/INTERSECT/EXCEPT KeyError |
query/executor.nim |
Dedup fingerprint от projected cols, не row["$value"] |
| H8 | 🟠 HIGH | MERGE … THEN DELETE / matched condition no-op |
query/executor.nim |
Honor mergeMatchedDelete + mergeMatchedCondition |
| H9 | 🟠 HIGH | WAL recovery crash на torn record | storage/lsm.nim, wal.nim, recovery.nim |
Bound key/val ≤ 64 MB; validate kind преди enum cast |
| M1 | 🟡 MEDIUM | MVCC write delete-during-iteration |
core/mvcc.nim |
Collect-then-delete stale txn ids |
| M3 | 🟡 MEDIUM | checkpoint lock leak |
storage/lsm.nim |
try/finally около write lock + walLock |
| M4 | 🟡 MEDIUM | flushUnsafe clear-before-write |
storage/lsm.nim |
Clear memtable едва след успешен writeSSTable |
| M5 | 🟡 MEDIUM | Compaction empty-key skip | storage/compaction.nim |
haveLast флаг вместо lastKey = "" sentinel |
| M6 | 🟡 MEDIUM | rewriteLive remove-before-move |
storage/wal.nim |
Само атомен moveFile (rename replace) |
| L3 | 🟢 LOW | mmap offset+size overflow |
storage/mmap.nim |
Overflow-safe: offset > size - length |
| — | hygiene | Stray ELF protocol/scram |
.gitignore |
Премахнат binary + ignore entry |
Верификация (батч 2): baradadb build чист; tests/bugfix_test.nim (вкл. batch-2 suite) и tests/test_all.nim (501 OK) минават без [FAILED]. tests/prop_test.nim B-Tree suite OK (H10 не е в този батч — naive left-max fix чупи interleaved remove).
Поправени — батч 3 (10)
| # | Severity | Проблем | Файл | Fix |
|---|---|---|---|---|
| H2 | 🟠 HIGH | TLS client връзките не верифицираха сертификата | core/server.nim, core/config.nim |
Отделен tlsClient контекст; CA auto-enable verify; production fail-closed |
| M2 | 🟡 MEDIUM | disttxn refused-connect wedge | core/disttxn.nim |
getsockopt(SO_ERROR) + try/except около RPC |
| M7 | 🟡 MEDIUM | Compaction unlink преди catalog load | storage/compaction.nim, baradadb.nim |
Unlink след load + MANIFEST |
| M8 | 🟡 MEDIUM | OFFSET без LIMIT → 0 реда |
query/exec/lower.nim, plan_exec.nim |
limitCount = -1 unlimited; clamp negative |
| M9 | 🟡 MEDIUM | Window SUM/AVG/COUNT/MIN/MAX → NULL | query/exec/window.nim |
Frame aggregates |
| M10 | 🟡 MEDIUM | WebSocket unmasked client frames | core/websocket.nim |
Protocol error / close |
| M11 | 🟡 MEDIUM | WebSocket unbounded buffer | core/websocket.nim |
1 MiB frame / 4 MiB message / 125-byte control |
| M12 | 🟡 MEDIUM | SUBSCRIBE без table auth | core/websocket.nim, httpserver.nim |
canSubscribe + hasPrivilegeFor SELECT |
| L1 | 🟢 LOW | SCRAM timing user enumeration | protocol/auth.nim |
Dummy nonce+encode work за unknown users |
| L2 | 🟢 LOW | SCRAM c= не се верифицира |
protocol/auth.nim, scram.nim |
c= must match gs2 header (biws за n,,) |
Поправени — батч 4 (2)
| # | Severity | Проблем | Файл | Fix |
|---|---|---|---|---|
| H10 | 🟠 HIGH | B-tree remove separator convention — splitChild/search са left-max (key > sep → right); removeRec копираше first key на дясното дете (right-min). Naive left-max върху internal ключове чупи prop_test. |
storage/btree.nim |
Leaf borrow/remove пишат left-max; merge underflow се качва нагоре; invariant max(left) <= sep (boundary duplicates са позволени, next ги събира) |
| L4 | 🟢 LOW | NULL equality — NULL = NULL / col = NULL бяха true през string sentinel |
query/exec/eval.nim |
Сравнения, LIKE, IN, NOT, AND/OR: NULL operand → unknown (\N); IS NULL непроменен |
Остават (0)
Няма отворени находки от този одит.
Проверени и чисти (не са бъгове)
- JWT
exp/alg-confusion: pinnedjwt-nim-baraba#fbe084bverify()enforce-ва alg-match, reject-ваNONE, проверяваexp/nbf/iat, constant-time compare. auth.nimconstantTimeCompareи SCRAMverifyClientProofса constant-time; празен JWT secret fail-closed (server.nim:59).wire.nimdeserialize bounds/depth caps са sound.- CRC byte ranges /
headerSize = 40са консистентни между write/verify/load (format коментарът още казва "36" — само коментар). - Lock ordering (
walLockвdb.lock; gate предиdb.lock), mmap negative offset /close()recursion / fd handling (BUG-036/046) — непокътнати. COUNT(col)изключва NULLs (v.kind != vkNull);LIMIT 0→ празно е коректно; IN-list се lower-ва към OR/AND вериги.
Виж също: PLAN.md (Сесия 13), docs/en/known-limitations.md.