feat(FN-009): implement config and secrets management with runtime injection
- Add RuntimeInjectionService for scope-based config/secret resolution - Mount configs as JSON files at /app/config/ with 0400 permissions - Inject secrets as environment variables with uppercase keys - Implement scope hierarchy: instance > project > user > global - Create ConfigListPage and SecretListPage frontend components - Mask secret values in API responses (never expose decrypted) - Validate secrets exist before spawning containers - Add comprehensive tests for runtime injection service - Update documentation with config/secrets workflow
This commit is contained in:
@@ -1171,3 +1171,44 @@ Any implementation task must:
|
||||
7. **High availability:** No replicas or load balancing in MVP.
|
||||
8. **Backup strategy:** Out of MVP scope; rely on host-level volume backups.
|
||||
9. **Rate limiting:** Not in MVP; add at Traefik or API gateway layer later.
|
||||
|
||||
## 19. Config & Secrets System
|
||||
|
||||
### 19.1 Design
|
||||
|
||||
The config and secrets system provides scoped, runtime-injected configuration for tool containers.
|
||||
|
||||
**Config:**
|
||||
- Plaintext JSON values
|
||||
- Mounted as read-only files at `/app/config/<key>.json`
|
||||
- Scope hierarchy: global → user → project → instance (closest wins)
|
||||
|
||||
**Secrets:**
|
||||
- Encrypted with Fernet at rest
|
||||
- Injected as environment variables with uppercase keys
|
||||
- Never exposed decrypted to the frontend (masked as `••••••`)
|
||||
- Scope hierarchy: global → user → project → instance (closest wins)
|
||||
|
||||
### 19.2 Runtime Injection
|
||||
|
||||
When a tool instance is spawned:
|
||||
|
||||
1. **Config Resolution:** Collect configs from all applicable scopes, with closer scopes overriding broader ones
|
||||
2. **Secret Resolution:** Decrypt secrets from all applicable scopes, with closer scopes overriding broader ones
|
||||
3. **Config File Generation:** Write JSON files to `/tmp/headquarter-configs/{instance_id}/`
|
||||
4. **Volume Mounting:** Mount config files as read-only volumes with `0400` permissions
|
||||
5. **Env Var Injection:** Add decrypted secrets to the container's environment variables
|
||||
6. **Validation:** Fail spawn if required secrets are missing, with clear error messages
|
||||
|
||||
### 19.3 Frontend
|
||||
|
||||
- `/projects/{id}/configs` — Config management with JSON formatting
|
||||
- `/projects/{id}/secrets` — Secret management with masked values
|
||||
- Both support create, read, update, delete operations with scope selection
|
||||
|
||||
### 19.4 Security
|
||||
|
||||
- Config files have restrictive permissions (0400)
|
||||
- Secret values are never sent to the frontend
|
||||
- Decryption only happens during runtime injection in the backend
|
||||
- Missing required secrets prevent container spawn
|
||||
|
||||
@@ -259,3 +259,67 @@ docker network create tools # One-time setup
|
||||
```
|
||||
|
||||
Spawned containers use the `tools` network for Traefik routing.
|
||||
|
||||
## Config & Secrets
|
||||
|
||||
### Overview
|
||||
|
||||
The platform supports scoped configuration values and encrypted secrets that are injected into tool containers at spawn time.
|
||||
|
||||
### Scopes
|
||||
|
||||
Configs and secrets support four scope levels (closest match wins):
|
||||
|
||||
1. **Global** — Available to all users and projects
|
||||
2. **User** — Available to a specific user across all projects
|
||||
3. **Project** — Available within a specific project
|
||||
4. **Instance** — Available to a specific tool instance
|
||||
|
||||
### Configs
|
||||
|
||||
Configs are plaintext JSON values mounted as files into containers:
|
||||
|
||||
- Mount path: `/app/config/<key>.json`
|
||||
- Permissions: `0400` (read-only, owner-only)
|
||||
- Scope resolution: instance > project > user > global
|
||||
|
||||
**API Endpoints:**
|
||||
- `POST /configs` — Create config
|
||||
- `GET /configs` — List configs (filter by scope_type, scope_id)
|
||||
- `PUT /configs/{id}` — Update config value
|
||||
- `DELETE /configs/{id}` — Delete config
|
||||
|
||||
**Frontend:**
|
||||
- `/projects/{id}/configs` — Config management UI
|
||||
|
||||
### Secrets
|
||||
|
||||
Secrets are encrypted with Fernet and injected as environment variables:
|
||||
|
||||
- Env var format: `<UPPERCASE_KEY>=<decrypted_value>`
|
||||
- Values are never sent to the frontend decrypted (displayed as `••••••`)
|
||||
- Scope resolution: instance > project > user > global
|
||||
|
||||
**API Endpoints:**
|
||||
- `POST /secrets` — Create secret
|
||||
- `GET /secrets` — List secrets (filter by scope_type, scope_id)
|
||||
- `PUT /secrets/{id}` — Update secret value
|
||||
- `DELETE /secrets/{id}` — Delete secret
|
||||
|
||||
**Frontend:**
|
||||
- `/projects/{id}/secrets` — Secret management UI
|
||||
|
||||
### Runtime Injection
|
||||
|
||||
When a tool instance is spawned:
|
||||
|
||||
1. Configs are resolved from all applicable scopes
|
||||
2. Secrets are resolved and decrypted
|
||||
3. Config files are generated in `/tmp/headquarter-configs/{instance_id}/`
|
||||
4. Config files are mounted as read-only volumes
|
||||
5. Secrets are injected as environment variables
|
||||
6. Missing required secrets will fail the spawn with a clear error
|
||||
|
||||
### Validation
|
||||
|
||||
Before spawning, the system validates that all required secrets exist. If any are missing, the spawn fails with an error message listing the missing secrets.
|
||||
|
||||
Reference in New Issue
Block a user