Files
headquarter/openspec/changes/config-secrets/design.md
T
alex 78aaddb2b5
CI / Web CI (push) Failing after 12s
CI / API CI (push) Failing after 1m1s
docs(openspec): add OpenSpec changes for FN-005, FN-006, FN-008, FN-009, FN-010
- Add frontend-foundation change (FN-005) with 46 tasks
- Add deployment-config change (FN-006) with 27 tasks
- Add runfusion-poc/opencode-poc change (FN-008) with 25 tasks
- Add config-secrets change (FN-009) with 31 tasks
- Add codeserver-spawn change (FN-010) with 38 tasks
- Include project specsheet and configuration
- Archive completed deployment-config change
2026-05-14 17:35:20 +02:00

2.5 KiB

Context

The backend has Config and Secret models (FN-004) with scope fields, but no frontend UI or runtime injection. SSH keys already use Fernet encryption (FN-011), so the encryption pattern is established. This design completes the config/secrets lifecycle.

Current state:

  • Config model: key, value, scope (global/user/project/instance), scope_id
  • Secret model: key, encrypted_value, scope, scope_id
  • Fernet encryption utilities exist in app/encryption.py
  • No UI for management
  • No runtime injection into containers

Goals / Non-Goals

Goals:

  • Allow users to manage configs and secrets via UI
  • Inject configs/secrets into tool containers at spawn time
  • Support scope-based inheritance (instance overrides project overrides user overrides global)
  • Maintain encryption for all secret values

Non-Goals:

  • Secret versioning or history
  • Automatic secret rotation
  • Integration with external secret managers (Vault, AWS Secrets Manager)
  • Config/secrets for non-tool resources

Decisions

1. Mount configs as files, secrets as env vars

  • Rationale: Configs (JSON) are often files (e.g., settings.json). Secrets are typically env vars.
  • Config mount: /app/config/<key>.json
  • Secret env: <KEY>=<decrypted_value>

2. Scope resolution: closest match wins

  • Rationale: Instance-specific values should override project defaults
  • Resolution order: instance → project → user → global

3. Secret values never sent to frontend decrypted

  • Rationale: Security. Frontend only sees masked values (e.g., ••••••).
  • Decryption happens only in backend during runtime injection

4. Config values are plaintext (not encrypted)

  • Rationale: Configs are not sensitive. Encrypting them adds complexity without security benefit.

Risks / Trade-offs

[Risk] Secret injection at spawn time could fail silently → Mitigation: Validate all referenced secrets exist before spawning. Return error if missing.

[Risk] Config files in containers could be read by other processes → Mitigation: Mount config files with restrictive permissions (0400). Run containers as non-root.

[Risk] Large configs could exceed container env var limits → Mitigation: Document size limits. Consider config file mounting for large values.

Migration Plan

No migration needed. This extends existing models.

Open Questions

  1. Should configs support JSON schema validation?
  2. Do we need bulk import/export for configs/secrets?
  3. Should secret keys be validated against a naming convention?