Compare commits

..

3 Commits

Author SHA1 Message Date
Sharang Parnerkar 0e1ce44146 feat(m7.3): scheduler pulls tenants from registry, env as fallback
CI / Check (pull_request) Failing after 4m27s
CI / Detect Changes (pull_request) Has been skipped
CI / Deploy Agent (pull_request) Has been skipped
CI / Deploy Dashboard (pull_request) Has been skipped
CI / Deploy Docs (pull_request) Has been skipped
CI / Deploy MCP (pull_request) Has been skipped
Replaces the M7.2-C static `SCHEDULER_TENANT_IDS` env enumeration with
a live query to the tenant-registry at every tick. New tenants get
picked up without an agent restart; the env stays as the fallback
when the registry is unreachable so the scheduler is never silenced
by a registry outage.

Resolution order
1. agent.config.tenant_registry_url → GET <url>/v1/tenants
   - 5s timeout (kept short — we'd rather fall back than block the
     tick)
   - Frozen and Archived tenants filtered out (the M7.1 status gate
     would 402/410 them anyway, no point scanning their repos)
   - Accepts either {"id"} or {"tenant_id"} for forward compatibility
     with whatever shape the registry settles on
2. SCHEDULER_TENANT_IDS env (comma-separated) — fallback when the
   registry URL is unset OR the fetch fails OR the parsed response is
   empty. Each failure mode logs a warn with the url so operators see
   the problem.
3. DEFAULT_SCHEDULER_TENANT_ID ("dev") — last-ditch fallback so a
   bare `cargo run` against a clean Mongo still scans the dev tenant.

Why each tick instead of caching
- Tick frequency is every few hours (scan_schedule default
  "0 0 */6 * * *"). The registry call is at most 4 times a day per
  agent — cheap.
- Caching introduces a staleness window for newly provisioned
  tenants. The whole point of registry integration is to pick them
  up fast.

Startup log
- Includes "tenant source=tenant-registry" or "env" so operators can
  tell at a glance which mode the scheduler is in.

Test plan
- cargo fmt --all clean
- cargo clippy -p compliance-agent -- -D warnings clean
- cargo test -p compliance-agent --lib — 232 pass (+3 new):
    * filter_active_keeps_running_skips_frozen_archived
    * deserialize_registry_response_accepts_id_or_tenant_id (covers
      the {"id"|"tenant_id"} alias)
    * tenants_from_env_resolution (single test covering unset →
      default, csv → splits, "" → default — collapsed to one to
      avoid env-var test races)

Production
- Set TENANT_REGISTRY_URL in orca-infra alongside KEYCLOAK_URL when
  the registry is ready to serve. Until then, scheduler keeps using
  SCHEDULER_TENANT_IDS — no operator action needed.
- Future M7.4 cleanup: once tenant-registry adoption is universal,
  delete SCHEDULER_TENANT_IDS env support entirely.

Stacked on #95 (admin endpoints) since that PR added
tenant_registry_url to AgentConfig. Once #95 lands this auto-
retargets to main.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-30 17:24:18 +02:00
sharang ac24ca766a feat(m7.3): cross-tenant admin HTTP endpoints (#95)
CI / Check (push) Has been skipped
CI / Detect Changes (push) Successful in 4s
CI / Deploy Dashboard (push) Has been cancelled
CI / Deploy Docs (push) Has been cancelled
CI / Deploy MCP (push) Has been cancelled
CI / Deploy Agent (push) Has been cancelled
GET /api/admin/tenants lists tenant DBs; DELETE /api/admin/tenants/{tenant_id} drops them (GDPR). Behind a separate auth path that rejects customer realm tokens.
2026-06-30 15:23:39 +00:00
sharang 485c3ff45e chore(agent): remove stale unscoped webhook routes from API router (#93)
CI / Check (push) Has been skipped
CI / Detect Changes (push) Successful in 4s
CI / Deploy Dashboard (push) Has been cancelled
CI / Deploy Docs (push) Has been cancelled
CI / Deploy MCP (push) Has been cancelled
CI / Deploy Agent (push) Has been cancelled
Webhook routes live on the separate webhook server (port 3002). M7.2-C URL form is /webhook/{tenant_id}/{platform}/{repo_id}; mounting unscoped variants on the API router would mismatch handler signatures.
2026-06-30 15:18:31 +00:00
+6 -14
View File
@@ -2,7 +2,6 @@ use axum::routing::{delete, get, patch, post};
use axum::Router; use axum::Router;
use crate::api::handlers; use crate::api::handlers;
use crate::webhooks;
pub fn build_router() -> Router { pub fn build_router() -> Router {
Router::new() Router::new()
@@ -175,17 +174,10 @@ pub fn build_router() -> Router {
"/api/v1/pentest/stats", "/api/v1/pentest/stats",
get(handlers::pentest::pentest_stats), get(handlers::pentest::pentest_stats),
) )
// Webhook endpoints (proxied through dashboard) // Webhook routes live on the separate webhook server (port 3002,
.route( // see crate::webhooks::server). The M7.2-C tenant-in-URL form is
"/webhook/github/{repo_id}", // `/webhook/{tenant_id}/{platform}/{repo_id}` and the handlers
post(webhooks::github::handle_github_webhook), // expect a (tenant_id, repo_id) path tuple. Anything mounting
) // them here on the API server would mismatch the handler
.route( // signature, so the routes are not exported.
"/webhook/gitlab/{repo_id}",
post(webhooks::gitlab::handle_gitlab_webhook),
)
.route(
"/webhook/gitea/{repo_id}",
post(webhooks::gitea::handle_gitea_webhook),
)
} }