feat(v1.1.7-secrets): secrets SDK + table + admin API + dashboard
Encrypted per-app secrets, reachable from scripts as
secrets::{get,set,delete,list}(name) and managed from the dashboard
Secrets tab. Values are AES-256-GCM-sealed with the process master key
(picloud_shared::crypto) before they touch Postgres; the repo only ever
sees ciphertext + nonce. JSON round-trip preserves Rhai types.
- migration 0023_secrets.sql (PRIMARY KEY (app_id, name)).
- SecretsService trait (picloud-shared) + SecretsServiceImpl + repo
(manager-core), wired into the Services bundle and Rhai engine.
- Capability::AppSecretsRead/Write (→ script:read / script:write); no
new Scope variants (seven-scope commitment).
- Admin API GET/POST/DELETE /apps/{id}/secrets (list returns names +
updated_at, never values).
- build_app now takes a MasterKey, sourced from PICLOUD_SECRET_KEY in
main.rs; test callers pass a fixed test key.
- 64 KB value cap (PICLOUD_SECRET_MAX_VALUE_BYTES); no ServiceEvent
emission (secret writes don't fire triggers, by design).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
crates/manager-core/migrations/0023_secrets.sql
Normal file
24
crates/manager-core/migrations/0023_secrets.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- v1.1.7: encrypted per-app secrets.
|
||||
--
|
||||
-- Operational config (API keys, OAuth tokens, webhook signing keys)
|
||||
-- encrypted at rest with the process master key (AES-256-GCM). Both the
|
||||
-- ciphertext (16-byte GCM auth tag appended) and the 12-byte nonce are
|
||||
-- stored; the master key itself never lives in the database. See
|
||||
-- `picloud_shared::crypto` + `manager-core::secrets_service`.
|
||||
--
|
||||
-- This is the user-facing `secrets::*` store. It is intentionally
|
||||
-- separate from `app_secrets` (the one-row-per-app realtime signing
|
||||
-- key, 0022): different cardinality (many named rows per app), and the
|
||||
-- realtime key is encrypted in place by migration 0025.
|
||||
|
||||
CREATE TABLE secrets (
|
||||
app_id UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
encrypted_value BYTEA NOT NULL, -- ciphertext incl. 16-byte GCM auth tag
|
||||
nonce BYTEA NOT NULL, -- 12 bytes
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (app_id, name)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_secrets_app ON secrets (app_id);
|
||||
Reference in New Issue
Block a user