Skip to content

v9.1.0 — Audit coverage made permanent + the sensitive-data lever now enforces

Choose a tag to compare

@saurabhjain1592 saurabhjain1592 released this 12 Jun 18:07
7f2c283

[9.1.0] - 2026-06-12 — Audit coverage made permanent, policy-inventory truth, a portal policy-display fix, and the sensitive-data lever now enforced

Community. v9.0.0 converged every enforcement plane onto one canonical audit vocabulary and closed the then-known early-return-deny holes by hand. v9.1.0 makes that coverage durable instead of a recurring pre-release sweep: a deterministic CI gate now fails the build whenever a Policy Enforcement Point's deny path doesn't write a canonical audit_logs row, the last remaining agent-plane gaps are closed (so the gate reports zero deferred exceptions), the built-in policy inventory is pinned to a single source of truth, a customer-portal bug that silently hid most seeded system policies is fixed, and the sensitive-data governance lever — long documented but inert — now actually enforces. One behavior change to note: the strict and compliance profiles now BLOCK credential/secret detections that previously only logged (see Fixed); set SENSITIVE_DATA_ACTION=log to retain the prior behavior. The audit and inventory changes are otherwise additive; a single data migration realigns a legacy sensitive-pattern phase column to the active action with no behavior change.

Added

  • A deterministic audit-coverage CI gate that ends the recurring "this deny path forgot to audit" surprises. A new test walks every non-test .go file under platform/ and ee/platform/, resolves from the parsed AST every function that calls the policy decision engine (EvaluateRequest / EvaluateResponse / EvaluateDynamicPolicies / EvaluatePolicy / EvaluateStepGate / EvaluateMCPPermission / EvaluateWithGracefulDegradation, plus a one-hop set of in-tree policy-delegating helpers), and fails the build if any such enforcement point's deny path doesn't write a canonical row through a blessed audit writer. Every conscious exception lives in a checked-in, reviewed allowlist with a one-line reason — BY-DESIGN (engine-internal / adapter / dry-run whose audit is the caller's responsibility, with the auditing caller named) or a tracked deferred gap. This replaces the hand-run coverage sweeps that historically found a fresh batch of holes only after they shipped. The gate's known structural limits — single-hop helper resolution and single-deny-per-function detection — are documented.

Fixed

  • Every Policy Enforcement Point now audits — the gate reports zero deferred exceptions. The last agent-plane gaps the new gate flagged are closed so a denied request can no longer return before recording its decision:
    • Agent /api/request denials write a canonical plane=agent row. The agent proxy's terminal denials (circuit breaker, static / tenant policy, HITL gate, budget) previously landed only in the reader-less legacy agent_audit_logs table, so an agent-side block was invisible in the portal /decisions feed and the compliance exporters. Each deny now also writes a canonical audit_logs row via the established decision writer, keyed on the authenticated user / tenant.
    • The MCP service-license permission gate audits its 403. An authorization failure now writes a canonical plane=mcp blocked row, keyed on the authenticated request identity (never the service-license deployment id, which is the licensee — not a customer tenant); the license key is never passed to the writer.
    • The legacy in-memory HITL engine audits a fail-open policy-check error. When the optional in-memory HITL gate's policy check itself errors, the engine still fails open for availability, but the errored governance verdict is no longer lost — it writes a canonical error step_gate row instead of being silently treated as an allow.
  • The sensitive-data governance lever now actually enforces — on both the request and response planes. (Community) The built-in sensitive-data system policies (credentials, tokens, secrets, connection strings) resolved to a hardcoded log regardless of AXONFLOW_PROFILE or SENSITIVE_DATA_ACTION — the documented default=warn / strict=block posture was a no-op. Sensitive-data is now wired into the action-override map (mirroring SQL-injection and PII) and evaluated on every request plane and the response plane, so the profile and env lever drive it.
    • ⚠️ Behavior change: the strict and compliance profiles now BLOCK sensitive-data detections that previously only logged, and the default profile now WARNs (was log) — on both the request and response planes (a credential-shaped LLM response is withheld under strict/compliance). This matches the long-documented Governance Profiles matrix and the System Policies reference. A deployment running AXONFLOW_PROFILE=strict/compliance will start blocking content carrying credentials/secrets. Set SENSITIVE_DATA_ACTION=log (or =warn) to retain the prior pass-through behavior.
  • Three privileged mutations that were unaudited now write a persistent, secret-free audit row. Reusing the established writers (no new table):
    • SCIM bearer-token mint / revoke. (Enterprise) Token create / revoke now emit an admin_audit_log event on every outcome, keyed on the session tenant; the row carries only the token id / display prefix / name through an allowlist — the minted plaintext value and its hash structurally cannot be logged.
    • Deployment upgrade trigger. (Enterprise) The portal's trigger-upgrade endpoint now audits every post-auth outcome (validation / lookup / cloud-API failures and the terminal success / partial / all-failed result) with the session org, initiator, and targeted service; a decode failure is recorded with a fixed label, never the request body.
    • Legacy in-memory HITL gate verdicts. A block / require_approval verdict from the optional in-memory HITL engine now emits a canonical step_gate audit_logs row.
  • The customer-portal Policies page now shows all seeded system policies instead of silently dropping them. (Enterprise / Community) The unified-policies view fetches the seeded system (static) policies from the agent over an internal-service-authenticated call. Both docker-compose.yml and docker-compose.enterprise.yml defaulted the shared internal-service secret to empty, so on a local / evaluation enterprise stack the agent rejected the unauthenticated call with a 401, and the portal handler silently dropped every static policy — leaving a short list (≈17) that looked complete. The compose files now default that secret to a shared local-dev value across the agent, orchestrator, and portal (real deployments still inject their own secret), and the list / summary / effective unified-policies endpoints now return an additive partial flag with source_errors so a degraded policy view is never presented as complete.

Changed

  • The built-in policy inventory has a single source of truth: the migrations. (Community) A dead, never-consumed in-code seed file (platform/agent/system_policies_seed.go) that advertised a phantom 106-policy count — and caused confusion about the real number — is deleted, along with the four test files that solely exercised it. The authoritative inventory is now pinned by a red-on-revert real-Postgres test against a fully-migrated database: 79 immutable system policies (69 static + 10 dynamic), 103 enabled out of the box (any tier), 112 seeded rows total. Stale count comments and references to the deleted file were corrected. No runtime behavior change — the deleted Go definitions never reached the database or the engine.
  • A legacy sensitive-pattern phase column realigned to the active action. (Community) A data migration realigns the per-phase action column on the built-in SQL-injection system policies to match their already-relaxed base action, so the stored value no longer contradicts the runtime posture (which is profile-driven). No behavior change — the runtime already used the profile/override action; this removes a stale column that misrepresented the default posture.

CI / Internal

  • The audit-coverage gate runs as a dedicated, DB-free CI job wired into the test summary, so every change that adds or moves an enforcement point is checked automatically.

Full release notes: https://docs.getaxonflow.com/docs/releases/v9-1-0
Source-available under BSL 1.1. Upgrade: docker compose pull && docker compose up -d.