Skip to content

Commit df6496e

Browse files
committed
feat: v8.5.1 -- licensed tier reconciled at boot + dev-mode token endpoint
Patch release synced from enterprise. No breaking changes; additive migration only. Fixed (Community): - Licensed tier is now written into the database at boot. After validating the deployment license, the agent upserts the deployment organization's tier and max_nodes to the licensed values via a new RLS-safe SECURITY DEFINER migration, so the portal UI, node-limit enforcement, and compliance-evidence paths no longer lag the in-memory tier (surfaced at /health) on a fresh install. The promotion is idempotent (writes only when tier/limit differs) and non-fatal. Added (Community): - Dev-mode token endpoint: POST /api/v1/dev/token. In an explicitly non-production deployment, mints a short-lived HS256 user_token from the authenticated Basic-auth credential so local and CI integrations don't have to hand-run a JWT signing script. Fail-closed: the route is only registered when a non-production ENVIRONMENT / DEPLOYMENT_MODE / DEPLOYMENT_KIND is set (else 404), and returns 503 if JWT_SECRET is not configured. Tenant inherited from the Basic-auth username; signing algorithm pinned to HS256. Never reachable in production. Documentation: - Architecture: "Five Runtime Modes" overview with Decision / MAP / WCP sequence diagrams describing how governance is enforced in each runtime mode. Version: all version sites bumped to 8.5.1. Signed-off-by: AxonFlow Team <bot@getaxonflow.com>
1 parent 6d1ef59 commit df6496e

40 files changed

Lines changed: 2542 additions & 147 deletions

.github/workflows/security.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ jobs:
144144
name: Trivy Filesystem Scan
145145
runs-on: ubuntu-latest
146146
needs: [detect-changes]
147+
# Trivy's Java analyzer resolves remote parent POMs by default. On
148+
# ee/examples/compliance/rbi-sebi/java/pom.xml that network call cancels
149+
# ("semaphore acquire: context canceled") and FATAL-aborts the WHOLE fs
150+
# scan -> no SARIF -> Security Scan Summary red on every PR. Offline scan
151+
# disables remote dependency resolution (the crash class); skip-dirs below
152+
# also excludes example projects, which are not shipped artifacts.
153+
env:
154+
TRIVY_OFFLINE_SCAN: 'true'
147155
# Run if: push/schedule/workflow_dispatch OR (PR/merge_group with security-relevant changes)
148156
if: |
149157
always() &&
@@ -164,6 +172,7 @@ jobs:
164172
format: 'sarif'
165173
output: 'trivy-fs-results.sarif'
166174
severity: 'CRITICAL,HIGH,MEDIUM'
175+
skip-dirs: 'ee/examples'
167176

168177
- name: Upload Trivy results to Security tab
169178
uses: github/codeql-action/upload-sarif@v4
@@ -180,6 +189,7 @@ jobs:
180189
format: 'table'
181190
severity: 'CRITICAL,HIGH'
182191
exit-code: '1'
192+
skip-dirs: 'ee/examples'
183193

184194
# Trivy Configuration Scan
185195
trivy-config-scan:

CHANGELOG.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,30 @@ community mirror, **Enterprise** changes are EE-only.
1212

1313
## [Unreleased]
1414

15+
## [8.5.1] - 2026-06-08 — Licensed tier reported correctly in the portal/database + dev-mode token endpoint
16+
17+
Patch release. Fixes a tier-reporting divergence where the licensed tier was held only in agent memory and never written to the `organizations` table, so the portal and other database consumers could lag behind `/health`. Also adds a non-production developer convenience for minting user tokens. Additive migration only; no breaking changes.
18+
19+
### Added (Community)
20+
21+
- **Dev-mode token endpoint (`POST /api/v1/dev/token`).** In an explicitly non-production deployment, mints a short-lived HS256 `user_token` from the authenticated Basic-auth credential, so local and CI integrations don't have to hand-run a JWT signing script. Fail-closed: the endpoint is **only registered** when an explicitly non-production `ENVIRONMENT` / `DEPLOYMENT_MODE` / `DEPLOYMENT_KIND` is set — otherwise the route returns `404`; and when registered but `JWT_SECRET` is not configured it returns `503` rather than minting. The token's tenant is inherited from the Basic-auth username, and the signing algorithm is pinned to HS256. Never reachable in production.
22+
23+
### Fixed (Community)
24+
25+
- **The agent now writes the licensed tier into the database at boot.** After validating the deployment license, the agent upserts the deployment organization's `tier` and `max_nodes` to the licensed values, using a new RLS-safe `SECURITY DEFINER` migration so the write clears `FORCE ROW LEVEL SECURITY` without giving the request path elevated privileges. Previously the licensed tier lived only in agent memory (surfaced at `/health`) while `organizations.tier` stayed at the seeded `Community` default — so the portal UI, node-limit enforcement, and compliance-evidence paths could report `Community` on a valid Enterprise license. The promotion runs at boot and is idempotent: it writes only when the tier or node limit actually differs.
26+
- **Tests:** added a runtime end-to-end test that boots a freshly-installed Enterprise deployment and asserts the database reports `Enterprise` with no prior request traffic, plus a migration-level unit test for the promotion helper.
27+
28+
### Documentation
29+
30+
- Expanded architecture documentation: a "Five Runtime Modes" overview with Decision / MAP / WCP sequence diagrams describing how governance is enforced in each runtime mode.
31+
1532
## [8.5.0] - 2026-05-30 — Decision Mode context propagation + Pasal 56(b) attestation + multi-arch images
1633

1734
Minor release. Decision Mode gains request-context propagation and durable audit persistence, OJK compliance gains an explicit UU PDP Pasal 56(b) transfer-basis tag plus a wired cross-border-transfers export, and all six platform images now ship for both `linux/amd64` and `linux/arm64`. Indonesia compliance migrations (OJK + UU PDP + BI) relocated from `industry/banking/` to `enterprise/` so they load in every in-vpc-enterprise deployment by default. No breaking changes. SDKs are also updated in this release train — Go / Python / TypeScript / Java to **v8.4.0** and Rust to **v0.6.0** — adding the typed `context` field on `DecisionSummary` / `DecisionExplanation` and the `pasal_56b_dpa` transfer-basis value; see each SDK's own release notes for details.
1835

1936
### Added (Community)
2037

21-
- **Decision Mode request-context propagation (`request.context`).** `POST /api/v1/decide` accepts an optional top-level `context` object — arbitrary caller-supplied key/value metadata (e.g. `tenant_tier`, `region`, `feature_flag`) that rides alongside the decision for audit and correlation. Keys are filtered against an allowlist, canonicalized, capped at 256 bytes per value and 10 keys per request, and a `request.context.truncated` flag is set when either cap trims the payload. Allowed keys land as OTel span attributes under `request.context.<key>` for trace-side filtering. The allowlist is configurable via `AXONFLOW_DECISION_CONTEXT_ALLOWLIST` (comma-separated); the default ships the BukuWarung-aligned key set. Closes #2509.
38+
- **Decision Mode request-context propagation (`request.context`).** `POST /api/v1/decide` accepts an optional top-level `context` object — arbitrary caller-supplied key/value metadata (e.g. `tenant_tier`, `region`, `feature_flag`) that rides alongside the decision for audit and correlation. Keys are filtered against an allowlist, canonicalized, capped at 256 bytes per value and 10 keys per request, and a `request.context.truncated` flag is set when either cap trims the payload. Allowed keys land as OTel span attributes under `request.context.<key>` for trace-side filtering. The allowlist is configurable via `AXONFLOW_DECISION_CONTEXT_ALLOWLIST` (comma-separated); the default ships a curated set of agent/session/leader identity headers plus a tenant-scoped header family. Closes #2509.
2239

2340
- **Decision Mode decisions now persist to `audit_logs`.** Previously `POST /api/v1/decide` emitted only an OTel span, so `GET /api/v1/decisions` returned empty for Decision Mode callers who had not wired an OTel backend. Each decision now also writes a best-effort row to `audit_logs` (mirroring `writeExplainableAuditLog`), with the propagated context stored under `policy_details->'context'`. `GET /api/v1/decisions` surfaces a 5-key truncated view of the context; the explain endpoint returns the full context plus a `context_truncated` flag. OpenAI-compatible callers continue to use `llm_call_audits` unchanged. (BUKU-A scope expansion on #2509.)
2441

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ git rebase --signoff origin/main
3232

3333
A DCO check runs automatically on every PR opened in the `getaxonflow` org. **PRs with any unsigned commit will be blocked from merging until the missing sign-offs are added.** No exceptions, including for maintainers.
3434

35+
## No partner/customer names in community source
36+
37+
Partner-driven features are named for the **capability** (e.g. `Indonesia`, `KTP`, `OJK`), never for the partner. Partner-specific artifacts (policy bundles, eval configs, partner runbooks) live **gated or internal** (`ee/`, `technical-docs/`, `docs/protected/`) — never in community source. A CI denylist (`.github/partner-name-denylist.txt`, enforced by the Partner Name Denylist workflow and as a fail-closed gate in the community sync) blocks any denylisted name from appearing in synced paths (`platform/`, `migrations/`, `config/seed-data/`, `docs/`, `examples/`, `infra/`) or public docs.
38+
3539
## Table of Contents
3640

3741
- [Quick Start](#quick-start)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8.5.0
1+
8.5.1

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ services:
8787
DEPLOYMENT_MODE: ${DEPLOYMENT_MODE:-community}
8888
AXONFLOW_INTEGRATIONS: ${AXONFLOW_INTEGRATIONS:-}
8989
AXONFLOW_LICENSE_KEY: ${AXONFLOW_LICENSE_KEY:-}
90-
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-8.5.0}"
90+
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-8.5.1}"
9191

9292
# Anonymous platform startup telemetry — inherit the operator's
9393
# opt-out lever. CI / dev shells should export AXONFLOW_TELEMETRY=off
@@ -261,7 +261,7 @@ services:
261261
PORT: 8081
262262
DEPLOYMENT_MODE: ${DEPLOYMENT_MODE:-community}
263263
AXONFLOW_LICENSE_KEY: ${AXONFLOW_LICENSE_KEY:-}
264-
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-8.5.0}"
264+
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-8.5.1}"
265265

266266
# Anonymous platform startup telemetry — inherit the operator's
267267
# opt-out lever. See agent service above for the full rationale.

docs/ARCHITECTURE.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,97 @@ response = await axonflow.execute_query(
157157

158158
---
159159

160+
## The Five Runtime Modes
161+
162+
AxonFlow is a **policy plane** for AI execution: at the point where an agent, model, or workflow is about to do something consequential, it **decides, enforces, redacts, and records** that action against your policies. There are five ways to wire that in. They differ only in *who calls AxonFlow* and *where AxonFlow sits relative to the traffic* — the governed-call lifecycle (decide → allow/deny/redact → audit, fail-closed) is identical across all five.
163+
164+
The split that makes this work is **PEP / PDP**: AxonFlow is the **Policy Decision Point** (it returns a verdict), and the integration is the **Policy Enforcement Point** (it acts on the verdict).
165+
166+
| Mode | Who calls AxonFlow | Traffic path | Endpoint(s) | When to use |
167+
|---|---|---|---|---|
168+
| **Decision Mode** | Your infra **gateway** | Client → gateway → target (verdict checked inline) | `POST /api/v1/decide` | Gateway-level enforcement with **no app-code changes** |
169+
| **Gateway** | Your **app code** (SDK) | App → LLM (direct) | `POST /api/policy/pre-check`, `POST /api/audit/llm-call` | Adding governance to an existing app/framework, least invasive |
170+
| **Proxy** | Your **app code** (one call) | App → AxonFlow → LLM | `POST /api/request` | New apps wanting AxonFlow to own routing + the LLM call |
171+
| **MAP** (Multi-Agent Planning) | Your **app code** | App → AxonFlow plans + executes | Orchestrator planning API | Decomposing a request into a governed multi-step plan |
172+
| **WCP** (Workflow Control Plane) | Your **external orchestrator** | Orchestrator → AxonFlow gates each step | `workflow_control/` step gate + complete | Step-level gates beside LangGraph / n8n / Temporal |
173+
174+
> The public, user-facing version of this model — with a per-integration coverage matrix — lives at [docs.getaxonflow.com/docs/architecture/governance-coverage](https://docs.getaxonflow.com/docs/architecture/governance-coverage). This section is the engineering source that page derives from.
175+
176+
### Decision Mode — gateway-level governance, no app changes
177+
178+
Your infrastructure gateway (LLM gateway, MCP gateway, agent router) asks AxonFlow for a verdict on each request and enforces it locally. AxonFlow is **never on the traffic path** — it is consulted for decisions only. This is the lowest-touch way to govern many apps at once: application code is unchanged; the gateway does the enforcing.
179+
180+
```mermaid
181+
sequenceDiagram
182+
participant C as Client
183+
participant GW as Infra gateway (PEP)
184+
participant AX as AxonFlow (PDP)
185+
participant T as Target (LLM / tool / agent)
186+
C->>GW: request
187+
GW->>AX: POST /api/v1/decide
188+
alt deny / needs_approval
189+
AX-->>GW: deny
190+
GW-->>C: blocked (reason)
191+
else allow
192+
AX-->>GW: allow (+ obligations)
193+
GW->>T: forward
194+
T-->>GW: response
195+
GW-->>C: response (obligations applied)
196+
end
197+
GW->>AX: audit (decision_id · trace_id)
198+
```
199+
200+
**Endpoint:** `POST /api/v1/decide` (`stage` = llm / tool / agent). Reference PEP adapters ship for **LLM**, **MCP** (`tools/call`), and **agent** gateways. **Code:** `platform/agent/decision_handler.go`. **See:** [ADR-056 — Decision Mode](../technical-docs/architecture-decisions/ADR-056-decision-mode.md).
201+
202+
### MAP — Multi-Agent Planning
203+
204+
AxonFlow decomposes a natural-language request into a multi-step plan, then executes the steps with a policy decision **at each step**, with replay/resume and optional approval gates.
205+
206+
```mermaid
207+
sequenceDiagram
208+
participant App
209+
participant AX as AxonFlow (planner)
210+
participant S as Step executor
211+
App->>AX: request (multi-agent-plan)
212+
AX-->>App: plan (steps)
213+
loop each step
214+
AX->>AX: policy decision for step
215+
AX->>S: execute (governed)
216+
S-->>AX: result
217+
end
218+
AX-->>App: workflow result + per-step audit
219+
```
220+
221+
**Code:** `platform/orchestrator/planning_engine.go` (plan generation), with per-step decisions recorded to the decision chain (`platform/agent/decision_chain.go`).
222+
223+
### WCP — Workflow Control Plane
224+
225+
Your external orchestrator (LangGraph, n8n, Temporal, Airflow) keeps running the workflow; AxonFlow adds a **gate before each step** and a **completion record after**, plus checkpoints and approvals — without replacing the orchestration engine.
226+
227+
```mermaid
228+
sequenceDiagram
229+
participant O as External orchestrator (PEP)
230+
participant AX as AxonFlow
231+
participant N as Step / node
232+
O->>AX: gate(step)
233+
alt block / needs_approval
234+
AX-->>O: block
235+
else allow
236+
AX-->>O: allow
237+
O->>N: run step
238+
N-->>O: result
239+
O->>AX: complete(step) — state + audit
240+
end
241+
```
242+
243+
**Code:** `platform/orchestrator/workflow_control/` (step gates + completion + checkpoints). **See:** [ADR-028 — Workflow Control Plane](../technical-docs/architecture-decisions/ADR-028-workflow-control-plane.md).
244+
245+
### Gateway & Proxy
246+
247+
**Gateway Mode** and **Proxy Mode** are covered in detail above ([Gateway Mode](#gateway-mode-recommended-for-existing-stacks), [Proxy Mode](#proxy-mode-full-control)); their combined request/audit sequence is in [Execution Model → Policies Before and After Steps](#policies-before-and-after-steps). The LLM-architecture rationale for the Gateway-default / optional-full-Proxy split is in [ADR-004 — LLM Architecture](../technical-docs/architecture-decisions/ADR-004-llm-architecture-governance.md).
248+
249+
---
250+
160251
## Control Plane vs Orchestration
161252

162253
| Aspect | Orchestration (LangChain) | Control Plane (AxonFlow) |

docs/api/agent-api.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4106,12 +4106,13 @@ components:
41064106
decision span, so a SIEM can correlate the decision with upstream
41074107
logs (e.g. by session_id). Intended for infrastructure-gateway
41084108
audit headers such as `X-AI-Agent`, `X-Session-ID`,
4109-
`X-Leader-Identity`, and the `x-bukuwarung-*` family.
4109+
`X-Leader-Identity`, and a tenant-scoped header family.
41104110
41114111
Only keys matching the server's allowlist
4112-
(`AXONFLOW_DECISION_CONTEXT_ALLOWLIST`; default
4113-
`x-ai-agent,x-session-id,x-leader-identity,x-bukuwarung-*`, where a
4114-
trailing `*` is a prefix match) are persisted; all other keys are
4112+
(`AXONFLOW_DECISION_CONTEXT_ALLOWLIST`; the default covers common
4113+
agent / session / leader identity headers plus a tenant-scoped
4114+
header family, where a trailing `*` is a prefix match) are
4115+
persisted; all other keys are
41154116
silently dropped. Surviving keys are canonicalized to
41164117
lower_snake_case (`X-AI-Agent` → `x_ai_agent`) so joins are
41174118
deterministic regardless of header casing. Non-string values are

examples/mcp-decision-mode/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ AXONFLOW_AGENT_URL=http://localhost:8080
77

88
# Basic-auth credentials for the agent. In enterprise mode CLIENT_SECRET is
99
# the license key, and CLIENT_ID / TENANT_ID are your AxonFlow org identifier.
10-
# Replace these with the values your AxonFlow deployment issued for BukuWarung.
10+
# Replace these with the values your AxonFlow deployment issued for your organization.
1111
AXONFLOW_CLIENT_ID=mcp-decision-mode-demo
1212
AXONFLOW_CLIENT_SECRET=replace-with-license-key
1313
AXONFLOW_TENANT_ID=mcp-decision-mode-demo

examples/mcp-decision-mode/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ through the PEP, which asks the PDP first.
4545

4646
## Audit-layer mapping
4747

48-
BukuWarung's Risk Committee defines a four-layer audit framework. This example
48+
A design partner's Risk Committee defines a four-layer audit framework. This example
4949
produces the first two layers and is the join point for the other two:
5050

5151
| Layer | What it is | Produced by |
5252
|-------|-----------|-------------|
5353
| **Layer 1** | MCP server logging (`timestamp, session_id, leader_email, tool_name, parameters_hash, response_record_count, duration_ms`) | `audit_log.py``audit_log.jsonl` |
5454
| **Layer 2** | `X-AI-Agent` / `X-Session-ID` / `X-Leader-Identity` propagation | `mcp_server.py` forwards them in the `decide()` `context` map; values land in the Layer 1 row (`ai_agent`, `session_id`, `leader_email`) |
55-
| **Layer 3** | Decision record → SIEM, correlated to BigQuery Cloud Audit Logs by `session_id` | AxonFlow decision record (`decision_id` + `trace_id`) exported via OpenTelemetry; correlate on `session_id` (BukuWarung GCP-side config) |
55+
| **Layer 3** | Decision record → SIEM, correlated to BigQuery Cloud Audit Logs by `session_id` | AxonFlow decision record (`decision_id` + `trace_id`) exported via OpenTelemetry; correlate on `session_id` (the design partner's GCP-side config) |
5656
| **Layer 4** | Anomaly alerts (volume, off-hours, bulk retrieval) | SIEM's job once Layer 1 + Layer 3 feeds are joined |
5757

5858
## Quickstart

examples/mcp-decision-mode/audit_log.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
Each governed MCP tool invocation writes exactly one JSON line to an append
44
-only ``audit_log.jsonl``. This is the PEP-side audit record that satisfies
5-
**Layer 1** of BukuWarung's four-layer audit framework (MCP server logging).
5+
**Layer 1** of a design partner's four-layer audit framework (MCP server logging).
66
It is produced locally by the MCP server, independent of whether AxonFlow
77
persists the forwarded context, so the example works end-to-end today.
88
@@ -15,8 +15,8 @@
1515
(session_id, leader_email, ai_agent)
1616
Layer 3 BigQuery Cloud Audit Logs → SIEM AxonFlow decision record
1717
(decision_id) lands in the SIEM and
18-
correlates by session_id (BukuWarung
19-
GCP-side config)
18+
correlates by session_id (the design
19+
partner's GCP-side config)
2020
Layer 4 Anomaly alerts ............... SIEM's job once both feeds are in
2121
2222
Layer 1 schema (the Risk Committee's named field set) — every row carries,

0 commit comments

Comments
 (0)