feat(FN-4913): complete Step 8 — update docs and changeset
Fusion-Task-Id: FN-4913 Fusion-Task-Lineage: 2fa1fe49-a2a9-405d-833b-cb34d41ef19a
This commit is contained in:
committed by
gsxdsm
parent
cca96a7604
commit
e9ef40f6a7
5
.changeset/FN-4913-secrets-sync-endpoints.md
Normal file
5
.changeset/FN-4913-secrets-sync-endpoints.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@runfusion/fusion": minor
|
||||
---
|
||||
|
||||
Add cross-node secrets sync endpoints (`POST /api/nodes/:id/secrets/push`, `POST /api/nodes/:id/secrets/pull`, `POST /api/secrets/sync-receive`, `GET /api/secrets/sync-export`) with shared-passphrase envelope (scrypt → AES-256-GCM) and Bearer-apiKey auth on inbound routes. Passphrase is stored locally encrypted under the master key (reserved `__sync_passphrase__` row, `access_policy="deny"`) and is never transmitted or echoed.
|
||||
@@ -996,17 +996,18 @@ The client treats mapping persistence as part of onboarding success. If mapping
|
||||
| POST | `/api/nodes/:id/settings/pull` | Pull settings from a remote node. |
|
||||
| GET | `/api/nodes/:id/settings/sync-status` | Get sync status and diff summary (includes `actionableDenialReason` when remote probe fails). |
|
||||
| POST | `/api/nodes/:id/auth/sync` | Sync model auth snapshots (push/pull, checksum/version validated). |
|
||||
| POST | `/api/nodes/:id/secrets/push` | Push local secrets snapshot to a remote node *(planned; follow-up FN-4867)*. |
|
||||
| POST | `/api/nodes/:id/secrets/pull` | Pull secrets snapshot from a remote node *(planned; follow-up FN-4867)*. |
|
||||
| POST | `/api/nodes/:id/secrets/push` | Push local secrets snapshot to a remote node. |
|
||||
| POST | `/api/nodes/:id/secrets/pull` | Pull secrets snapshot from a remote node. |
|
||||
| POST | `/api/settings/sync-receive` | Receive pushed settings (inbound). |
|
||||
| POST | `/api/settings/auth-receive` | Receive `AuthMaterialSnapshot` and persist via auth storage. |
|
||||
| POST | `/api/secrets/sync-receive` | Receive pushed secrets payload (inbound, planned; follow-up FN-4867). |
|
||||
| POST | `/api/secrets/sync-receive` | Receive pushed secrets payload (inbound). |
|
||||
| GET | `/api/secrets/sync-export` | Export local secrets sync envelope for remote pull flows. |
|
||||
| GET | `/api/settings/auth-export` | Export local `AuthMaterialSnapshot`. |
|
||||
| GET | `/api/update-check` | Read cached/TTL-guarded npm update status for `@runfusion/fusion` (respects `updateCheckEnabled`). |
|
||||
| POST | `/api/update-check/refresh` | Clear cached update data and force a fresh npm update check. |
|
||||
| GET | `/api/updates/check` | Perform an on-demand npm registry check for the latest `@runfusion/fusion` version (no cache). |
|
||||
|
||||
When adding a new node settings/auth sync endpoint, add it to the `ENDPOINTS` catalog in `packages/dashboard/src/__tests__/routes-nodes-sync-contract.test.ts` so the auth/error/payload parity matrix covers it. Inbound sync endpoints (including planned `/api/secrets/sync-receive`) must validate `Authorization: Bearer <apiKey>` against the local node API key.
|
||||
When adding a new node settings/auth sync endpoint, add it to the `ENDPOINTS` catalog in `packages/dashboard/src/__tests__/routes-nodes-sync-contract.test.ts` so the auth/error/payload parity matrix covers it. Inbound sync endpoints (including `/api/secrets/sync-receive` and `/api/secrets/sync-export`) must validate `Authorization: Bearer <apiKey>` against the local node API key.
|
||||
|
||||
### Agent stats endpoint
|
||||
|
||||
|
||||
@@ -103,13 +103,29 @@ The schema already carries env-materialization metadata (`env_exportable`, `env_
|
||||
|
||||
## Cross-node Sync
|
||||
|
||||
⚠️ Secrets sync endpoints are not yet present in this branch:
|
||||
Fusion now exposes four secrets sync endpoints:
|
||||
|
||||
- `POST /api/nodes/:id/secrets/push`
|
||||
- `POST /api/nodes/:id/secrets/pull`
|
||||
- `POST /api/secrets/sync-receive`
|
||||
- `POST /api/nodes/:id/secrets/push` — wraps local secrets into a passphrase-protected envelope and sends it to a remote node.
|
||||
- `POST /api/nodes/:id/secrets/pull` — fetches a remote envelope from `GET /api/secrets/sync-export` and applies it locally.
|
||||
- `POST /api/secrets/sync-receive` — inbound apply endpoint (Bearer `apiKey` required).
|
||||
- `GET /api/secrets/sync-export` — inbound export endpoint (Bearer `apiKey` required).
|
||||
|
||||
Passphrase-based sync wrapping/KDF behavior is also pending; see follow-up **FN-4867**.
|
||||
Envelope format is `WrappedSecretsBundle` from `packages/core/src/secrets-sync.ts`: `{ version, ciphertext, salt, nonce, kdf, kdfParams }` plus transport metadata (`sourceNodeId`, `exportedAt`). Wrapping uses scrypt (`N=32768, r=8, p=1, keyLen=32`) and AES-256-GCM with fresh 12-byte nonce + 16-byte salt per export. `TODO(FN-4867)` remains for planned Argon2id migration.
|
||||
|
||||
Sync passphrase storage is local-only: reserved key `__sync_passphrase__` in `secrets_global` with `access_policy="deny"` and `env_exportable=false`, encrypted under the local master key. The passphrase is never transmitted and never returned by HTTP endpoints.
|
||||
|
||||
Error mapping:
|
||||
|
||||
- `SecretsSyncError` codes (`wrong-passphrase`, `version-mismatch`, `malformed`) return HTTP `400` with `{ "error": <code> }`.
|
||||
- Missing passphrase returns HTTP `400` with `{ "error": "passphrase-not-configured" }`.
|
||||
- Bearer auth failures return HTTP `401`.
|
||||
|
||||
Audit events emitted on apply/send paths:
|
||||
|
||||
- `secret:sync-push`
|
||||
- `secret:sync-pull`
|
||||
|
||||
Audit payloads exclude plaintext values, passphrases, and envelope crypto material (`ciphertext`, `salt`, `nonce`).
|
||||
|
||||
## Audit Events
|
||||
|
||||
|
||||
Reference in New Issue
Block a user