Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# gitleaks configuration for axonflow-enterprise
# Issue #1541: prevent any future hardcoded Ed25519 signing keys

title = "AxonFlow Gitleaks Rules"

[extend]
useDefault = true

[[rules]]
id = "axonflow-ed25519-signing-key"
description = "Hardcoded Ed25519 private seed near a *_SIGNING_KEY env var assignment"
regex = '''(?i)(ENT|EVAL|ED25519|AXONFLOW_(ENT|EVAL))_SIGNING_KEY[[:space:]]*=[[:space:]]*["'][A-Za-z0-9+/]{42,44}={0,2}["']'''
tags = ["key", "ed25519", "private-key"]
keywords = ["SIGNING_KEY"]

# Allow the load_signing_keys() helper which legitimately mentions the env vars
# without ever assigning a hardcoded value.
[allowlist]
description = "Setup script load helpers + tests"
paths = [
'''.*_test\.go$''',
'''.*_test\.py$''',
'''.*_test\.ts$''',
'''.*\.md$''',
]
regexes = [
'''SIGNING_KEY[[:space:]]*=[[:space:]]*""''',
'''SIGNING_KEY=\$\{''',
'''SIGNING_KEY=\$\(''',
]
14 changes: 14 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Pre-commit hooks for axonflow-enterprise.
# Run `pre-commit install` once to enable.
# CI also runs these on every PR.
#
# Issue #1541: gitleaks rule prevents hardcoded Ed25519 signing keys.

repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.2
hooks:
- id: gitleaks
name: Detect hardcoded secrets
description: Scan for hardcoded keys, tokens, and Ed25519 signing seeds
args: ["--config=.gitleaks.toml"]
89 changes: 89 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,95 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [6.2.0] - 2026-04-09

### Community

#### Added — Governance profiles and per-category enforce

- **`AXONFLOW_PROFILE` env var** (`dev` | `default` | `strict` | `compliance`). Resolved at agent and orchestrator startup, applied to the policy engine, and logged on boot. A single env var picks the enforcement posture instead of tuning eight individual `*_ACTION` env vars. The matrix is documented in `docs/guides/governance-profiles.md`. Explicit category env vars (`PII_ACTION=block`, `SQLI_ACTION=warn`, etc.) continue to override the profile, so existing automation keeps working.

- **`AXONFLOW_ENFORCE` env var** for per-category opt-in enforcement. Accepts a comma-separated subset of `pii`, `sqli`, `sensitive_data`, `high_risk`, `dangerous_queries`, `dangerous_commands`, plus the sentinels `all` and `none`. Categories listed resolve to `block`; categories not listed resolve to `warn`. Unknown tokens are a fatal startup error so typos can never silently disable enforcement. Precedence (highest → lowest): explicit `*_ACTION` env vars > `AXONFLOW_ENFORCE` > `AXONFLOW_PROFILE` > built-in defaults.

- **Profile banner at startup.** The agent now logs the active profile and resolved per-category actions on boot, so operators can confirm what posture the process is running in without grepping the env. Example: `[Profile] agent active: dev — PII=log, SQLI=log, SensitiveData=log, HighRisk=log, DangerousQuery=warn, DangerousCommand=warn`.

#### Changed — Default detection actions relaxed

- **Breaking:** the default `PII_ACTION` is now `warn` (previously `redact`). SQLi and sensitive-data categories also default to `warn`. Compliance categories (HIPAA, GDPR, PCI, RBI, MAS FEAT) default to `log`. Only unambiguously dangerous patterns — reverse shells, `rm -rf /`, SSRF to `169.254.169.254`, `/etc/shadow`, credential files — block by default. Rationale: silent redaction breaks debugging mid-session and teaches evaluators that AxonFlow is "broken". The new posture surfaces the detection signal honestly without mutating the data flow. To restore the v6.1.0 behavior set `AXONFLOW_PROFILE=strict` or `PII_ACTION=redact`.

- **Migration 066** rewrites system-default policies in the database to match the new defaults: `sys_pii_*` policies move from `redact`/`block` to `warn`, SQLi and sensitive-data system policies from `block` to `warn`, compliance system policies (HIPAA / GDPR / PCI / RBI / MAS FEAT) from `block` or `redact` to `log`. Dangerous-command policies (migration 059) stay `block`. The migration is gated on `tenant_id IS NULL` so user-created and tenant-owned policies are untouched. The down migration restores the v6.1.0 strict defaults.

#### Fixed — `deploy-client.sh` JWT path silent failure

- **`scripts/multi-tenant/deploy-client.sh` no longer silently falls back to a hardcoded Secrets Manager path.** The "Path B" fallback was reading `axonflow/clients/travel/production/user-token` regardless of the client being deployed, swallowing AWS errors with `2>/dev/null || echo ""`, and silently passing an empty `USER_TOKEN` into the container — which the agent then rejected at runtime with a misleading "token signature is invalid" error. The variable `AXONFLOW_STACK_PREFIX_JWT` is now required; the script fails loudly if missing. The generated `USER_TOKEN` is validated to be a syntactically-valid JWT (three base64 segments separated by dots) before the container is started. All client environment files under `configs/environments/clients/` have been updated to declare the variable. A new runbook at `technical-docs/runbooks/JWT_SECRET_ROTATION.md` documents the underlying JWT secret rotation flow.

#### Fixed — Evaluation tier `MaxPendingApprovals` outlier

- **`EvaluationLimits.MaxPendingApprovals` corrected from 100 to 25** to match the rest of the evaluation tier caps (`MaxConcurrentExec`, `MaxSSEConnections`, `MaxVersionsPerPlan`). The previous value of 100 was an outlier that contradicted `TestTierBoundary_EvaluationLimitsValues` and inflated evaluation-tier capacity above what was documented and tested.

### Security

- **Ed25519 enterprise license signing key rotated.** The previous private seed was found embedded in `scripts/setup-e2e-testing.sh` (line 87), where it had been since the script was authored. Anyone with read access to the repo could mint valid Enterprise / Professional / Plus licenses for any `org_id`, bypassing tier gating in any deployment. As part of this release the key has been rotated, all active customer licenses re-signed under the new key, and the agent's embedded `enterprisePublicKey` byte array updated. The previous public key (first 8 bytes `9a b6 f6 b2`) is no longer accepted. A new internal-only runbook at `technical-docs/runbooks/ED25519_KEY_ROTATION.md` documents the rotation procedure for any future operator.

- **`scripts/setup-e2e-testing.sh` no longer hardcodes any signing keys.** The eval and dev-only enterprise keys are sourced from the environment (CI uses GitHub Actions secrets) or fetched at runtime from AWS Secrets Manager (`axonflow/license-signing/evaluation-private-key` and `axonflow/license-signing/dev-ent-private-key`). A separate dev-only enterprise keypair has been created so local E2E never touches the production signing key.

- **Pre-commit `gitleaks` rule** added at `.gitleaks.toml` and wired into `.pre-commit-config.yaml`. The rule blocks any commit that introduces a base64 Ed25519 seed near a `*_SIGNING_KEY` env var assignment. CI runs gitleaks on every PR.

- **Checkpoint telemetry retention bumped from 90 → 180 days.** Evaluation-to-production conversion windows run 2-4 months in observed data, so 90 days was cutting off the tail. 180 days still fits comfortably in DynamoDB free tier at current volume.

#### Fixed — Multi-tenant SaaS correctness and security

- **`X-Org-ID` now derived from the validated client license, not the deployment env var.** The agent's Single Entry Point proxy middleware (`platform/agent/proxy.go`) was forcibly overwriting the authenticated client's `org_id` with the deployment's `ORG_ID` environment variable on every request, preventing a single deployment from serving multiple organizations. Every tenant on a shared stack was being stamped with the same `org_id`, making true multi-tenant workflow scoping impossible. The middleware now forwards `X-Org-ID` from the cryptographically validated client license payload (`client.OrgID`) — matching the behavior of `apiAuthMiddleware` in `auth.go`, which was already correct. The Ed25519 signature on the client license guarantees the `org_id` claim cannot be forged, so trusting it is both safe and required for multi-tenant operation. Deployments with a single org per stack are unaffected; deployments serving multiple orgs now correctly scope workflows, policies, and audit data per-tenant.

- **Internal orchestrator forwarding path fixed.** `platform/agent/run.go` also had the same bug in the direct HTTP forwarding path that bypasses the Single Entry Point mux. It was checking whether the client had an `org_id` and then setting the header to `getDeploymentOrgID()` anyway. Now uses `client.OrgID` directly.

- **MCP check-input and check-output audit log OrgID.** `platform/agent/mcp_handler.go` was writing every MCP audit record with `OrgID: getDeploymentOrgID()` regardless of which client authenticated. Multi-tenant audit trails were structurally broken — all records from all tenants were attributed to the deployment. Both handlers now lift `orgID` into function-level scope alongside `tenantID`, populated from `client.OrgID` in enterprise auth, `X-Org-ID` header in internal-service auth, and `getDeploymentOrgID()` in community mode.

- **Removed `validateClient()` mock authentication fallback.** `platform/agent/run.go` had a `validateClient(clientID)` function that accepted any `client_id` from the request body and returned a fake "Demo Client" with the deployment's own `org_id`, no credential validation. All four MCP handlers (`/api/v1/mcp/query`, `/api/v1/mcp/execute`, `/api/v1/mcp/check-input`, `/api/v1/mcp/check-output`) called this as a fallback when Basic auth was missing. Effectively: in enterprise mode, any request without Basic auth but with a `client_id` field in the JSON body was silently authenticated as that client. Removed the function and all four call sites now reject unauthenticated requests with 401.

- **Orchestrator workflow tenant/org ownership checks.** `platform/orchestrator/workflow_control/service.go` — **nine** service methods now enforce tenant/org ownership before acting on a workflow: `GetWorkflow`, `StepGate`, `MarkStepCompleted`, `ApproveStep`, `RejectStep`, `ResumeWorkflow`, `CompleteWorkflow`, `FailWorkflow`, `AbortWorkflow`. Previously `GetWorkflow` (called from `GET /api/v1/workflows/{id}`) did no tenant/org filtering — any authenticated client that knew a workflow ID could fetch any workflow (classic IDOR). The same gap existed on every other workflow state transition: an attacker could approve, reject, resume, complete, fail, or abort any other tenant's workflow, or inject fake cost/token metrics into another tenant's audit trail by calling `MarkStepCompleted`. All matching HTTP handlers in `handlers.go` extract tenant/org from request headers (`X-Tenant-ID`, `X-Org-ID`) and pass them through. Callers in `run.go` (MAP confirm mode) and `unified_execution_handler.go` also updated. `ListWorkflows` was already filtering correctly.

- **Unified execution handler `checkTenantOwnership` hardened.** `platform/orchestrator/unified_execution_handler.go` previously had permissive fallbacks: requests without `X-Tenant-ID` were allowed through, and executions without a `tenant_id` were accessible to any caller. Both were cross-tenant data leak vectors. The check now:
- Requires **both** `X-Tenant-ID` and `X-Org-ID` on every request (401 if missing).
- Rejects executions that lack either `tenant_id` or `org_id` (404).
- Requires exact match on both fields (404 on any mismatch).
- All mismatch responses return 404 (not 403) to prevent cross-tenant existence leakage.

#### Added — Customer portal multi-tenant identity

- **`tenant_id` column on `user_sessions`** (migration 065). The customer portal previously aliased `tenantID := orgID` in `auth.go` with the comment *"organizations table doesn't have tenant_id column"*. That collapsed two concepts and prevented a single portal org from representing multiple tenants (prod, staging, dev). The new column lets a portal session track which tenant within an org the user is currently viewing.

- **`portal_default_tenant_id()` SQL helper** (migration 065). Resolves the default tenant for an org: prefers `tenant_id = org_id` (canonical default) and falls back to the oldest tenant in the `tenants` table, then to `org_id` itself for community deployments. Used at login time to populate the session.

- **Automatic default tenant backfill** for every existing organization (migration 065). Every org gets a canonical tenant row inserted into the `tenants` table if one doesn't already exist, so portal login can deterministically resolve a tenant without schema changes to customer data.

#### Changed — Customer portal auth and proxy

- **`AuthHandler.HandleLogin`** now resolves `defaultTenantID` via `portal_default_tenant_id()` at login time, inserts it into `user_sessions.tenant_id`, and returns both `org_id` and `tenant_id` in the login response. Legacy fallback kicks in if migration 065 hasn't been applied yet.

- **`AuthHandler.HandleCheckSession`** (GET /api/v1/auth/session) now reads and returns `tenant_id` alongside `org_id`.

- **`middleware/dev_auth.go`** stops joining `customers.tenant_id` and reads `user_sessions.tenant_id` directly. The previous `orgID + "_tenant"` fallback is replaced with a deterministic fallback to `org_id` for legacy sessions.

- **`api/orchestrator_proxy.go`** forwards `X-Tenant-ID` from `session.TenantID` (the currently-selected tenant within the org) and `X-Client-ID` from the tenant identifier — previously both collapsed to `session.OrgID`. `X-Org-ID` continues to carry `session.OrgID`. A warning log fires when `session.TenantID` is empty (legacy session, unexpected after migration 065).

- **`ORG_ID` environment variable role clarified.** Previously documented as "canonical org identity (single source of truth)", the env var is now understood as:
- **Stack-level deployment label** (used in logs, metrics, startup validation against the stack's own boot license)
- **Community mode fallback** (when no client license is present)
- **NOT a routing key** for per-request multi-tenant data scoping — that comes from the authenticated client license

#### Fixed — Deployment tooling

- **`deploy-cloudformation.sh` missing required `OrganizationID` parameter.** The script built the `aws cloudformation deploy --parameter-overrides` list without passing `OrganizationID`, so creating a new stack from a clean state failed with `Parameter 'OrganizationID' must have a value`. Existing stack updates worked because CloudFormation falls back to `UsePreviousValue` for parameters not passed explicitly. The script now reads `deployment.organization_id` from the environment yaml config, falling back to the environment name if not set, and passes it on every deploy. This unblocks creating fresh environments from `deploy-platform.yml`.

### Security

- **IDOR on `GET /api/v1/workflows/{id}` closed.** Before v6.2.0, any authenticated client could fetch any workflow by ID regardless of which tenant or org it belonged to. Combined with the `X-Org-ID` deployment-env-var override, this meant a compromised tenant could enumerate workflow IDs and read every other tenant's execution state. Both the header source fix and the service-layer ownership check are required to close the hole end-to-end.
- **No-auth fallback on MCP handlers closed.** Before v6.2.0, in enterprise mode, any request with a `client_id` field in the JSON body (but no Basic auth credentials) was silently authenticated as that client and attributed to the deployment's own org. Removed entirely.
- **Permissive cross-tenant fallback on unified execution endpoints closed.** Before v6.2.0, executions without a `tenant_id` were accessible to any caller, and requests without `X-Tenant-ID` were accepted. Both now rejected.

---

## [6.1.0] - 2026-04-06

### Community
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ services:
DEPLOYMENT_MODE: ${DEPLOYMENT_MODE:-community}
AXONFLOW_INTEGRATIONS: ${AXONFLOW_INTEGRATIONS:-}
AXONFLOW_LICENSE_KEY: ${AXONFLOW_LICENSE_KEY:-}
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-6.1.0}"
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-6.2.0}"

# Media governance (v4.5.0+) - set to "true" to enable in Community mode
MEDIA_GOVERNANCE_ENABLED: ${MEDIA_GOVERNANCE_ENABLED:-}
Expand Down Expand Up @@ -223,7 +223,7 @@ services:
PORT: 8081
DEPLOYMENT_MODE: ${DEPLOYMENT_MODE:-community}
AXONFLOW_LICENSE_KEY: ${AXONFLOW_LICENSE_KEY:-}
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-6.1.0}"
AXONFLOW_VERSION: "${AXONFLOW_VERSION:-6.2.0}"

# Media governance (v4.5.0+) - set to "true" to enable in Community mode
MEDIA_GOVERNANCE_ENABLED: ${MEDIA_GOVERNANCE_ENABLED:-}
Expand Down
3 changes: 2 additions & 1 deletion docs/COMPATIBILITY_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ This document maps platform versions to minimum SDK versions and the features ea

| Platform Version | Min SDK Version | Recommended SDK | Key Features Added |
|-----------------|----------------|-----------------|-------------------|
| v6.0.0 | v5.0.0 (Go/TS/Java), v6.0.0 (Python) | v5.0.0 / v6.0.0 | OAuth2 Basic auth required, legacy engine removed, agent single entry point, Go module v5 |
| v6.1.0 | v5.0.0 (Go/TS/Java), v6.0.0 (Python) | v5.1.0 / v6.1.0 | Mistral LLM provider, Cursor/Codex integration, GovernedTool adapter (TS/Go/Java), checkToolInput/checkToolOutput aliases |
| v6.0.0 | v5.0.0 (Go/TS/Java), v6.0.0 (Python) | v5.1.0 / v6.1.0 | OAuth2 Basic auth required, legacy engine removed, agent single entry point, Go module v5 |
| v5.0.0 | v4.0.0 | v4.1.0 | Removed `total_steps` from create workflow, MCP operation default `"execute"`, Go module v4 |
| v4.8.0 | v3.8.0 | v3.8.0 | Version discovery, capability registry, User-Agent headers |
| v4.7.0 | v3.7.0 | v3.7.0 | MCP check-input/check-output endpoints, circuit breaker pipeline |
Expand Down
2 changes: 1 addition & 1 deletion docs/RBI_FREE_AI_COMPLIANCE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# RBI FREE-AI Framework Compliance Guide

*Last updated: April 2026 | AxonFlow Platform v6.0.0 | SDKs: Python v6.0.0, Go v5.0.0, TypeScript v5.0.0, Java v5.0.0*
*Last updated: April 2026 | AxonFlow Platform v6.0.0 | SDKs: Python v6.1.0, Go v5.1.0, TypeScript v5.1.0, Java v5.1.0*

This guide covers AxonFlow's compliance features for the Reserve Bank of India (RBI) Framework for Responsible and Ethical Enablement of AI (FREE-AI) published in August 2025.

Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AxonFlow Documentation

**Last Updated: April 2026** | **Platform: v6.0.0** | **SDKs: Python v6.0.0, Go v5.0.0, TypeScript v5.0.0, Java v5.0.0**
**Last Updated: April 2026** | **Platform: v6.0.0** | **SDKs: Python v6.1.0, Go v5.1.0, TypeScript v5.1.0, Java v5.1.0**

Public documentation for AxonFlow - synced to the Community Edition repository.

Expand Down Expand Up @@ -31,7 +31,7 @@ Configuration and how-to guides for common tasks.

## SDK Documentation

AxonFlow provides official SDKs for Go, Python, Java, and TypeScript. SDK versions: Python v6.0.0, Go/TypeScript/Java v5.0.0.
AxonFlow provides official SDKs for Go, Python, Java, and TypeScript. SDK versions: Python v6.1.0, Go/TypeScript/Java v5.1.0.

| Document | Description |
|----------|-------------|
Expand Down
2 changes: 1 addition & 1 deletion docs/compliance/eu-ai-act.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# EU AI Act Compliance Guide

*Last updated: April 2026 | AxonFlow Platform v6.0.0 | SDKs: Python v6.0.0, Go v5.0.0, TypeScript v5.0.0, Java v5.0.0*
*Last updated: April 2026 | AxonFlow Platform v6.0.0 | SDKs: Python v6.1.0, Go v5.1.0, TypeScript v5.1.0, Java v5.1.0*

AxonFlow provides comprehensive support for EU AI Act compliance. This guide covers the key features and APIs available for organizations operating AI systems in the European Union.

Expand Down
2 changes: 1 addition & 1 deletion docs/compliance/rbi-free-ai.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# RBI FREE-AI Framework Compliance

*Last updated: April 2026 | AxonFlow Platform v6.0.0 | SDKs: Python v6.0.0, Go v5.0.0, TypeScript v5.0.0, Java v5.0.0*
*Last updated: April 2026 | AxonFlow Platform v6.0.0 | SDKs: Python v6.1.0, Go v5.1.0, TypeScript v5.1.0, Java v5.1.0*

AxonFlow provides comprehensive compliance support for the Reserve Bank of India's **Framework for Responsible and Ethical Enablement of AI (FREE-AI)** guidelines for Indian banking institutions.

Expand Down
Loading
Loading