molecule-core/docs/development/constraints-and-rules.md
rabbitblood 262a52a32c docs(security): document the KMS-rooted custody chain for SECRETS_ENCRYPTION_KEY
External architecture review flagged the SECRETS_ENCRYPTION_KEY env var
on the platform as encryption-at-rest theater. The reviewer read only
the platform repo and missed that the master key actually lives in AWS
KMS at the control plane layer, with envelope encryption wrapping each
tenant secret blob.

Adds docs/architecture/secrets-key-custody.md as the canonical source
of truth for the full chain:

- Two-mode envelope (KMS_KEY_ARN vs static-key fallback)
- Per-blob AES-256-GCM with KMS-wrapped DEKs
- Where each key actually lives (KMS, CP env, tenant env)
- Threat model per attacker capability
- Rotation story (annual KMS CMK rotation, manual DEK rotation on incident)
- Audit posture (SOC2 / ISO 27001 questionnaire bullets)

Patches three downstream docs that previously stopped at the env-var
level and link them to the new custody doc:

- development/constraints-and-rules.md (Rule 11)
- architecture/database-schema.md (workspace_secrets paragraph)
- architecture/molecule-technical-doc.md (env-vars table)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 11:29:16 -07:00

4.0 KiB

Constraints & Rules

Key design rules and invariants that must be followed throughout the codebase.

1. The Platform Never Routes Agent Messages

A2A messages go workspace-to-workspace directly. The platform only handles:

  • Discovery — resolving workspace URLs
  • Registry — knowing what workspaces exist

2. Postgres Is Source of Truth, Redis Is Ephemeral

If Redis is wiped, workspaces re-register on next heartbeat and state is restored. Nothing critical lives only in Redis.

3. structure_events Is Append-Only

Never UPDATE or DELETE rows in this table. The workspaces table is the mutable projection. See Event Log.

4. workspace-template Is Generic

It contains no business logic. All business logic lives in workspace-configs-templates/. The template reads config files at startup — it does not know what kind of workspace it is until it loads config.

5. Bundles Do Not Contain Secrets

API keys, passwords, and credentials are never serialized into bundle JSON. The provisioner injects them from the host environment when spinning up a workspace container.

6. No Auth for MVP

The platform API has no authentication. All endpoints are open. This is intentional — the project follows the n8n Community Edition model. Auth is added in a separate SaaS wrapper (molecule-cloud).

7. org_id Is Omitted from MVP Schema

Removed entirely for MVP simplicity. Added in the SaaS migration for multi-tenancy.

8. Tier Determines Provisioner, Not Behavior

The workspace code is the same regardless of tier. The tier only affects how the workspace is deployed:

  • Docker flags
  • host access level and isolation boundary
  • Resource allocation

See Workspace Tiers.

9. The Hierarchy IS the Topology

There is no manual connection wiring. Communication is derived from the parent_id hierarchy:

  • Siblings can talk to each other
  • Parents can talk to children (and vice versa)
  • No skipping levels

The org chart IS the access control policy. See Communication Rules.

10. Discovery-Time Auth for MVP

Direct A2A calls between workspaces are unauthenticated in MVP. Access control is enforced at discovery time via CanCommunicate(). Post-MVP adds platform-issued signed tokens scoped to caller/target pairs. See A2A Protocol — Authentication.

11. Secrets in Postgres, Encrypted

Workspace secrets (API keys, credentials) are stored in Postgres with AES-256-GCM encryption at the application layer. The tenant's SECRETS_ENCRYPTION_KEY is provisioned at boot by the control plane, which holds the master key material in AWS KMS (envelope encryption, dual-mode with a static-key fallback for dev). Full custody chain in secrets-key-custody.md. Secrets are never included in bundles, never logged, never exposed via API responses.

12. Last-Write-Wins for MVP

Concurrent canvas modifications from multiple clients use last-write-wins. No optimistic locking or CRDTs for MVP.

13. Security Headers on All Responses

The platform applies HTTP security headers via middleware (workspace-server/internal/middleware/securityheaders.go):

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • X-XSS-Protection: 1; mode=block

These are applied after CORS middleware on every response.

14. No Exposed Database Ports

Postgres and Redis must not expose host ports. They communicate exclusively over the internal Docker network (molecule-monorepo-net). Use docker compose exec for direct access during development.