Skip to content

feat(secrets): registration API for secret_dependencies (#10088 Task 8.2) - #13065

Merged
mrveiss merged 3 commits into
Dev_new_guifrom
issue-13064
Jul 30, 2026
Merged

mrveiss merged 3 commits into
Dev_new_guifrom
issue-13064

Conversation

@mrveiss

@mrveiss mrveiss commented Jul 30, 2026 •

Copy link
Copy Markdown
Owner

Closes #13064

Thinking Path

Audited the whole of Task 8 (umbrella #10088) before touching anything, per the
FIFO-backlog instruction, because the umbrella still shows Task 8 entirely
unchecked and Task 9 flagged as a dependency-edge prerequisite.

Task 9 blocker check (does NOT block 8.2): secrets_authz.authorize() has
an explicit marker — # agent / service principals are refined in Task 9.2; default closed (autobot-backend/services/secrets_authz.py:117) — confirming
Task 9.2 (agent/service → effective principal for RBAC) is genuinely
incomplete for the access side of the graph. But secret_dependencies
does not need an authenticated agent/service principal: dependent_kind/
dependent_id are descriptive strings naming what depends on a secret
(models/secret_dependency.py:44-54), not a vault/principal to authorize
against. The only identity the registration API needs is the caller doing
the registering
, and that's already solved — principal (user RBAC,
api/envelope_secrets.py:60) and, separately, service_principal (HMAC /
X-Internal-API-Key, api/envelope_secrets.py:72, landed via #10478) already
resolve callers today. Task 9 does not block 8.2.

8.1 audit (already done): secret_grants.grantee stores a VaultRef
string (kind:id) — migration 20260614_057_secrets_envelope_store.py:86-97
— so every grant already carries grantee principal-type/id (folded into Task
2's schema exactly as the PRD says). services/secrets_access_audit.py
(describe_secret_access, merged PR #10344) expands team:/role:/
company: grants through the membership tables into effective member users —
the RBAC-expansion the PRD calls for. Org coords concretely present: only
company_id (LLC company) — no project_id/sprint_id/team_id columns
exist on any secrets table today; agent_id/service_id are folded into the
generic dependent_kind/dependent_id pair rather than separate columns.

8.2 audit (mostly already done, one real gap): grep found the model,
migration 061, and SecretDependencyService (register/what_depends_on/
secrets_for_dependent/unregister) already merged — under the umbrella's
earlier task numbering, PRs #10375/#10381 built exactly what current 8.2
describes, plus a GET /{secret_id}/dependencies query endpoint (arguably
8.4 scope, shipped early). Gap: no HTTP path to register a dependency —
SecretDependencyService.register/unregister were only callable
in-process. Filed and closed by this PR: #13064.

Designed against real seed shapes rather than an imagined one: checked
AGENT_SECRET_MAPPINGS (services/agent_secrets_integration.py:53, keyed by
agent_type string like "interactive_terminal") and the workflow
${secrets.NAME} reference format (services/workflow_secret_service.py,
services/workflow_automation/executor.py) — both fit dependent_kind/
dependent_id as plain strings, so 8.3's future seeders need no model change.

No migration in this PR — 061 already has everything 8.2's model needs
(FK CASCADE, unique constraint for idempotency, optional company_id).
Adding new schema for the reason above would be speculative ahead of 8.3.

What Changed

  • SecretsCoordinator.register_dependency / .unregister_dependency
    (autobot-backend/services/secrets_coordinator.py) — same write-authority
    gate on the secret's owner vault as create/rotate/delete (registering a
    dependency is secret metadata, not a grant, so it doesn't need share).
  • POST /api/v2/secrets/{secret_id}/dependencies and
    DELETE /api/v2/secrets/{secret_id}/dependencies/{dependent_kind}/{dependent_id}
    (autobot-backend/api/envelope_secrets.py) — thin FastAPI shells over the
    coordinator, same exception-mapping pattern as every other route in the
    router.
  • Filed issue feat(secrets): registration API for secret_dependencies (#10088 Task 8.2) #13064 tracking this specific gap (closed by this PR).

Verification

  • py_compile / flake8 --max-line-length=120 / black --check --line-length=120 — clean on all 3 changed files.
  • Coordinator-level tests (real Postgres, migration-gate pattern,
    tests/migrations/test_secret_dependencies.py):
    register → read-back via describe_dependencies; idempotent through the
    coordinator (not just the service); unauthorized caller → SecretAccessError;
    unknown secret → SecretNotFoundError; unregister removes exactly one row.
    6 passed (was 5 before this PR — pre-existing model/service/migration
    tests unaffected).
  • Ran against a disposable local Postgres (initdb private cluster, port
    5499) — did not touch the shared host cluster's pg_hba.conf.
  • cp-swapped baseline diff: reverted the 3 changed files via git checkout --, ran test_secret_dependencies.py + test_raw_client_session_ceiling_12992.py
    • test_startup_imports.py → 357 passed; restored via cp, reran →
      358 passed (the one new test). Identical failing set (0) before/after.
  • Startup import smoke (tests/test_startup_imports.py) and the raw-ClientSession
    ceiling guard (tests/test_raw_client_session_ceiling_12992.py) both included
    in the before/after run above — unaffected.

Model Used

Claude Sonnet 5

mrveiss added 2 commits July 30, 2026 23:04
…ncies (#10088)

Task 8.2 of umbrella #10088 already shipped the model/migration/service (061,
PR #10375/#10381 under the umbrella's earlier numbering) plus a read-only
GET /{secret_id}/dependencies query. The registration half never got an HTTP
surface: SecretDependencyService.register/unregister were only callable
in-process. Adds SecretsCoordinator.register_dependency/unregister_dependency
(same write-authority gate as create/rotate/delete) and
POST/DELETE /api/v2/secrets/{secret_id}/dependencies so 8.3's seed scanners
and admins have something to call.
#10088)

Register/read-back, idempotency through the coordinator (not just the
service), unauthorized-caller rejection, and unknown-secret 404 for the new
register_dependency/unregister_dependency methods.
@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No hardcoded values detected that have SSOT config equivalents!

Auto-regenerated (py3.14) to match the backend schema so the required
verify-generated-types gate passes. Triggered by auto-fix-generated-types.yml.
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mrveiss
mrveiss merged commit 4146b5c into Dev_new_gui Jul 30, 2026
43 checks passed
@mrveiss
mrveiss deleted the issue-13064 branch July 30, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant