lrosales
a împins spre feature/m14-backend-prep la lrosales/broad-announce
57f838089e M14-backend W1 prep: CA scripts, mTLS verifier, incident runbook
Sub-milestone: M14-backend W1 prep (cert-manager + CA) without
the K8s pieces. The K8s/manifests/Helm work for W1 proper is
blocked on M12 W1 (not started), so this PR ships the parts
that don't need K8s.
Scripts (scripts/cert-manager/):
- ca-init.sh: generates offline root CA (RSA 4096, 10y) +
intermediate (ECDSA P-256, 1y). Passphrase-protected keys.
Outputs root + intermediate + chain + ca-bundle.json with
fingerprints and notAfter.
- ca-rotate-intermediate.sh: rotates the intermediate against
the existing root. Refuses to run >60 days before expiry
unless ROTATE_FORCE=1. Backs up the previous intermediate
before overwriting.
- test-certs.sh: generates throwaway test fixtures
(valid, wrong-cn, no-san, untrusted) for the Go tests.
- README.md: usage, security notes, related docs.
- testdata/MANIFEST.txt + .gitignore: documents and ignores
the test certs.
Verifier (internal/auth/mtls.go):
- Verifier struct wraps a *x509.CertPool (the intermediate CA)
and a SourceIDResolver callback.
- Verify() chain-checks + expiry + key usage + revocation list.
- Sentinel errors: ErrCertExpired, ErrUntrustedIssuer,
ErrMissingClientUsage, ErrRevoked.
- SourceIDResolver interface + StaticSourceIDResolver default
(parses CN of form 'source:<id>.<company_slug>').
- Revoke / Unrevoke / IsRevoked for in-memory CRL.
Tests (internal/auth/mtls_test.go):
- 9 table-driven tests, all passing:
valid cert, expired cert, untrusted CA, wrong CN, no SAN,
revoked (round-trip), nil cert, resolver unit tests,
revoke idempotency.
- Uses scripts/cert-manager/testdata fixtures; testdata is
gitignored, regenerated by test-certs.sh.
Runbook (docs/runbooks/mtls-incident.md):
- 4 incident scenarios: cert expired, cert revoked, handshake
errors spiking, private key compromise, CA compromise.
- Resolution steps + diagnosis commands + preventive measures.
- Each scenario has a 'jump to' anchor for fast on-call lookup.
What is NOT in this PR (will be in M14 W1 proper, blocked on
M12 W1):
- cert-manager Helm chart install
- ClusterIssuer + Certificate CRDs
- serving certs for ingestd/routerd/deliverd-*
- cert-manager rotation controller config
What is NOT in this PR (will be in M14 W2):
- ingestd source-side mTLS listener (the verifier is ready
and tested; W2 wires it into the HTTP server).
Co-Authored-By: Jarvis <jarvis@techno-world.net>
2cc3c273af M14: split into M14-backend + M14-ui, M14-backend runs before M13
User decision: finish all backend work before the frontend. 5 of
6 M14 workstreams are backend-only (cert-manager + ingestd mTLS +
gRPC mTLS + rotation + alerts + smoke). W4 (cert UI) is the only
frontend piece.
Reorder:
- M14-backend (W1, W2, W3, W5, W6) — runs after M12 W1, in
parallel with M13a. 13-18d.
- M14-ui (W4) — runs inside M13b W2 as a feature incremental
on the Sources module. 3-5d.
M14_SECURITY_PLAN.md §10: addendum documenting the split, updated
sequencing diagram, and how SPEC.md rows should be split into
'M14 (backend)' and 'M14 (ui)'.
M13b_PLAN.md W2: Sources CRUD scope grows to include the cert
lifecycle UI (CSR upload, auto-generate, revoke, expiration
banner). Estimate 2-3d → 4-6d. New exit criteria for the cert
tab. M13c unchanged.
M14-backend exit criteria unchanged. M14-ui smoke folded into
M13b smoke.
Co-Authored-By: Jarvis <jarvis@techno-world.net>
4c13c3fdb4 M13 (frontend admin) + M14 (security hardening) — planning
M13 — multi-tenant admin UI for broad-announce. Replaces dlq.html
and adds CRUD + live-tail + audit + auth surfaces for super-admin
and tenant-admin personas. Ships in 3 sub-milestones:
M13a: authd (JWT IdP) + web/ skeleton + JWT gate 5-6d
M13b: Companies + Sources + Telegram CRUD 7-8d
M13c: Live tail + DLQ + Audit + K8s + Playwright E2E 7-9d
Stack: Vite + React 19 + shadcn/ui + TanStack Query + RHF +
Zod + SSE + openapi-fetch. Embedded in admind via embed.FS.
Same-origin, no CORS, no separate frontend server.
M14 — security hardening. Closes the M11.5 wishlist (mTLS +
secrets management + network policies) with cert-manager + CA
hierarchy + opt-in per-source mTLS + internal gRPC mTLS + cert
lifecycle UI + rotation + PromQL alerts + runbook. 6 workstreams,
16-24d solo / 10-15d parallel with M13c.
Survey decisions: hybrid super+tenant admin, in-house JWT (SSO
post-v1), Vite SPA (literal SPEC), magic-link invites with psql
fallback, no Next.js, no Redux, no Sentry, no i18n lib.
Open questions flagged in M13_FRONTEND_SPEC.md §9 (users table
location, JWT verification path, refresh token storage, audit
log writer, authd port) — defaults documented, ready for review
before M13a W1 starts.
Co-Authored-By: Jarvis <jarvis@techno-world.net>
cbcb33b305 M11 + F2: SHIPPED with full self-defense
F1 (NATS resource limit fix) + F2 (publish-path verification)
together close the M11 NATS investigation. The system is now
defended on three layers:
- F1 cap: stream-level MaxAge/MaxBytes prevent storage from
exceeding the server cap
- F2 smoke: the next time the publish path diverges from
receive (the M11 10-min false-positive class of bug), the
smoke fails immediately
- F2 alerts: NatsJetStreamStorageHigh/Critical and
IngestdReceivePublishMismatch / IngestdNatsPublishErrorsHigh
page on-call before the system goes red
M11 dev-playground gate: 20/20 soak samples green at 7048-7610/s,
p99=25ms, DLQ=0, rate and publish_ok within 1/s on every sample.
Next: M12 (multi-broker NATS, 50k/s ceiling, K8s).
dc71b38625 fix(m11_smoke): include publish_ok column in summary table
The F2 publish-rate assertion (assert_nats_publish_rate_near) was
already wired into the per-minute soak log, but the final summary
table at the end of the smoke was missing the publish_ok column.
This adds it so the saved log file shows whether the NATS publish
path tracked the receive path throughout the run.
Without this, an operator reading a saved smoke log would see the
'rate' column green and assume the system is healthy, but would
have to do PromQL gymnastics to verify the publish path was
actually OK. Now it's right there in the table.
1 lună în urmă