Files
git.stella-ops.org/docs/modules/policy/contracts/policy-console-23-001-console-api.md
StellaOps Bot 37cba83708
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
up
2025-12-03 00:10:19 +02:00

6.1 KiB
Raw Blame History

Contract: POLICY-CONSOLE-23-001 — Console findings/export & simulation surfaces

Status: Draft → Proposed (2025-12-02)

Scope

  • Provide deterministic, tenant-scoped APIs from Policy Engine to StellaOps Console for findings browse/export and simulation/explain experiences.
  • Replace legacy ad-hoc Console queries with cursor-based, RBAC-aware endpoints that expose provenance and aggregation hints.
  • Keep all responses deterministic (stable ordering, explicit timestamps, no wall-clock/default time windows).

Versioning & Compatibility

  • schemaVersion: console-policy-23-001 (bumped on breaking changes).
  • Media type: application/vnd.stellaops.console-policy-23-001+json (clients MUST send Accept and SHOULD send Content-Type).
  • Backward-compatible additions follow additive fields; ordering and cursor format remain stable.

Authentication & RBAC

  • Required scopes: policy:read, effective:read, explain:read (all tenant-scoped).
  • Optional findings:export to enable NDJSON bulk export.
  • All endpoints require X-Tenant-Id; server enforces tenant filter and rejects cross-tenant cursor reuse.

Determinism Rules

  • Ordering: policyVersion DESC, artifactDigest ASC, purl ASC, ruleId ASC, findingId ASC.
  • Cursor: opaque, URL-safe base64 of the last tuple above; contains policyVersion|artifactDigest|purl|ruleId|findingId plus schemaVersion. No server clocks in cursors.
  • Timestamps: clients MUST provide evaluationTimestamp or timeWindowStart/End; server never injects DateTime.UtcNow defaults.
  • Randomness/network access disallowed; sampling ratios must be provided by the client or policy config.

Endpoints

1) List findings (paged)

  • GET /policy/console/findings
  • Query params
    • cursor (string, optional)
    • limit (int, 1500, default 100)
    • severityBand[] (enum: critical|high|medium|low|unknown)
    • ruleId[], policyId, policyVersion
    • artifactDigest[], purl[], namespace[]
    • advisoryId[], vexStatement[]
    • state[] (open|waived|fixed|not_applicable)
    • timeWindowStart, timeWindowEnd (ISO-8601, optional)
    • sort (one of default, severity_desc, artifact, rule); default respects deterministic tuple above.
  • Response
    {
      "schemaVersion": "console-policy-23-001",
      "items": [
        {
          "findingId": "ulid",
          "policyVersion": "2025.11.24",
          "artifactDigest": "sha256:...",
          "purl": "pkg:maven/org.example/foo@1.2.3",
          "ruleId": "RULE-1234",
          "severity": "high",
          "state": "open",
          "explainSummary": {
            "hitRules": ["RULE-1234"],
            "traceSampleId": "ulid",
            "rationale": ["package matches advisory CVE-2025-1234"]
          },
          "provenance": {
            "evaluationTimestamp": "2025-11-28T00:00:00Z",
            "effectiveFindingHash": "be...",
            "source": "materialized"
          }
        }
      ],
      "cursor": { "next": "b64...", "prev": "b64..." },
      "aggregates": {
        "countsBySeverity": {"critical": 1, "high": 5, "medium": 12, "low": 3, "unknown": 0},
        "countsByRule": [{"ruleId": "RULE-1234", "count": 4}],
        "countsByPolicyVersion": [{"policyVersion": "2025.11.24", "count": 25}]
      }
    }
    

2) Finding explain trace (summary)

  • GET /policy/console/findings/{findingId}/explain
  • Returns deterministic trace summary for UI drawer (no full trace fan-out): hit rules, key facts, sampled trace token, policyVersion, evaluationTimestamp, hashes.
  • Optional format (json default, markdown for UI preview); output ordering stable.

3) Simulation/export diff (used by POLICY-CONSOLE-23-002)

  • POST /policy/console/simulations/diff
  • Body
    {
      "baselinePolicyVersion": "2025.11.24",
      "candidatePolicyVersion": "2025.12.02",
      "artifactScope": [{"artifactDigest": "sha256:..."}],
      "budget": {"maxFindings": 2000, "maxExplainSamples": 50},
      "filters": {"severityBand": ["high","critical"]}
    }
    
  • Response
    {
      "schemaVersion": "console-policy-23-001",
      "summary": {
        "before": {"total": 120, "severity": {"critical":4,"high":30,"medium":60,"low":26}},
        "after": {"total": 98, "severity": {"critical":3,"high":22,"medium":55,"low":18}},
        "delta": {"added":12,"removed":34,"regressed":2}
      },
      "ruleImpact": [
        {"ruleId":"RULE-1234","added":3,"removed":10,"severityShift":{"high→medium":6}},
        {"ruleId":"RULE-2000","added":1,"removed":0}
      ],
      "samples": {
        "explain": ["trace-token-1","trace-token-2"],
        "findings": ["finding-ulid-1","finding-ulid-2"]
      },
      "provenance": {
        "baselinePolicyVersion": "2025.11.24",
        "candidatePolicyVersion": "2025.12.02",
        "evaluationTimestamp": "2025-12-02T00:00:00Z"
      }
    }
    
  • Ordering of ruleImpact array: ruleId ASC; samples ordered by hash.

4) Bulk export (NDJSON)

  • POST /policy/console/findings/export
  • Body accepts same filters as list endpoint plus format (ndjson only) and maxRows (hard cap 50k).
  • Response streams NDJSON of finding records in deterministic ordering with content hashes.

Error Model

  • 400 with machine-readable code (invalid_filter, unsupported_schemaVersion, budget_exceeded).
  • 401/403 for auth/scope failures; 409 when schemaVersion mismatch.
  • 429 when budget limits tripped; include retryAfterSeconds but never implicit sleep in server.

Non-Goals

  • No mutable state or approvals exposed here; status transitions remain in Console backend via existing endpoints.
  • No live wall-clock filtering; clients must pass explicit windows.

Testing Hooks

  • Provide X-Dry-Run: true to validate filters and budgets without executing evaluation.
  • X-Debug-Sampling: <0..1> allowed in non-production tenants only; otherwise rejected.

Implementation Notes

  • Reuse batch evaluation pipeline for simulation diff; reuse materialized effective_finding_* collections for listing/export.
  • Enforce deterministic evaluationTimestamp supplied by caller; reject missing timestamp when baselinePolicyVersion != candidatePolicyVersion.
  • All aggregates computed in-memory over deterministically ordered result sets; no sampling unless explicitly requested.