Skip to content

Commit 59ad3fa

Browse files
committed
security: complete remaining hardening
1 parent ec05acc commit 59ad3fa

255 files changed

Lines changed: 16857 additions & 4174 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/supply-chain.yml‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
- "**/Cargo.toml"
88
- "**/Cargo.lock"
99
- supply-chain/**
10+
- fuzz/supply-chain/**
1011
- deny.toml
1112
- scripts/ci/check_advisory_ignores.py
1213
- .github/workflows/supply-chain.yml
@@ -16,6 +17,7 @@ on:
1617
- "**/Cargo.toml"
1718
- "**/Cargo.lock"
1819
- supply-chain/**
20+
- fuzz/supply-chain/**
1921
- deny.toml
2022
- scripts/ci/check_advisory_ignores.py
2123
- .github/workflows/supply-chain.yml
@@ -45,4 +47,6 @@ jobs:
4547
run: cargo install cargo-vet --version 0.10.2 --locked
4648

4749
- name: Verify dependency audits
48-
run: cargo vet --locked
50+
run: |
51+
cargo vet --locked
52+
cargo vet --locked --manifest-path fuzz/Cargo.toml

‎docs/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ Welcome to the NodeDB docs. These guides explain what each engine does, when to
5353
- [Row-Level Security](security/rls.md) — Per-row filtering with `$auth.*` context
5454
- [Audit & Change Tracking](security/audit.md) — Hash-chained audit log, SIEM export, `updated_at` patterns
5555
- [Multi-Tenancy](security/tenants.md) — Isolation, quotas, backup, GDPR purge
56+
- [Threat Model](security/threat-model.md) — Trust boundaries, entry points, and security invariants
57+
- [Pre-Merge Security Checklist](security/pre-merge-checklist.md) — Actionable security review for changes
5658
- [Real-Time](real-time.md) — LIVE SELECT, CDC change streams, consumer groups, webhook delivery, durable topics, cron scheduler
5759
- [CLI (`ndb`)](https://github.com/NodeDB-Lab/nodedb-cli) — Terminal client usage and configuration (separate repo)
5860
- [Studio](https://github.com/NodeDB-Lab/nodedb-studio) — GUI client (Dioxus desktop + web) (separate repo)

‎docs/security/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ NodeDB has a defense-in-depth security model covering authentication, authorizat
1212
- [Audit Log](audit.md) — Hash-chained audit trail, database-scoped events, DML audit, SIEM export
1313
- [Multi-Tenancy](tenants.md) — Database vs Tenant, tenant isolation, quotas, purge
1414
- [Encryption](encryption.md) — At-rest cipher per storage tier, key management, TLS
15+
- [Threat Model](threat-model.md) — Trust boundaries, entry points, invariants, and operational assumptions
16+
- [Pre-Merge Security Checklist](pre-merge-checklist.md) — Security review checklist for code changes
1517

1618
## Database Scoping
1719

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Security pre-merge checklist
2+
3+
Use this checklist for changes to a protocol, request handler, decoder, storage format, authorization path, cluster path, or egress integration.
4+
5+
## Entry points and authorization
6+
7+
- [ ] Every new client entry point authenticates through the protocol's established authentication path and routes operations through `control::server::shared::authorization` before dispatch.
8+
- [ ] Client entry points **MUST** route through shared authorization and **MUST NOT** construct `AuthenticatedIdentity` directly. Identity comes only from verified credentials or a narrowly scoped trusted-internal service constructor.
9+
- [ ] The handler dispatches an `AuthorizedTask` through the authorized dispatch/gateway path; it does not construct a client-controlled `PhysicalTask` and send it to the Data Plane.
10+
- [ ] The required capability is explicit for every new `PhysicalPlan` or operation, and permission mapping is exhaustive.
11+
- [ ] Authentication failures, catalog lookup failures, authorization failures, and unknown scopes fail closed with no default tenant/database or unauthenticated fallback.
12+
- [ ] New public/admin/health endpoints have an explicit authentication, authorization, startup-gate, rate-limit, and deployment-exposure decision.
13+
14+
## Identity, tenant, database, and RLS
15+
16+
- [ ] Claims, API-key data, client certificates, session values, request bodies, and headers are treated as untrusted until their verifier and server-side binding accept them.
17+
- [ ] Tenant authority is server-owned; an asserted token/payload tenant cannot override provider, credential, or session binding.
18+
- [ ] Database selection resolves to a catalog descriptor and is checked against the authenticated identity. A database name/header/query parameter selects a target; it does not grant access.
19+
- [ ] Every task, stream, descriptor, cache key, lease, route, audit event, and egress record that needs scope carries and checks both database ID and tenant ID.
20+
- [ ] Engine-specific identity and persisted state—including Array schema/op-log/ACK/snapshot/cursor/GC state and function/trigger/schedule registries—use explicit `(database, tenant, object)` keys. Legacy unscoped rows are accepted only by documented DEFAULT-database migration paths with scoped records taking precedence.
21+
- [ ] Session refresh/re-authentication cannot silently change tenant or database while retaining subscriptions, cursors, presence, sync engines, or other authority. Scope changes are rejected or atomically revoke and rebuild all identity-bound state.
22+
- [ ] RLS is applied after capability authorization and uses the server-derived `AuthContext`.
23+
- [ ] `X-On-Deny`, SQL `ON DENY`, and session denial settings only choose RLS-denial presentation (silent filter or error). They cannot grant database/RBAC/collection access or bypass authorization.
24+
- [ ] No raw JWT, MessagePack field, sync value, or SQL parameter is decoded into an identity override.
25+
26+
## Parsing, allocation, and query construction
27+
28+
- [ ] Decoders **MUST bounds-check before allocation**: validate framing, declared size, nesting/depth, field/label counts, decompressed size, batch size, and semantic ranges before allocating, buffering, or dispatching.
29+
- [ ] HTTP JSON/NDJSON body and stream limits, WebSocket/native/sync/RESP frame limits, ILP line/batch limits, PromQL range/result limits, and deadlines are explicit and tested.
30+
- [ ] Malformed, truncated, duplicate, oversized, invalid-UTF-8, invalid-compression, and adversarial-depth inputs are rejected without panic, unbounded work, or partial authorization.
31+
- [ ] SQL is parsed and planned; untrusted identifiers and values are not concatenated into reconstructed SQL. Use structured plans and correct identifier/value quoting where generation is necessary.
32+
- [ ] MessagePack, ILP, PromQL, sync, CRDT, and remote-read/write payloads receive equivalent syntax, type, length, and semantic validation.
33+
- [ ] Filenames and COPY/import/export paths are normalized and constrained to configured authorized roots before open; traversal and symlink escape are rejected.
34+
35+
## CDC, streams, and leases
36+
37+
- [ ] CDC poll/SSE/named-stream authorization happens before buffer reads and is bound to `(database_id, tenant_id, stream/collection)`.
38+
- [ ] CDC cursors are treated as opaque, validated positions rather than authority. They cannot be replayed across a different database, tenant, stream, or collection.
39+
- [ ] CDC offsets preserve the composite WAL position (`CdcOffset`: LSN plus sequence); consumer commits are monotonic and reject regression, including per-partition cases.
40+
- [ ] Subscription, poll, SSE, LIVE, consumer-group, and egress queues have bounded retention, fan-out, cancellation, and shutdown behavior.
41+
- [ ] Descriptor leases cover planning, dispatch, and lazy/streamed response consumption for their full lifetime; transaction/savepoint rollback releases aligned scopes, and DDL/metadata changes drain or fence conflicting work.
42+
- [ ] Parse, Describe, and EXPLAIN use metadata-only planning: they do not allocate durable identities, mutate catalogs, expand execution-only work, acquire execution leases, cache executable plans, or dispatch.
43+
- [ ] Original tasks are authorized before implicit task expansion or other side effects; the final expanded task set is authorized again before lease admission and dispatch.
44+
- [ ] Cached plans and metadata are revalidated/authorized for the current identity, database, tenant, descriptor version, and lease context before execution.
45+
46+
## Planes, cluster transport, and durability
47+
48+
- [ ] Control Plane code owns client parsing/authentication/planning/authorization; Data Plane code accepts only admitted work; Event Plane side effects re-enter through Control-to-Data authorization.
49+
- [ ] Cross-plane traffic uses the bounded SPSC bridge or Event Bus—no direct shared mutable cross-plane shortcut.
50+
- [ ] Cluster QUIC/Raft frames authenticate the peer first, then validate framing, size, version, membership, group/node identity, and message semantics before apply.
51+
- [ ] SWIM liveness information is not treated as data, membership, or authorization authority without the corresponding authenticated metadata/cluster transition.
52+
- [ ] Bootstrap/join validates one-time/expiry token lifecycle and node identity; failed joins revoke temporary peer authorization.
53+
- [ ] New WAL/segment/snapshot/catalog formats validate lengths, versions, and integrity before use and have explicit corruption/quarantine/recovery behavior.
54+
- [ ] An operation acknowledged as durable has an authoritative WAL/Raft/persistent-log write and tested restart/failover recovery; an in-memory retention buffer is never described or acknowledged as durable.
55+
- [ ] A definition and its executable content are replicated consistently. Content-addressed WASM modules are present and hash-verified on every node that may execute the function, and missing modules fail closed.
56+
- [ ] Publish and subscribe APIs for one logical topic use the same database/tenant-scoped authoritative topic subsystem; compatibility protocols do not subscribe to an unrelated change stream or abandoned registry.
57+
- [ ] CRC is described only as corruption detection. Claims of authenticity require AEAD or authenticated transport and must state the applicable configuration.
58+
59+
## Cryptography, shutdown, and operations
60+
61+
- [ ] TLS/mTLS certificate validation, hostname/SPKI policy, key rotation, revocation, and insecure/private-only mode constraints are preserved.
62+
- [ ] Encryption changes define key ownership, KMS/key-file permissions, nonce uniqueness, nonce/key usage budgets, rotation, backup/restore, and failure behavior.
63+
- [ ] Secrets, bearer tokens, private keys, raw authorization headers, and sensitive payloads are not logged, returned in errors, added to metrics labels, or placed in traces.
64+
- [ ] New webhook/Kafka/alert/telemetry egress configuration has outbound allowlisting/SSRF controls, TLS and credential handling, payload minimization, timeout/retry limits, and bounded pending work.
65+
- [ ] Startup readiness remains false until required recovery is complete. Shutdown uses the one canonical phased bus, stops admission, drains listeners and Event Plane/delivery work before final watermark/WAL phases, joins correctness-critical no-abort loops, and reserves forced process exit for a second OS signal.
66+
67+
## Verification and supply chain
68+
69+
- [ ] Unit/integration tests cover allowed and denied access, same-name cross-tenant/database attempts, malformed/oversized payloads, cursor/offset tampering, cancellation, drain, restart, recovery, failover, and registry/catalog divergence.
70+
- [ ] Fuzz/property/static tests cover parsers and decoders, integer narrowing/overflow, decompression, SQL/PromQL parsing, MessagePack/native/sync framing, and storage/frame corruption where applicable.
71+
- [ ] Tests confirm that a new entry point cannot bypass shared authorization, RLS, database binding, descriptor lease rules, or shutdown gates.
72+
- [ ] Dependency changes are reviewed with the repository's advisory policy and cargo-vet baseline for advisories, license and maintenance status, minimal features, and transitive network/crypto parsers; CI actions and tool versions remain immutable/pinned.
73+
- [ ] Secrets are supplied by approved runtime configuration, never committed; full-history secret scanning remains enabled, and release artifacts include the required dependency inventory/SBOM and provenance attestations.

0 commit comments

Comments
 (0)