Files
stargue-publishing-engine/docs/deferred-gates.md
Angelo B. J. Luidens e529651de1 Stage 1 complete: shared packages with full test coverage
- packages/schema: 15 Vitest tests (6 valid + 6 invalid frontmatter + 3 round-trip)
- packages/sanitize: fail-closed remark plugin + 12 private fixtures + 6 clean fixtures, 20 tests
- packages/observability: Pino + correlation IDs + redaction; 5 tests with 100-log validation
- packages/linkedin-client: Posts API client + token store; 10 tests; AES-256-GCM substituted for libsodium crypto_secretbox (Bun ESM bug, see docs/deferred-gates.md D-001)

50/50 tests pass across 4 packages. All Stage 1 DoDs verified.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-26 12:50:03 -04:00

51 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Deferred gates
Items that could not be completed in the Stage 0 execution window and must be resolved before the gate they block.
## Gate 0.8 — Postgres + Redis on PaaS
**Status:** Deferred 2026-04-19.
**Reason:** Dokploy MCP tools (`mcp__dokploy__*`) were not loaded in the Stage 0 session, and `DOKPLOY_API_KEY` was not in the WSL environment. Direct API query not possible in-session.
**Blocks:** Stage 2 (database + API) — the scheduler and admin cannot run without a Postgres + Redis pair.
**Resolution options:**
1. **Recommended:** Restart Claude Code with the vault's `.mcp.json` Dokploy MCP attached; run `mcp__dokploy__list_applications` / equivalent against `sg-paas-s1.stargue.net` to verify or provision.
2. Angelo confirms via Dokploy web UI and reports service names + connection hostnames.
3. Provision fresh Postgres + Redis services in the `stargue-publishing-engine` Dokploy stack (clean room; isolates blast radius from other PaaS apps).
**Acceptance when resolved:** this file updated with service names, hostnames, and connection-string env-var locations (Dokploy secrets).
## Gate 0.9 — LinkedIn Developer Portal apps
**Status:** Pending Angelo's manual action.
**Reason:** Dev Portal registration cannot be automated — requires human auth at `linkedin.com/developers/`.
**Blocks:** Stage 3.1 (OAuth flow) live integration — structure + contract tests can proceed in parallel.
**Resolution:** follow the checklist in [`linkedin-apps.md`](./linkedin-apps.md). Expected time ~30 min for OIDC + Share; multi-week for Community Management API + MDP partner approvals.
**Acceptance when resolved:** `linkedin-apps.md` registry filled in with app IDs; client credentials stored in Dokploy secrets `LINKEDIN_CLIENT_ID`, `LINKEDIN_CLIENT_SECRET`, `LINKEDIN_TOKEN_ENCRYPTION_KEY`.
## What proceeds in parallel
Stages 12 (local DB), 3 structural (OAuth code + tool shapes + msw fixtures), 4 (scheduler), 5 (admin UI with Authentik stub), 6 (sanitize integration in stargue-com/.net), 7.1 (`/market audit` baseline), 7.2 (7 Cs post drafting) can all proceed without these gates. Live integration tests and first production publish require both gates resolved.
---
## D-001 — Token store cipher: AES-256-GCM instead of XSalsa20-Poly1305
**Plan §3.2 specified:** libsodium `crypto_secretbox` (XSalsa20-Poly1305), per architect gap 3.
**Implemented (2026-04-26):** Node stdlib `aes-256-gcm` via `node:crypto`. Same AEAD security profile (256-bit key, 96-bit nonce, 128-bit auth tag), zero external dependencies.
**Reason:** `libsodium-wrappers` and `libsodium-wrappers-sumo` (v0.7.16) both have a known ESM resolution bug under Bun where the loader fails to find `./libsodium.mjs` / `./libsodium-sumo.mjs` from within their own dist folder. Reproduced cleanly on Bun 1.3.11. AES-256-GCM is the recommended AEAD when libsodium isn't available — same security guarantees, FIPS-compliant, in stdlib of every JavaScript runtime (Node, Bun, Deno, Cloudflare Workers).
**Security review:**
- AEAD: ✅ (authenticity + confidentiality)
- Key length: 256 bits (same as XSalsa20-Poly1305)
- Nonce length: 96 bits (sufficient for random nonces; collision probability < 2^-32 after 2^32 messages well within Phase 1 envelope of <100k tokens lifetime)
- Tag length: 128 bits (same as XSalsa20-Poly1305)
- Implementation: Node stdlib (audited, FIPS 140-2 validated under common builds)
**Remediation path:** When `libsodium-wrappers` ships a Bun-compatible ESM build, migrate by: (1) restore dep, (2) re-implement encrypt/decrypt with `crypto_secretbox_easy`, (3) one-time decrypt-and-re-encrypt migration on `linkedin_tokens.*_ct` rows, (4) drop AES-GCM code path.
**Risk:** Low. Both ciphers offer equivalent security for this use case (encrypting OAuth tokens at rest in Postgres). The deviation is purely about the cipher primitive, not the threat model or key management.
**Status:** Accepted. 4/4 token-store round-trip tests pass. Production-ready.