feat(m7.2-C): migrate background paths to per-tenant pool #88
Reference in New Issue
Block a user
Delete Branch "feat/m7.2c-background-paths"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes the loop on M7.2 isolation for background paths that don't have a JWT context: scheduler, webhooks, and the agent's
run_scan/run_pr_reviewhelpers all now take atenant_idat the boundary and resolve to a tenant-scopedDatabaseviadb_pool.for_tenant_id(...).Internal orchestrators (
PipelineOrchestrator,PentestOrchestrator) and pipeline helpers were already DB-agnostic — they takedb: Databaseat construction and don't care which tenant it points to. So the migration scope is purely the boundary code.Stacked on PR-B (#87) — diff shown is only C's changes.
Changes
DatabasePool::for_tenant_id(&str)— same asfor_tenantbut accepts a baretenant_idstring. Background paths don't have a fullTenantContext.for_tenantis now a thin wrapper that delegates.agent.run_scan(tenant_id, repo_id, trigger)— pulls the tenant database before constructing thePipelineOrchestrator. Was:run_scan(repo_id, trigger)readingagent.db.agent.run_pr_review(tenant_id, repo_id, ...)— same shape./webhook/{tenant_id}/{platform}/{repo_id}. Tenant is part of the URL path because webhooks arrive without a JWT — they're authenticated via per-repo HMAC, not the tenant gate. The dashboard surfaces the full per-tenant URL when the repo is registered. All three handlers (gitea, github, gitlab) updated.scheduler.rs— iterates tenants from$SCHEDULER_TENANT_IDS(comma-separated env), orDEV_TENANT_ID's default ofdev. Bothscan_all_reposandmonitor_cvesnow run once per configured tenant. PR-D will replace this static config with a pull from the tenant-registry.api/handlers/repos.rs::trigger_scannow passestenant.0.tenant_idintorun_scan.What's unchanged because it didn't need to change
PipelineOrchestrator,PentestOrchestrator— takedb: Databaseat construction; tenant-DB-agnostic by design. The caller picks the tenant DB. (Per-tenant DB pattern means the orchestrator never sees a tenant_id directly — it just writes to whichever DB it was handed.)pipeline/{dedup,graph_build,issue_creation,sbom/mod}.rs,pentest/{context,report/html/*}.rs,trackers/jira.rs,llm/triage.rs— take&Databaseor&mongodb::Databaseas args, transitively tenant-scoped via the caller.Grep proof:
Test plan
cargo fmt --all -- --checkcleancargo clippy --workspace --exclude compliance-dashboard -- -D warningscleancargo test -p compliance-core --lib— 7 passcargo test -p compliance-agent --lib— 228 passcargo test -p compliance-agent --test tenant_isolation— 5 passcargo test -p compliance-agent --test tenant_status_middleware— 6 passWhat PR-D does
agent.dbfield — no remaining call sites (verified by grep above).main.rs/TestServerstop constructing the legacyDatabase; only the pool remains.list_tenants,drop_tenant_db) on the pool for offboarding flows.SCHEDULER_TENANT_IDSenv with a pull from the tenant-registry so the scheduler picks up new tenants automatically.🤖 Generated with Claude Code
Closes the loop on M7.2 isolation for paths that don't have a JWT context: scheduler, webhooks, and the agent's `run_scan` / `run_pr_review` helpers all now take a `tenant_id` at the boundary and resolve to a tenant-scoped `Database` via `db_pool.for_tenant_id(...)`. Internal orchestrators (PipelineOrchestrator, PentestOrchestrator) and pipeline helpers were already DB-agnostic — they take `db: Database` at construction and don't care which tenant it points to. Changes - DatabasePool::for_tenant_id(&str) — same as for_tenant but accepts a bare tenant_id. Background paths don't have a full TenantContext. for_tenant is now a thin wrapper that delegates. - agent.run_scan(tenant_id, repo_id, trigger) — pulls the tenant database before constructing the PipelineOrchestrator. Was: run_scan(repo_id, trigger) reading agent.db. - agent.run_pr_review(tenant_id, repo_id, ...) — same shape. - Webhook routes change: /webhook/{tenant_id}/{platform}/{repo_id}. Tenant is part of the URL path because webhooks arrive without a JWT — they're authenticated via per-repo HMAC, not the tenant gate. The dashboard surfaces the full per-tenant URL when the repo is registered. All three handlers (gitea, github, gitlab) updated. - scheduler.rs — iterates tenants from $SCHEDULER_TENANT_IDS (comma-separated env), or DEV_TENANT_ID's `dev` default. Both scan_all_repos and monitor_cves now run once per configured tenant. M7.2-D will replace this static config with a pull from the tenant-registry. - api/handlers/repos.rs::trigger_scan now passes tenant.0.tenant_id. What's unchanged because it didn't need to change - PipelineOrchestrator, PentestOrchestrator: take `db: Database` at construction — they're tenant-DB-agnostic by design. The caller picks the tenant DB. - pipeline/{dedup,graph_build,issue_creation,sbom/mod}.rs, pentest/{context,report/html/*}.rs, trackers/jira.rs, llm/triage.rs: take `&Database` or `&mongodb::Database` as args, transitively tenant-scoped via the caller. Test plan - cargo fmt --all clean - cargo clippy --workspace --exclude compliance-dashboard -- -D warnings clean - cargo test -p compliance-core --lib — 7 pass - cargo test -p compliance-agent --lib — 228 pass - cargo test -p compliance-agent --test tenant_isolation — 5 pass - cargo test -p compliance-agent --test tenant_status_middleware — 6 pass What's left (PR-D) - Drop the transitional agent.db field — no remaining call sites (verified by `grep -rn "agent\.db\b" compliance-agent/src`). - main.rs / TestServer stop building the legacy Database; only the pool remains. - Add cross-tenant admin helpers (list tenants, drop tenant DB) on the pool for offboarding flows. - Pull tenants from the tenant-registry instead of an env var. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Superseded — the M7.2 stack was inadvertently included in PR #90 squash-merge (
5648291) on main. The dashboard PR was branched off this PR's descendant and its full diff swept into main as one squash commit. M7.2-A through M7.2-D are all live on main and in production. Closing without merging.Pull request closed