Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32abbfb7bb |
+8
-19
@@ -7,13 +7,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# registry + cosign creds via env, NOT inline ${{ }}: the Harbor robot
|
|
||||||
# username contains '$', which sh expands when interpolated into the
|
|
||||||
# script (robot$ci-push -> robot-push) => docker login unauthorized.
|
|
||||||
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
||||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
|
||||||
COSIGN_KEY: ${{ secrets.COSIGN_KEY }}
|
|
||||||
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
|
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
RUSTFLAGS: "-D warnings"
|
RUSTFLAGS: "-D warnings"
|
||||||
# Compile cache: sccache -> Hetzner S3 (breakpilot-sccache), runner-independent
|
# Compile cache: sccache -> Hetzner S3 (breakpilot-sccache), runner-independent
|
||||||
@@ -214,12 +207,11 @@ jobs:
|
|||||||
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||||
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
||||||
IMAGE=repo.meghsakha.com/certifai/compliance-agent
|
IMAGE=repo.meghsakha.com/certifai/compliance-agent
|
||||||
echo "$REGISTRY_PASSWORD" | docker login repo.meghsakha.com -u "$REGISTRY_USERNAME" --password-stdin
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login repo.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||||
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
||||||
-f Dockerfile.agent -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
-f Dockerfile.agent -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
||||||
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
||||||
{ command -v cosign >/dev/null 2>&1 || curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 || wget -qO /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64; } || echo "::warning::cosign fetch failed"
|
command -v cosign >/dev/null 2>&1 || { curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 && chmod +x /usr/local/bin/cosign; }
|
||||||
chmod +x /usr/local/bin/cosign 2>/dev/null || true
|
|
||||||
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
||||||
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy agent"}}' "${GITHUB_SHA}")
|
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy agent"}}' "${GITHUB_SHA}")
|
||||||
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
||||||
@@ -241,12 +233,11 @@ jobs:
|
|||||||
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||||
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
||||||
IMAGE=repo.meghsakha.com/certifai/compliance-dashboard
|
IMAGE=repo.meghsakha.com/certifai/compliance-dashboard
|
||||||
echo "$REGISTRY_PASSWORD" | docker login repo.meghsakha.com -u "$REGISTRY_USERNAME" --password-stdin
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login repo.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||||
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
||||||
-f Dockerfile.dashboard -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
-f Dockerfile.dashboard -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
||||||
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
||||||
{ command -v cosign >/dev/null 2>&1 || curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 || wget -qO /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64; } || echo "::warning::cosign fetch failed"
|
command -v cosign >/dev/null 2>&1 || { curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 && chmod +x /usr/local/bin/cosign; }
|
||||||
chmod +x /usr/local/bin/cosign 2>/dev/null || true
|
|
||||||
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
||||||
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy dashboard"}}' "${GITHUB_SHA}")
|
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy dashboard"}}' "${GITHUB_SHA}")
|
||||||
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
||||||
@@ -266,11 +257,10 @@ jobs:
|
|||||||
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||||
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
||||||
IMAGE=repo.meghsakha.com/certifai/compliance-docs
|
IMAGE=repo.meghsakha.com/certifai/compliance-docs
|
||||||
echo "$REGISTRY_PASSWORD" | docker login repo.meghsakha.com -u "$REGISTRY_USERNAME" --password-stdin
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login repo.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||||
docker build -f Dockerfile.docs -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
docker build -f Dockerfile.docs -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
||||||
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
||||||
{ command -v cosign >/dev/null 2>&1 || curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 || wget -qO /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64; } || echo "::warning::cosign fetch failed"
|
command -v cosign >/dev/null 2>&1 || { curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 && chmod +x /usr/local/bin/cosign; }
|
||||||
chmod +x /usr/local/bin/cosign 2>/dev/null || true
|
|
||||||
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
||||||
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy docs"}}' "${GITHUB_SHA}")
|
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy docs"}}' "${GITHUB_SHA}")
|
||||||
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
||||||
@@ -292,12 +282,11 @@ jobs:
|
|||||||
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||||
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
||||||
IMAGE=repo.meghsakha.com/certifai/compliance-mcp
|
IMAGE=repo.meghsakha.com/certifai/compliance-mcp
|
||||||
echo "$REGISTRY_PASSWORD" | docker login repo.meghsakha.com -u "$REGISTRY_USERNAME" --password-stdin
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login repo.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||||
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
||||||
-f Dockerfile.mcp -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
-f Dockerfile.mcp -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
||||||
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
||||||
{ command -v cosign >/dev/null 2>&1 || curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 || wget -qO /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64; } || echo "::warning::cosign fetch failed"
|
command -v cosign >/dev/null 2>&1 || { curl -sSfLo /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.4.3/cosign-linux-amd64 && chmod +x /usr/local/bin/cosign; }
|
||||||
chmod +x /usr/local/bin/cosign 2>/dev/null || true
|
|
||||||
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
cosign sign --yes --key env://COSIGN_KEY "$IMAGE:latest" || echo "::warning::cosign failed"
|
||||||
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy mcp"}}' "${GITHUB_SHA}")
|
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy mcp"}}' "${GITHUB_SHA}")
|
||||||
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
||||||
|
|||||||
@@ -42,19 +42,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let pool_for_factory = pool.clone();
|
let pool_for_factory = pool.clone();
|
||||||
let service = StreamableHttpService::new(
|
let service = StreamableHttpService::new(
|
||||||
move || {
|
move || Ok(ComplianceMcpServer::new(pool_for_factory.clone())),
|
||||||
// The factory runs in the request task, still inside the bearer
|
|
||||||
// middleware's `TENANT_ID` scope, and BEFORE rmcp spawns the
|
|
||||||
// session task (which would lose the task_local). So bind the
|
|
||||||
// tenant into the session's server instance here, once.
|
|
||||||
let tenant_id = auth::current_tenant_id().ok_or_else(|| {
|
|
||||||
std::io::Error::other("no tenant context when creating MCP session")
|
|
||||||
})?;
|
|
||||||
Ok(ComplianceMcpServer::new(
|
|
||||||
pool_for_factory.clone(),
|
|
||||||
tenant_id,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
Arc::new(LocalSessionManager::default()),
|
Arc::new(LocalSessionManager::default()),
|
||||||
StreamableHttpServerConfig::default(),
|
StreamableHttpServerConfig::default(),
|
||||||
);
|
);
|
||||||
@@ -81,11 +69,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
tenant_id = %synth_tenant,
|
tenant_id = %synth_tenant,
|
||||||
"stdio transport — using synthetic tenant id; DO NOT use in production"
|
"stdio transport — using synthetic tenant id; DO NOT use in production"
|
||||||
);
|
);
|
||||||
let server = ComplianceMcpServer::new(pool, synth_tenant);
|
let server = ComplianceMcpServer::new(pool);
|
||||||
let transport = rmcp::transport::stdio();
|
let transport = rmcp::transport::stdio();
|
||||||
use rmcp::ServiceExt;
|
use rmcp::ServiceExt;
|
||||||
|
auth::TENANT_ID
|
||||||
|
.scope(synth_tenant, async {
|
||||||
let handle = server.serve(transport).await?;
|
let handle = server.serve(transport).await?;
|
||||||
handle.waiting().await?;
|
handle.waiting().await?;
|
||||||
|
Ok::<_, Box<dyn std::error::Error>>(())
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -2,33 +2,37 @@ use rmcp::{
|
|||||||
handler::server::wrapper::Parameters, model::*, tool, tool_handler, tool_router, ServerHandler,
|
handler::server::wrapper::Parameters, model::*, tool, tool_handler, tool_router, ServerHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::auth::current_tenant_id;
|
||||||
use crate::database::{Database, DatabasePool};
|
use crate::database::{Database, DatabasePool};
|
||||||
use crate::tools::{dast, findings, oscal, pentest, sbom};
|
use crate::tools::{dast, findings, oscal, pentest, sbom};
|
||||||
|
|
||||||
pub struct ComplianceMcpServer {
|
pub struct ComplianceMcpServer {
|
||||||
pool: DatabasePool,
|
pool: DatabasePool,
|
||||||
/// Tenant this session serves. Bound once at session creation (the HTTP
|
|
||||||
/// factory reads the bearer-set tenant while still in the request scope;
|
|
||||||
/// stdio passes a synthetic id) — NOT a per-request `task_local`, which is
|
|
||||||
/// lost across the `tokio::spawn` that runs the Streamable-HTTP session.
|
|
||||||
tenant_id: String,
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
tool_router: rmcp::handler::server::router::tool::ToolRouter<Self>,
|
tool_router: rmcp::handler::server::router::tool::ToolRouter<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComplianceMcpServer {
|
impl ComplianceMcpServer {
|
||||||
/// The per-tenant `Database` for this session.
|
/// Resolve the per-tenant `Database` from the bearer-set
|
||||||
|
/// `task_local`. Every tool handler calls this; missing context
|
||||||
|
/// surfaces as `internal_error` because it means the auth
|
||||||
|
/// middleware was misconfigured (handler ran without scope).
|
||||||
fn tenant_db(&self) -> Result<Database, rmcp::ErrorData> {
|
fn tenant_db(&self) -> Result<Database, rmcp::ErrorData> {
|
||||||
Ok(self.pool.for_tenant_id(&self.tenant_id))
|
let tenant_id = current_tenant_id().ok_or_else(|| {
|
||||||
|
rmcp::ErrorData::internal_error(
|
||||||
|
"no tenant context — bearer middleware not in chain".to_string(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(self.pool.for_tenant_id(&tenant_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tool_router]
|
#[tool_router]
|
||||||
impl ComplianceMcpServer {
|
impl ComplianceMcpServer {
|
||||||
pub fn new(pool: DatabasePool, tenant_id: String) -> Self {
|
pub fn new(pool: DatabasePool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pool,
|
pool,
|
||||||
tenant_id,
|
|
||||||
tool_router: Self::tool_router(),
|
tool_router: Self::tool_router(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,25 +108,16 @@ Every finding maps to its exact control family, with the most specific control o
|
|||||||
- **Generic catch-all controls co-occur.** `mc-20890 secure_development_security_code_review` appears in the top-K for many code-security findings because it is semantically near almost all of them. It's harmless (the judge grounds it, and it never crowds out the specific controls — the SQLi example didn't get it) but is a candidate for future down-weighting.
|
- **Generic catch-all controls co-occur.** `mc-20890 secure_development_security_code_review` appears in the top-K for many code-security findings because it is semantically near almost all of them. It's harmless (the judge grounds it, and it never crowds out the specific controls — the SQLi example didn't get it) but is a candidate for future down-weighting.
|
||||||
- **Corpus classification noise.** The master-controls `verification_method` classification is imperfect — e.g. a documentation control (`eu_declaration_accuracy`) is currently tagged `source_code`. That's a corpus-side data-quality issue, separate from the mapping engine.
|
- **Corpus classification noise.** The master-controls `verification_method` classification is imperfect — e.g. a documentation control (`eu_declaration_accuracy`) is currently tagged `source_code`. That's a corpus-side data-quality issue, separate from the mapping engine.
|
||||||
|
|
||||||
## Emitting over MCP — closing the loop
|
|
||||||
|
|
||||||
Findings don't just land in the dashboard; they flow to breakpilot-compliance as OSCAL over the scanner's MCP server, so the compliance report is assembled from real, control-tagged findings.
|
|
||||||
|
|
||||||
- The MCP server exposes an **`oscal_assessment`** tool: given a `repo_id`, it emits a standard OSCAL 1.1 assessment-results document for that repo's findings — mapped findings target their controls via the stamped `control_refs`, and unmapped findings are reported **as-is** (as observations), so nothing is lost.
|
|
||||||
- breakpilot pulls it: `POST /v1/cra/oscal-from-scanner` calls `oscal_assessment` over MCP (Streamable HTTP + bearer) and consumes the pre-computed OSCAL — rather than pulling raw findings and re-assessing.
|
|
||||||
|
|
||||||
**Operational note — tenant context over HTTP.** The MCP server is multi-tenant; the bearer token resolves a tenant whose per-tenant database the tools query. rmcp's Streamable HTTP transport runs each session's tool calls in a `tokio::spawn`ed task, and `task_local`s do **not** cross a spawn — so binding the tenant in a per-request middleware `task_local` leaves tool handlers with no context (every call fails `no tenant context`). The fix is to bind the tenant to the **per-session server instance** at creation (the factory runs in the request scope before the spawn), not to a per-request task_local. Until this was fixed, the loop silently failed over HTTP and consumers fell back to demo data.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
| Variable | Effect |
|
| Variable | Effect |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `BREAKPILOT_BASE_URL` | breakpilot-compliance root; enables control ingest + all mapping passes. **Unset disables all control mapping** — findings are produced without `control_refs`. |
|
| `BREAKPILOT_BASE_URL` | breakpilot-compliance root; enables control ingest + Stage 5b. Unset disables all control mapping. |
|
||||||
| `BREAKPILOT_SEMANTIC_MAPPING` | Stage 5c (semantic master-controls mapping). **Default on** (validated live). |
|
| `BREAKPILOT_SEMANTIC_MAPPING` | Enables Stage 5c (semantic master-controls mapping). Default off. |
|
||||||
| `BREAKPILOT_GROUNDED_CHECKS` | Stage 5d (grounded surface checks). **Default on** (validated live). |
|
| `BREAKPILOT_GROUNDED_CHECKS` | Enables Stage 5d (grounded surface checks). Default off. |
|
||||||
| `BREAKPILOT_SNAPSHOT_DIR` | Where OSCAL catalog snapshots and the cached control-embedding index live. |
|
| `BREAKPILOT_SNAPSHOT_DIR` | Where OSCAL catalog snapshots and the cached control-embedding index live. |
|
||||||
|
|
||||||
The semantic and grounded passes default **on** now that both are validated live; each is still a no-op if `BREAKPILOT_BASE_URL` is unset or the catalog is unreachable, so they only ever add coverage. The live verifications live in `compliance-agent/tests/c5_semantic_live.rs` and `grounded_surface_live.rs` (ignored; run with `--ignored`).
|
The semantic and grounded passes are gated because they are the heavier, less deterministic paths; they stay off until verified live against a deployed catalog. The live verification lives in `compliance-agent/tests/c5_semantic_live.rs` (ignored; run with `--ignored`).
|
||||||
|
|
||||||
## Appendix — the master-controls data pipeline
|
## Appendix — the master-controls data pipeline
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user