## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Its feature map describes user journeys. Its access map describes the matching agent paths. > - The recent index and capability additions improved discovery and breadth. > - Broad baseline records still combined operations with different actors, permissions, and retry behavior. > - This pull request reviews the existing task, approval, secret, and recovery capabilities at operation level. > - Each operation now has its own access boundary, source evidence, and verification recipe. Source review remains separate from live proof. ## Linked Issues or Issue Description Refs: #16987, #16990, #16025. These related pull requests are merged. The search found no open duplicate or matching issue. **Issue type** Missing documentation. **Where is the issue?** The paired task, questions-and-approvals, secrets, and recovery files under `maps/feature-map/` and `maps/agent-access-map/`. **What's wrong?** Baseline records do not show enough detail to verify who can perform each action, which state must persist, or what happens after a denial, race, or retry. A declared scenario tool can also be mistaken for an admitted production tool. **Suggested fix** Split the four areas into source-reviewed operation records. Add compact checkpoints to their user recipes. Preserve existing capability IDs and the map schema. ## What Changed - Promote 27 existing capability records to `operation-reviewed`, with 125 operation records: tasks 32, questions and approvals 39, secrets 28, recovery 26. - Give each operation its own API, agent surface, policy, source evidence, verification recipe, and remaining gap. - Separate human, legacy agent, run JWT, native binding, mode, and resource authority. Split operations where those rules differ. - Correct production completion paths, plan acceptance and handoff, question dismissal and withdrawal, secret proposal authority, runtime recovery grants, and explicit duplicate-risk decisions. - Preserve access gaps found in source, including the binding-proposal dependency cascade and narrower native/CLI fields. - Add one checkpoint table per product recipe for saved results, denial, races, and retries. - Keep all 191 existing capability IDs. Change only eight Markdown files. Keep every operation's evidence `source-only` and verification `not-run`; the subset below does not prove an entire operation across its actors and surfaces. ## Verification Source review uses revision `3bbc2104b65caf9f7763938a01260a5673e12f7a`. Read-only area reviews and a second source review covered the changed pairs. Passed: - `node scripts/check-maps.mjs`: 35 paired areas, 191 capability IDs, valid references and fields. This is structural verification. - `node --test scripts/check-maps.test.mjs scripts/storybook-feature-index.test.mjs`: 17 passed. - `node scripts/storybook-catalog.mjs`: 308 files, 2,899 stories. Generated outputs remain ignored. - Capability comparison with the base: all 191 IDs unchanged; the four reviewed areas contain 27 capabilities and 125 source-only operation records. - `pnpm -r typecheck` and `pnpm build`. - `git diff --check`. - Focused existing interaction and proposal route tests: 80 passed. The two selected DB-backed suites skipped 119 tests because local embedded PostgreSQL could not start. These skipped tests are not passes. Live subset on a fresh local instance with a disposable PostgreSQL container: - Created the company and an unassigned task through the browser. Added a comment and completed the task. The saved status and comment survived reload. - Created a managed secret with inert dummy data through the browser. Its metadata and version survived reload. The metadata response did not contain the dummy value. - Created a question fixture through board REST. Invalid input returned 422 and left it pending. Browser dismissal kept it pending and preserved the draft. Reopening restored the choice. Submission survived reload. A duplicate response returned 409 and left the saved answer unchanged. - Used a real issued legacy agent API key. Task read and safe company-secret catalog returned 200. Full secret listing and run-only secret list/value routes returned 403. Revoked the key after the checks. - Read an empty recovery projection. Resolving a nonexistent action returned 404 and left the task unchanged. This did not execute recovery. - Closed the owned browser tab and stopped only the verified test runtime and labelled database container. Evidence survived cleanup. No provider or model ran. Limits and retained failures: - Native embedded PostgreSQL launch failed because the host could not allocate semaphores. The container-backed app was the successful alternate environment. - Full `pnpm test:run` was attempted. Fifteen DB-dependent native-session cases failed at database startup, and several DB suites skipped. The run was stopped after repeated failures of that prerequisite. The full local suite did not pass. - The sandboxed build attempt failed at the local tsx IPC socket. The required build passed outside the sandbox. - The first CI build job passed compilation and production boot, then its npm-install check was interrupted when the runner received a shutdown signal. The corrected head passed the full CI run, including the build and public-install checks. - Initial Greptile review found the recovery note field and native search/history limits were inaccurate. Corrected `resolutionNote` and the production cap of 100, then reran the map checks. Greptile reviewed the corrected head at 5/5; both earlier threads are resolved. - An initial harness used a nonexistent generic secret-value URL and received 404. The actual mapped agent routes were then checked separately. An initial recovery assertion expected 409; the actual missing-action contract returned 404. These were harness corrections, not product fixes. - Native run bindings, two-person ownership, secret delivery/rotation, external vaults, provider-stop proof, workspace repair, and actual recovery execution remain unexecuted. The map does not claim those journeys passed. The separate external **Paperclip Review** check is still in progress on `904509df80cc6de16d36906a410a66786f619b20`. The reviewer reports that its full changed-file request is pending. CI is green and Greptile is 5/5, but this external review has not published a final assessment. Its review service must finish that request and assessment. ## Risks Documentation can become stale as policy and runtime bindings change. Each operation cites source and retains its verification gaps. The records describe observed enforcement; they do not authorize broader access or certify live behavior. This pull request changes no product code, schema, or permission enforcement. ## Model Used OpenAI Codex, `gpt-6.1-sol`; 475,000-token context window; xhigh reasoning; tool use and code execution. Read-only source agents assisted the area reviews. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs: #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (focused map and route checks; full-suite host blocker recorded above) - [x] I have added or updated tests where applicable (existing map regression tests cover this documentation-only change) - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
60 KiB
Secrets, personal credentials, and proposals — agent access
Product map: Secrets, personal credentials, and proposals.
Feature ID: secrets.
Source revision: 3bbc2104b65caf9f7763938a01260a5673e12f7a.
Review depth and executed proof are separate. The operation records enumerate the named behavior and access boundaries. Their evidence states describe the reviewed sources; run results and environment limits belong in the PR or verification artifacts. A listed API or source test does not establish a live authorized journey. Follow the map contract.
- UI:
/company/settings/secrets(ui/src/App.tsx:187), company/personal Secrets, My secrets, Vaults, Proposals tabs in ui/src/pages/Secrets.tsx:657;?secret=<id>/?definition=<id>opens inspectable detail sheets (Secrets.tsx:673). Hidden tabs are presentation only: APIs stay live. Relevant UI sources:ui/src/pages/secrets/{MyUserSecretsTab,SetMyUserSecretDialog,ProposalsTab,ImportFromVaultDialog}.tsx; agent env/API-access editing in ui/src/components/AgentConfigForm.tsx:536 and ui/src/lib/secret-delivery.ts. - All board route operations require board identity and company/resource access, plus ordinary viewer-write protection. Company secret CRUD and vault administration use their own board checks. Definition administration and direct secret-proposal resolution require definition-admin authority; binding-proposal resolution instead checks target agent_config:update authority. The binding dependency cascade has a separate enforcement gap recorded under approve. Source secret routes and each handler. There is no board endpoint that returns arbitrary stored plaintext values.
- Native production agent path is admitted
search_api/call_apiover the exact REST operation, not the declaredread_secret_value/list_secret_metadatascenario names. Production authority does not bind those two dedicated scenario actions (server/src/services/native-runtime/paperclip-runner-tool-authority.ts:124,501,616,641; catalog runner-api-catalog.ts:43-123). Native fallback needs rollout admission, running authorized bound agent/task/run, current assignment/execution and budget/company/privacy authority. GETs are available in Ask/Plan; POST/DELETE secret operations are not, including POST value retrieval even though its business meaning is reading. Skill-test may appear in catalog allowedModes but secret authorization denies its JWT scope. Actual run scope survives restart/task mode edits. See runner-api-client.ts:50-61, runner-api-catalog.ts:117-123, paperclip-runner-tool-authority.ts:1190-1230,2440-2485. - Legacy shell/REST uses actual bearer actor and signed JWT run context, not merely an X-Paperclip-Run-Id.
secretsCLI wraps company/vault operations; it has no personal-secret/proposal/value command family. Direct REST remains necessary for those. CLI installation/working shell must be separately established for a given runtime; do not assume remote/native CLI presence. - Public personal-assistant MCP is a bounded named capability catalog, not arbitrary native call_api: no secret/vault/proposal operation is exposed in
server/src/services/public-mcp/{capabilities,expanded-capabilities}.ts. An assistant can request human action through a task/comment, but no secret-specific administrative delegation was found. secrets:read/secrets:proposeuse the shared access evaluator. Standard same-company agent visibility is default-allowed, but effective low trust, task_bridge and skill_test scopes deny these actions (authorization.ts:1313,1492,1563,2451). A recorded responsible/authorizing user adds the current user ceiling; responsible-user intersection has an operator shadow-mode setting, so record mode instead of claiming unconditional enforcement (authorization.ts:2650-2795). Run JWT source/claims, header mismatch, responsible identity and canceled-write fencing: middleware/auth.ts:395-480, agent-run-cancellation.ts:6.- Redaction/persistence: run value reads register dynamic secret redaction before returning and fail closed if registration cannot persist. Activity/access manifests contain IDs, versions, paths and outcomes, not values. Native credential value replies stay inline, capped at 10 MiB, with encrypted mutation receipts; they are not plaintext saved API-result assets. Histories omit bodies. Same native call ID replays the stored encrypted result without rereading/side effects. Source runner-api-sensitive-response.ts:1, runner-api-client.ts, paperclip-runner-tool-authority.ts API receipt path, runner-api-log-redaction.ts, run-secret-redaction.ts. A fresh call is necessary to prove current revocation/rotation; replay intentionally returns the original receipt.
- Important precision: proposals require a verified run JWT and a matching existing run, but the direct proposal service does not independently require run.status=running (secret-proposals.ts:42-53). Native fallback does require a running authorized binding; value-list/read service explicitly requires running. Do not turn the broader prose “active run” into a claim that every legacy proposal handler has a live-status check. Cancellation still fences non-GET REST writes in auth middleware.
company-secrets
Capability ID: secrets/company-secrets.
Review: operation-reviewed.
Discover safe company metadata; administer, rotate, inspect, delete and bind company secret references. Direct administration stays board-restricted; catalog and governed proposals are separate agent paths.
catalog
API: present — GET /api/companies/{companyId}/secrets/catalog.
Agent access: available through permitted same-company legacy REST or admitted native GET call_api. No dedicated secrets CLI catalog command.
Policy: board_or_agent, company access and secrets:read. Returns only {id,name,key,status} for nondeleted company-scope secrets; user/instance scopes and values/material are excluded. Board full metadata listing below is a different route.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:585; services/secrets.ts:3793.
Verification: not-run — compare exact projected fields; deny unauthenticated/other-company/low-trust/task-bridge/skill-test contexts and responsible-user ceiling; create user/instance controls and confirm absent. Test source tests/secrets-routes.test.ts:1066-1135, agent-secrets-routes.test.ts:270.
Gaps: no live/native catalog evidence from this wave; do not label whole company secret management agent-available.
list-metadata-and-audit
API: present — GET /api/companies/{companyId}/secrets; GET /api/secrets/{id}/usage; GET /api/secrets/{id}/access-events.
Agent access: restricted, board API/CLI secrets list -C, secrets usage <id>, secrets access-events <id>; native agent call_api remains board-denied.
Policy: company-scope only; user/instance IDs are hidden. Cross-company usage/audit returns same 404 shape as missing ID. List returns metadata/reference counts, usage resolves consumer labels, access events are value-free. No generic GET secret-value API.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:594,1076,1091; services/secrets.ts:3793-3851; cli/src/commands/client/secrets.ts:372,506,521.
Verification: not-run — known binding reference/count and success/failure event persist/reload; value absent; other-company/user/instance ID and agent denied. Tests secrets-routes.test.ts:904-1010, secrets-service.test.ts:1489,1530.
Gaps: board-only inspection has no agent-specific delegation beyond requesting human action.
create-managed-or-link-reference
API: present — POST /api/companies/{companyId}/secrets.
Agent access: restricted; board API/CLI secrets create -C ... --name ... --value-env <env-name> or secrets link -C ... --name ... --provider ... --external-ref .... Agent alternative is proposed secret creation, not direct write.
Policy: same company, same-provider selectable vault, valid unique path/name/key. Managed values require value and prohibit externalRef; external_reference requires supported provider/ref and stores provider reference metadata without fetching plaintext. Defaults use configured provider; GCP/Vault placeholders are not operational providers. New remote writes reserve/persist provider material with cleanup on DB failure; do not describe failed remote create as necessarily having no external effect.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:887; services/secrets.ts:2176-2395; cli/.../secrets.ts:415,443.
Verification: not-run — create managed dummy and link known test reference; reload metadata and bind/use separately. Assert duplicate/cross-company provider/mode/coming-soon failures, sanitized errors, ciphertext rather than plaintext at rest. Inspect provider cleanup and retained cleanup handle after failure. Tests secrets-service.test.ts:2627,2923,2943,3007-3135; secrets-routes.test.ts:158,171; aws-secrets-manager-provider.test.ts:33,340. Retry: create has no application idempotency key; repeated REST creation should conflict by name/key, not promise replay. Inspect state after uncertain outcomes; native same-call receipts provide their own replay.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
edit-lifecycle
API: present — PATCH /api/secrets/{id}.
Agent access: restricted; board UI/CLI secrets update <id> --payload-json ....
Policy: company-scope, nondeleted existing secret. Edit name/key/description and active/disabled/archived states; name/key uniqueness preserved. Generic PATCH cannot retarget externalRef/change external vault or reassign managed vault; managed deletion must use DELETE. External refs can be soft-deleted through PATCH (names/keys renamed), while full cleanup uses DELETE. Disabled/archived values stop resolving on fresh delivery/read. This does not erase values already issued to a process/model.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:1032; services/secrets.ts:2619-2720.
Verification: not-run — rename without breaking stable secret ID binding; disable/archive and show fresh delivery denied; reactivate and retry; reject retarget/vault/managed soft-delete, foreign/user/instance/deleted IDs; verify no value in activity. Tests secrets-service.test.ts:3210,3968-4015,4215; secrets-routes.test.ts:873. Retry: repeated same metadata patch is state-setting; do not repeat a value rotation under this operation.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
rotate-and-reference-version
API: present — POST /api/secrets/{id}/rotate.
Agent access: restricted; board API/CLI secrets rotate <id> --value-env ... (CLI value wrapper is narrower than API ref/vault options).
Policy: active company secret. Managed mode requires new value; rotation creates a new latest version, marks old as previous, and can migrate managed vault through this route. Latest versus explicitly pinned consumer version matters: previous is not automatically revoked. For external_reference, API can rotate reference/version, or write new value through a provider that supports it; value-write cannot also retarget/pin providerVersionRef. External value updates are actual provider writes (AWS AWSCURRENT), not just local metadata.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:992; services/secrets.ts:2397-2615; secrets/aws-secrets-manager-provider.ts:1120+.
Verification: not-run — bind one latest and one explicit version; rotate, reload latestVersion, verify new/latest and prior pinned behavior using harmless equality proof only; reject inactive/foreign/user/instance/provider mismatch. Controlled persistence failure must leave original current state or explicit cleanup evidence; external AWSCURRENT rollback is separate. Tests secrets-service.test.ts:3135,3170,3239,3596-3734; aws-secrets-manager-provider.test.ts:389,486. Retry: repeated fresh rotation increments versions; the public rotation schema has no general idempotency token or compare-and-swap field. Inspect metadata/provider state before retrying an uncertain response. Verify ordinary native agent denial; encrypted native replay applies to permitted value retrieval below.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
delete-and-cleanup
API: present — DELETE /api/secrets/{id}.
Agent access: restricted; board UI/CLI secrets delete <id> --yes --confirm <same-id>.
Policy: company scope only; marks deleted/renames before provider cleanup, then removes DB rows. Retry can continue cleanup from soft-deleted state; after complete deletion returns missing. AWS provider deletes only Paperclip-managed remote material; deleting an external reference does not delete the externally owned AWS secret. Removing a disabled-vault local reference need not contact the unavailable vault. Instance/user values use separate paths.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:1106; services/secrets.ts:3379-3455; secrets/aws-secrets-manager-provider.ts:1313-1360.
Verification: not-run — remove disposable managed+external references; old catalog/binding/fresh read unavailable; external provider resource remains for linked reference; provider failure leaves nonresolvable cleanup state, retry succeeds without restoring authority. Tests secrets-routes.test.ts:1010, secrets-service.test.ts:4032-4171, aws-secrets-manager-provider.test.ts:917.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
bind-unbind-and-migrate
API: present — ordinary target configuration API, concrete agent path PATCH /api/agents/{id} with adapterConfig env secret_ref or top-level access.<ALIAS> ref. Project/routine/environment consumer bindings follow their own configuration APIs and policy; do not invent a universal secret-binding CRUD route. secrets declarations -C ... uses POST /api/companies/{companyId}/exports/preview for portability declarations (not live value grants).
Agent access: partial—direct config edit only where actual agent_config:update/target policy permits; creating/changing another agent credential is not implied by catalog read. Binding proposal is explicit self/report human approval route. CLI secrets migrate-inline-env -C ... dry-run; --apply creates/rotates secrets then PATCHes agents under board authority.
Policy: same-company reference and target, target config grants, env path versus access alias validation, no instance/user secret_id treated as company ref; user_secret_ref declaration separately. API-access top-level aliases are only for agent target. Low-trust allowed binding IDs and class-3 static-lease allowlist must remain enforced. Unbinding is removing config ref plus persisted binding sync; aliases dropped by Secret access editor need replacement config semantics. Migration is a multi-request workflow, not atomic.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/agents.ts:1774,5262-5490; services/secrets.ts:4720-5184; AgentConfigForm.tsx:536; cli/.../secrets.ts:283-365; ui/src/lib/secret-delivery.ts.
Verification: not-run — bind env-only, API-only, both, unbind, reload config+usage and verify fresh delivery changes; alias rename and unrelated binding survive; cross-company/unknown/deleted refs denied before deleting existing bindings. Dry-run migration must not write; apply removes inline values and uses secret refs; failure/retry inspect partial state. Tests agents-service-secret-bindings.test.ts, secrets-service.test.ts:293,489,1450,1607,1647,2555, cli/src/tests/secrets.test.ts.
Gaps: full policy of every non-agent binding target is outside this secrets-only source wave; link existing owning feature maps rather than mark all targets qualified.
user-secrets
Capability ID: secrets/user-secrets.
Review: operation-reviewed.
Separate company-admin definitions and aggregate coverage from each authenticated person’s private value lifecycle; runtime resolves only the captured responsible user’s value.
definitions-list-create-edit-disable-delete
API: present — GET|POST /api/companies/{companyId}/user-secret-definitions; PATCH|DELETE /api/companies/{companyId}/user-secret-definitions/{definitionId}.
Agent access: restricted—company owner/admin (or existing local implicit/instance admin) with company access; no ordinary agent/native/CLI secret command for personal definitions. Direct user API/browser is real path.
Policy: definition != personal value. Definition owns key/name/provider/mode/guidance; company uniqueness/provider/vault checks. Disabling blocks required resolution. Definition deletion (DELETE or PATCH deleted) removes all owners' values/provider material then tombstones/renames definition; a required dangling declaration gives actionable definition/field/consumer error without value. Optional missing declarations resolve to absent.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:68,602-720; services/secrets.ts:3456,3853-3974.
Verification: not-run — admin creates, edits/disable/reactivate, then deletes disposable definition after two users set different dummy values; ensure owners/values gone and required stale ref fails clearly; member/agent/foreign denied, implicit board attribution system-safe. Tests secrets-routes.test.ts:219-306; secrets-service.test.ts:2163-2313; secrets-service-dangling-user-secret.test.ts. Retry: duplicate key ->409, mutation/reload verifies persistence; deletion may have provider partial cleanup so inspect/retry rather than claim transaction across vault writes.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
coverage
API: present — GET /api/companies/{companyId}/user-secret-definitions/{definitionId}/coverage.
Agent access: restricted to same definition-admin authority.
Policy: aggregate configured/inactive/missing counts across active human members; no values or arbitrary owner's credential read. Does not make every member's personal secret visible in company catalog.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:720; services/secrets.ts:3975-4010.
Verification: not-run — two active members, one configured then disabled; counts change after reload; inactive/nonmember values do not count; nonadmin/agent/foreign denied. No dedicated live proof in review.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
owner-values-list-create
API: present — GET|POST /api/companies/{companyId}/me/user-secrets.
Agent access: restricted—concrete authenticated board user only, company access; local implicit board with no userId fails User identity required. No ordinary agent impersonation or ownerId parameter allowed.
Policy: list pairs eligible definitions with current user's metadata or missing value. One value per definition+owner, active definition required, managed/external mode guards; provider config belongs to company. Value stored in user scope with derived unique key; no plaintext readback. User B cannot inspect/edit A by guessing ID; legacy company-secret endpoints hide user-scoped IDs.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:86,727-773; services/secrets.ts:1068-1095,2985-3160,4011-4037.
Verification: not-run — A/B set distinct values, switch sessions and see only own state; duplicate value 409 including race; absent user/company/definition/inactive mode denied; metadata never returns value. Tests secrets-routes.test.ts:306-383; secrets-service.test.ts:1783,2023,2061,2119; owner-scoped tests concern runtime mediation, not proof of this browser session flow.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
owner-values-edit-rotate-disable-delete
API: present — PATCH|DELETE /api/companies/{companyId}/me/user-secrets/{secretId}; POST .../{secretId}/rotate.
Agent access: restricted to owner board user, company scoped; even definition-admin/instance-admin status is not an alternate owner's value API.
Policy: owner/scope/company lookup returns 404 on another owner's ID. PATCH nonnull value/ref/version/vault fields goes through rotation; status-only PATCH sets state; nullable value patches are not rotation. DELETE or PATCH deleted removes owner value/provider material. Explicit rotate rejects empty payload, uses same mode/version/provider guards. Definitions remain intact when an owner removes a value.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:774-886; services/secrets.ts:1086,4054-4119.
Verification: not-run — rotate increments latest, disable fresh runtime resolution, reactivate, remove only A value and keep definition/B value. Try B's value and company API mutation route ->404; confirm no value in success/error/activity. Tests secrets-routes.test.ts:356-383; secrets-service.test.ts:2313; shared mode/provider tests as company rotation. Retry: fresh rotation is version-creating, no idempotency claim. Inspect current version on uncertain result; repeated completed DELETE missing is expected.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
proposals
Capability ID: secrets/proposals.
Review: operation-reviewed.
Run-JWT agents propose new secrets or self/report bindings, inspect and withdraw permitted requests; authorized humans resolve them and the server expires them with durable redaction and linked-card state.
Shared boundary: request creation/list/withdraw uses /agents/me, verified agent_jwt with company/agent/run, not long-lived agent_key; task_bridge and skill_test denied; secrets:propose effective trust/responsible-user policy. Secret routes. Proposal service secret-proposals.ts. Direct service checks matching run existence, not independently running status (native adds its binding check). Responses strip ciphertext; agent view also strips fingerprint/length; board metadata may include fingerprint/length. 20 pending per agent + 20 creations/minute, value <=64 KiB, expiry 14 days, default page 100, maximum 200. Do not claim direct POST idempotency: it can create duplicate requests on retry; native same-call receipt replay is the dedup layer.
propose-secret
API: present — POST /api/agents/me/secret-proposals kind=secret.
Agent access: available via eligible run JWT REST/admitted native standard call_api; no dedicated CLI or admitted secret-specific production tool.
Policy: Apply the capability boundary above. name valid slash path, normalized key, nonempty justification/value; encrypted local pending ciphertext, value registered for run redaction, quota checked; no direct active company secret created before approval. Origin task inferred by execution/checkout run binding, can be null.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — pending proposal exists with origin agent/run/task, catalog lacks active secret, neither response/list/history/activity nor run logs disclose dummy; quota/oversize/untrusted/forged header/agent_key/scope denied. Failed redaction registration fails closed. Source secret-proposals.ts:316; tests secret-proposals-routes.test.ts:338,860; native actual-route runner-api.integration.test.ts:449.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
propose-binding
API: present — POST /api/agents/me/secret-proposals with kind=binding.
Agent access: partial — eligible run JWT REST/native; human governance remains intact.
Policy: Apply the capability boundary above. exactly one secretId, own sourceConfigPath, or pending same-company secretProposalId; configPath env.KEY or access.ALIAS. Target only self or downstream reports, source path owned by proposer. Direct secretId only company scope; own existing user-secret source declaration may be forwarded as a user_secret_ref preserving each future responsible user's personal value semantics. Store proposal-time organization snapshot and recheck current graph at approval. Quota and justification guard; creates linked binding confirmation interaction when origin task exists.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — self/report allowed, peer/manager/foreign/missing source/direct user secret forbidden; existing path differing binding conflicts on approval. Required dependency and source label survive reload, one source selector rule enforced; safe UI card does not contain value. Source secret-proposals.ts:360-479,553,657; tests secret-proposals-routes.test.ts:566-860,1288,1326,1489.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
list-own-or-targeted
API: present — GET /api/agents/me/secret-proposals with limit/offset.
Agent access: partial — same verified run JWT gate even though GET; includes own proposals or binding proposals targeting caller, not all company proposals. Native GET Ask/Plan still route JWT/trust policy governed.
Policy: Apply the capability boundary above. returns {proposals,nextOffset} with bounded pagination headers; value ciphertext/fingerprint/length stripped.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — owner/target versus unrelated peer list isolation; >one page, no duplicates/hidden value; invalid limits rejected. Source routes/secrets.ts:219; secret-proposals.ts:521; tests pagination secret-proposals-routes.test.ts:860.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
withdraw
API: present — DELETE /api/agents/me/secret-proposals/{id}.
Agent access: partial — verified proposer JWT only, own pending same-company proposal.
Policy: Apply the capability boundary above. terminal proposal ->409, other proposer forbidden. Withdraw scrubs pending ciphertext and cascade-rejects pending binding dependents; linked card state mirrors withdrawn. Native Ask/Plan denies DELETE.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — withdraw pending secret+binding dependent; list/card reflect durable terminal state and no material; peer/foreign/second terminal transition denied. Source routes/secrets.ts:234; secret-proposals.ts:785; tests secret-proposals-routes.test.ts:942,1455.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
board-list-and-resolution-authority
API: present — GET /api/companies/{companyId}/secret-proposals optional status/limit/offset.
Agent access: restricted board company read; no secret-proposal board list through public personal assistant catalog.
Policy: Apply the capability boundary above. bounded company list; calculated viewerCanApprove and block reason reflect pending status, secret-kind company-admin policy, binding target agent_config:update decision with requiresChangeGrant:true. Approval affordance is separate from permission to enumerate metadata.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — board list redacted metadata, member can inspect but cannot secret-approve, binding user without grant sees blocked reason; other company/agent denied. Source routes/secrets.ts:165-192,240; secret-proposal-authorization.ts.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
approve
API: present — POST /api/companies/{companyId}/secret-proposals/{id}/approve, optional cascade and overrides(name,description,providerConfigId).
Agent access: restricted — board. Direct secret approval requires company definition-admin authority; binding approval requires target agent config change authority. The current binding cascade does not independently enforce the dependency's secret-admin check; see Gaps below.
Policy: Apply the capability boundary above. only pending, unexpired, current self/report chain and authority rechecked after locks; chosen provider vault same company. Secret approval creates reference/material and scrubs pending ciphertext. Binding can cascade pending secret dependency with cascade=true; already approved dependency reused. Applying user source preserves user-secret declaration semantics. Existing different target config path conflicts. Approved secret retained if later binding apply fails; retry reuses it. Resolved state ->409, not repeated active secret creation. Linked card and dual secret/agent activity update; best-effort origin comment/wake failure does not turn committed approval into failure.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — approve secret then binding, both direct and cascade; selected vault persists. Wrong target grant/company/admin/mode, expired, changed org graph, duplicate resolution denied. Force binding failure after dependency commit and retry without creating second secret; assert ciphertext scrub + metadata-only audits and notification failure does not 500 committed state. Tests secret-proposals-routes.test.ts:239,290,338,478,518,710,1168,1220,1254,1288,1489; sources routes/secrets.ts:255, secret-proposals.ts:718, secret-proposal-notifications.ts.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. approve() cascades pending dependency via applySecretApproval() but only invokes assertCanResolve on the binding in loadForApproval; it does not separately call it for the secret dependency (secret-proposals.ts:729-762). Do not claim independent secret-admin recheck on a binding cascade without explicit evidence. Record this observed gap; map maintenance must not widen/fix governance implementation.
reject-and-expire
API: present — POST /api/companies/{companyId}/secret-proposals/{id}/reject requires reason; no external expire endpoint (server bounded expiry sweeper).
Agent access: partial — reject restricted board with same kind/target resolution policy; expiration system-only.
Policy: Apply the capability boundary above. pending terminal transition, secret-kind reject also requires admin; scrub ciphertext, cascade-reject pending secret-dependent bindings, synchronize card rejection/withdrawal/expiry. At expiry approval rejects even before sweeper marks terminal. Concurrent card/proposal races serialize; no stale accepted card after resolved proposal.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — reject then repeat ->409; empty reason invalid; unauthorized reviewer/peer/foreign denied; time-controlled expiry and dependency/card state; no new runtime authority from rejected/expired proposal. Source routes/secrets.ts:284, secret-proposals.ts:785-891; tests secret-proposals-routes.test.ts:224,906,942,995,1031,1080,1120,1168,1220.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
vault-import
Capability ID: secrets/vault-import.
Review: operation-reviewed.
Board operators manage nonsecret provider-vault configuration and health, preview metadata, and import external references with per-row outcomes and canonical duplicate checks.
provider-descriptor-and-health
API: present — GET /api/companies/{companyId}/secret-providers; GET .../secret-providers/health; POST /api/secret-provider-configs/{id}/health.
Agent access: restricted board API/CLI secrets providers -C, secrets doctor -C, secrets provider-config:health <id>.
Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. routes/secrets.ts:361-585,921-990; provider secrets/aws-secrets-manager-provider.ts.
deployment provider descriptors/health differ from selected company vault health. Selected config state readiness and provider-returned sanitized health; persisted healthCheckedAt/message/details, safe activity. A health result is not secret resolution/import proof.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — owned configured/unconfigured/disabled/coming-soon vault health; persist timestamp/reload, no raw credential/provider body; nonboard/foreign denied. Tests secrets-routes.test.ts:133,383; secret-provider-registry.test.ts, aws-secrets-manager-provider.test.ts:877.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
vault-list-get-create-update-disable
API: present — GET|POST /api/companies/{companyId}/secret-provider-configs; GET|PATCH /api/secret-provider-configs/{id}.
Agent access: restricted board UI/API/CLI provider-configs, provider-config:create/get/update under paperclipai secrets; JSON mutations use --payload-json, company routes -C.
Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. routes/secrets.ts:361-585,921-990; provider secrets/aws-secrets-manager-provider.ts.
company-scoped provider/config, status ready/warning/disabled/coming_soon, display name and nonsecret provider options. GCP/Vault cannot be promoted to ready; disabled/coming-soon cannot be default/selected for new secret runtime resolution. Disable clears default. Configuration existence does not grant remote vault credentials/access.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — create/update dummy config, reload; reject sensitive fields, unsafe address, cross-company/agent, coming-soon promotion/default; disable then fresh resolution fails visibly while reference metadata remains. Tests secrets-routes.test.ts:383-682, secrets-service.test.ts:2923-3007.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
vault-default-and-remove
API: present — POST /api/secret-provider-configs/{id}/default; DELETE /api/secret-provider-configs/{id}.
Agent access: restricted board UI/CLI provider-config:default/delete <id>.
Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. routes/secrets.ts:361-585,921-990; provider secrets/aws-secrets-manager-provider.ts.
only ready/warning default, one default per company+provider, transaction rechecks status. Removal removes local provider config, logs remoteDeleted:false; it does not delete remote provider data. Distinguish disabled metadata from removed config and inspect referencing secrets afterward rather than claiming migration.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — two vaults switch default/reload, wrong company/status denied, remove disposable config and verify provider secret survives, reconcile remaining references/health. Tests secrets-service.test.ts:2691,2713,2728, secrets-routes.test.ts:682.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
discover-config-and-preview-import
API: present — POST /api/companies/{companyId}/secret-provider-configs/discovery/preview (draft config); POST .../secrets/remote-import/preview (saved providerConfigId).
Agent access: restricted board UI/CLI provider-config:discovery-preview, remote-import:preview -C --payload-json ....
Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. routes/secrets.ts:361-585,921-990; provider secrets/aws-secrets-manager-provider.ts.
draft discovery does not persist vault; lists/samples metadata, query/page token/page size. Saved vault must be selectable in company, provider supports listing. Preview derives names/keys, canonical references, duplicate/name/key/provider-guardrail conflicts; does not read plaintext or import/create secret. AWS Paperclip-managed namespace cannot be imported as externally owned. Activity aggregate counts; provider failures sanitized.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — preview pagination, select ready versus duplicate/conflict, change draft without persistence, company/disabled/coming-soon/provider invalid; no GetSecretValue/plaintext during listing, no secret/vault row mutation. Tests secrets-routes.test.ts:407-524,724-811, secrets-service.test.ts:3261-3369,3478-3596,3846, aws-secrets-manager-provider.test.ts:536,617,714.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
commit-reference-import
API: present — POST /api/companies/{companyId}/secrets/remote-import.
Agent access: restricted board UI/CLI secrets remote-import -C ... --payload-json ....
Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. routes/secrets.ts:361-585,921-990; provider secrets/aws-secrets-manager-provider.ts.
same selectable saved vault; selected rows validated/canonicalized again, reference versions persisted, no plaintext fetched. Import operates row-by-row with imported/skipped/error counts, not atomic all-or-nothing. Exact canonical vault/reference duplicate skipped, name/key conflict skipped, remote guardrail/provider failure row error. Soft-deleted reference can be reimported; instance-secret same name/key does not collide with company ref.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — import two owned refs with one collision; reload metadata, expected imported/skipped/error, reference-only material. Repeat and confirm no second canonical ref; cross-company/disabled vault and Paperclip-managed namespace denied at commit even if preview old; change selection between preview/commit and inspect real outcomes. Tests secrets-service.test.ts:3734-3968, secrets-routes.test.ts:811, agent-instance-secrets.test.ts:222; source services/secrets.ts:4403-4608.
Gaps: only controlled AWS provider tests were inspected; live AWS identity, IAM, network, data ownership and actual import/rotation/deletion remain not-run. GCP/Vault do not get a live working path because draft config exists.
runtime-delivery
Capability ID: secrets/runtime-delivery.
Review: operation-reviewed.
Authorize env/config projection, responsible-user personal values, run-bound company value retrieval, and the deliberately server-only instance lifecycle boundary.
env-and-config-projection
API: present — configure bound consumer via its own API, then normal run/test lifecycle; no public arbitrary resolve-value endpoint for board. Concrete agent config PATCH /api/agents/{id}; normal task execution resolves saved bindings. User-perspective account/setup validation is separately scoped.
Agent access: available only for admitted authorized consumer projection; fresh model code sees its allowed env/config, not all company secret inventory. Environment injection is not blanket value-read API permission.
Policy: company secret binding must match consumer type/id/configPath and allowedBindingIds (when supplied), same company, active secret/version/vault. env.KEY -> env at run start; generic schema secret field -> adapter config; access.ALIAS -> API access and not env. latest versus pinned version recorded in value-free manifest, deleted/disabled/archived/version-disabled/revoked/provider-unavailable fail. Class-3 static lease needs exact approved target/path allowlist key. Missing required bindings block setup with diagnostic fields, optional absent personal ref skips. Audit writes best-effort in resolver, so a successful secret resolution alone does not prove every event persisted.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. services/secrets.ts:1132,1353-1455,5214,5282,5441,5598; ui/src/lib/secret-delivery.ts; tests secrets-service.test.ts:1530,1567,1607,1647,1738,2345,2442,2490,2596,2662.
Verification: not-run — env-only/API-only/both plus generic secret field on eligible adapter, compare harmless equality/length result without returning dummy, manifest IDs/version/outcome and redacted logs/errors; unbind/disable/rotate and fresh run behavior; denied consumer/path/foreign/allowlist/version. Do not claim rotation/removal retracts already projected process/model bytes.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
responsible-user-personal-projection
API: present — PATCH /api/agents/{id} declares user_secret_ref in consumer configuration. Normal run/test projection then uses the captured responsible user; there is no arbitrary-agent personal-value endpoint. Owner value changes use the /me/user-secrets operations above.
Agent access: partial runtime projection only; user values are excluded from GET /agents/me/secrets and POST key/value direct company access.
Policy: definition active and declaration matching company/consumer/configPath, captured responsible user, exactly that user's personal value and optional/required semantics; missing responsible_user_missing/user_secret_missing/binding_missing actionable. Current identity capture should be used rather than caller-supplied user override. New execution's responsible user changes which value is used, not a copied owner's secret ID. Local pre-save adapter test has an explicit owner_scoped mediation exception: resolves only authenticated user's own values without saved declarations, rejects any allowedBindingIds array, and still requires responsible user. This exception is not general run/API bypass.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. services/secrets.ts:4212-4307,5598; routes/authz.ts:251+; routes/agents.ts:3277; tests secrets-service-user-secret-owner-scoped.test.ts and secrets-service-dangling-user-secret.test.ts, secrets-service.test.ts:1688,1783; authz-secret-context.test.ts.
Verification: not-run — use the same saved agent configuration with separate runs capturing responsible users A and B; each gets its own harmless equality result. Missing/removed/inactive user or definition blocks a required value or skips an optional one; B must never fall back to A's value. Direct company resolver/catalog/API excludes personal values. Pre-save owner tests and persisted runtime require separate proof.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
api-list-bound-metadata
API: present — GET /api/agents/me/secrets.
Agent access: available with verified run-bound agent JWT via legacy REST or admitted native GET call_api; long-lived agent key plus fabricated run header denied, board denied.
Policy: explicit service running/company/agent/run check and secrets:read; low-trust/task_bridge/skill_test denied; only active company-scope bound secrets, direct agent env/access grants or IDs admitted in run secret manifest for other consumers. Returns key/name/description/delivery/projection/version plus opaque secretRef; hides internal bindingId/configPath and all values. It does not list user/instance or arbitrary unbound secret.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. routes/secrets.ts:314; services/secrets.ts:1756; tests secrets-routes.test.ts:91; agent-secrets-routes.test.ts:122,270.
Verification: not-run — env-only/API-only/both and run-manifest project ref listed, unbound/user/instance absent; metadata exact projection; foreign peer run/ended run/non-JWT/scope/company denied; activity secret.access.listed count value-free.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.
api-read-bound-value
API: present — POST /api/agents/me/secrets/{key}/value (key is secret key from list, not access alias).
Agent access: available with same verified running JWT REST. Native POST call_api only admitted standard mode; Ask/Plan reject transport POST even though this reads a value. No admitted dedicated read_secret_value binding.
Policy: list eligibility rechecked then exact grant/configPath/version; direct agent target or manifest-bound other consumer; only env/access namespace, active company/version/vault. Register redaction before response; Cache-Control:no-store, response key/value/version. Value-free access and secret.value.read success/failure audits. User/instance excluded. Credential replay encryption/history omission/10MiB applies to native surface; direct REST has no native replay receipt.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed.
Verification: not-run — allowed caller compares dummy securely, different/unbound peer and fake/ended/mismatched JWT/header/company/mode/scope denied. Remove grant/disable/rotate then issue a fresh call to prove current authority; same native call ID replays original response without re-dispatch and without plaintext stored receipt/response assets/history. Fail redaction registration ->no value response. Tests agent-secrets-routes.test.ts:122,230,270, secrets-service.test.ts:1271,1336,1414; real authenticated HTTP native authority tests services/native-runtime/runner-api.integration.test.ts:349-372, runner-api.test.ts:323-350, runner-api-log-redaction.test.ts.
Gaps: fresh local source test is not actual provider/tool-model execution; native rollout and eligible target must be evidenced by coordinator.
server-only-instance-lifecycle
API: not-applicable — trusted server lifecycle plugin callback/coordinator is the concrete existing path, not a new route or missing permission grant. agentInstanceSecretService.apply/read and native secret service agentInstance.
Agent access: restricted—never delivered to ordinary agent env/config/API catalog/value path. Owning installed lifecycle plugin server callback receives its scoped instance data. Agent cannot authorize itself into this owner scope.
Policy: company+owner agent+installed plugin, operation/version/phase/attempt lease owner and unexpired lease rechecked; nonnull writes only preparing/resuming. Encrypted local versions, isolated company/user names, removal/cascade on owning agent/plugin deletion; stale attempts fail. Lifecycle storage error must not be acknowledged as saved. Activity only key/action, not value.
Evidence: source-only — Reviewed at 3bbc2104b65caf9f7763938a01260a5673e12f7a. services/agent-instance-secrets.ts:10-38; services/secrets.ts:3494-3543; tests agent-instance-secrets.test.ts:49,107,118,134,148,174,190,206,247,266 (real DB/local encrypted storage/lifecycle callback controls, not hosted provider acceptance).
Verification: not-run — trusted lifecycle fixture save/rotate/restart/read in owner plugin only, stale version/phase/lease/company/plugin/agent denied, remove/cascade; ordinary binding/catalog/value read cannot access it; no value in logs/activity/evidence. This is a deliberate server custody restriction, not ordinary agent delivery.
Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed.