Skip to main content

AxonFlow v8.0.0 Operator Notes

This is the detailed companion to the v8.0.0 Release Notes. It covers enterprise and source-fork-affecting changes: full refuse-to-boot guard wiring with worker prefixes, the customer-portal API consumer breaking change, removed pool-scope helpers, SECURITY DEFINER auth-bootstrap helpers, and tenant-delete admin-pool routing detail.

If you are using only the SDKs, plugins, or HTTP API, the main release notes are sufficient. Use this page when you operate self-hosted, In-VPC, customer-portal, Marketplace, or source-fork deployments.

Operator-visible changes

1. Refuse-to-boot guard — full worker prefix matrix

The v8.0.0 agent, orchestrator, and customer-portal binaries refuse to boot when AXONFLOW_DB_USE_APP_ROLE=true (the default — also active when the env is unset) and the relevant cross-org worker has no admin DSN configured. Silent fallback to the request-traffic pool would defeat FORCE RLS — cross-org workers would silently return zero rows or undercount.

The binary exits with a FATAL log line naming both env vars. The bracketed prefix identifies which worker triggered the guard:

PrefixWorkerTriggered when
[Marketplace]AWS Marketplace meteringmetering is enabled
[NodeMonitor]Multi-node enforcementENABLE_NODE_MONITOR=true
[CSAAS-SWEEP]Community-SaaS sweepcommunity-saas mode enabled
[CSAAS-RECOVERY]Community-SaaS recovery handlercommunity-saas mode enabled
[CSAAS-DELETE]Tenant-delete cross-org handler (GDPR right-to-erasure)/api/v1/tenant/{id}/delete-* endpoints exposed
[customer-portal]customer-portal admin handlerscustomer-portal admin handlers in scope

Sample log:

[Marketplace] FATAL: AXONFLOW_DB_PLATFORM_ADMIN_URL is required when AXONFLOW_DB_USE_APP_ROLE=true (silent fallback to a non-BYPASSRLS pool would defeat FORCE RLS — cross-org metering/sweep/recovery/monitoring would silently return 0 rows or undercount). Set AXONFLOW_DB_PLATFORM_ADMIN_URL to a DSN authenticating as axonflow_platform_admin, or set AXONFLOW_DB_USE_APP_ROLE=false to opt out of the v8.0.0 default and run under the legacy v8.x posture.

Remediation:

  • Recommended: populate AXONFLOW_DB_PLATFORM_ADMIN_URL with a DSN authenticating as axonflow_platform_admin (mirror of AXONFLOW_DB_APP_ROLE_URL — different role, same host/db). See the v8.0.0 Self-Hosted Upgrade Guide step 4.5 for the canonical wiring.
  • Phased-rollout: set AXONFLOW_DB_USE_APP_ROLE=false explicitly on the agent + orchestrator + customer-portal task definitions to opt out of the v8.0.0 default and run under the legacy v8.x posture. The guard is a no-op under that flag.

2. middleware.RLSMiddleware family removed (self-hosted source forks)

Four pool-scope GUC functions in ee/platform/customer-portal/middleware/rls.goRLSMiddleware, SetRLSContextForSession, ResetRLSContext, WithRLS — were removed in v8.0.0. They issued SELECT set_org_id($1) against *sql.DB (the connection pool), which is unsafe under FORCE RLS because the GUC landed on one connection while the next handler statement might execute on a different one.

Migration: replace direct calls to the removed functions with api.withRequestOrgScope(r, h.db, fn) — a request-scoped helper that opens a single *sql.Conn from the pool, sets app.current_org_id on that connection, runs the handler closure, and releases the connection.

Diagnostic helpers in middleware/rls.go (GetCurrentOrgID, VerifyRLSActive, GetRLSStats, RLSHealthCheck) are retained for read-only introspection use.

3. Customer-portal handlers wrap every FORCE-RLS table read/write

In the bundled customer-portal codebase, nodes.go, export.go, connectors.go, sso.go, and auth/saml/service.go now wrap reads and writes of the FORCE-RLS-protected tables (organizations, tenants, community_saas_registrations, sso_*, connector_configs) in withRequestOrgScope / withOrgScope. SAML INSERTs populate org_id to satisfy the NOT NULL constraint that the relevant identity migration added.

The MCP cache-miss path was also closed: the cached MCP-session struct now carries the authenticated *Client plus AuthKind end-to-end, and the MCP auth middleware stamps four context keys (TenantID / OrgID / ClientID / AuthKind) onto r.Context(). Downstream MCP tools/call traffic now sees the authenticated identity end-to-end.

This means stock v8.0.0 customer-portal handlers are RLS-correct out of the box. Self-hosted forks with customized handlers must follow the source-fork audit recipe in the v8.0.0 Enterprise Migration Guide.

4. SECURITY DEFINER auth-lookup helpers for in-VPC enterprise

The in-VPC enterprise auth path (validateClientCredentialsDBvalidateViaAPIKeys) queries api_keys, customers, and pricing_tiers before app.current_org_id is established — a chicken-and-egg pattern (the agent needs to look up the API key to know the org_id, but RLS on those tables requires the org_id to already be set).

v8.0.0 ships SECURITY DEFINER helper functions — auth_lookup_api_key() and auth_touch_api_key() — that run with elevated privileges for the narrow auth-bootstrap window only, then drop back to app-role traffic for the rest of the request. api_keys and customers are FORCE-RLS-protected for all non-auth traffic.

No operator action required for stock v8.0.0; the migration runs automatically on first boot. Custom auth shims in source forks should follow the same pattern (create a SECURITY DEFINER function in your own migration if your customization needs pre-org-context auth lookups).

5. Cross-org workers route through axonflow_platform_admin

The community-saas sweep, node monitor, recovery handler, and tenant-delete (GDPR right-to-erasure) handler all open a separate *sql.DB authenticated as axonflow_platform_admin using the OpenPlatformAdminConnection() helper.

Each worker emits a startup log declaring whether it's running in admin-DSN mode or falling back to single-role mode, so operators can verify their cross-org workers are correctly wired without grepping handler code.

Specific call-out for the tenant-delete handler: under FORCE RLS, a cross-org DELETE running outside an org-scoped transaction filters silently to zero rows (DELETE evaluates USING, not WITH CHECK). The pre-v8.0.0 silent-fallback behavior had this failure mode in production — the handler returned HTTP 200 to the caller and wrote a GDPR Article-17 deletion log row asserting deletion completed, while the registration + usage_events rows remained on disk. Routing through the admin pool closes that.

Self-hosted forks with their own cross-org workers must adopt the same pattern; under the app role those workers silently return zero rows and emit no error.

6. Customer-portal API consumer breaking change: custom_roles / role_assignments JSON tag rename

Affects: direct HTTP API consumers of the customer-portal role APIs. In v8+ the current session-authenticated routes are /api/v1/roles, /api/v1/roles/{id}, /api/v1/users/{email}/roles, and /api/v1/users/{email}/roles/{roleId}. Older internal clients and notes may refer to the pre-v8 customer-portal role paths. Not affected: the bundled customer-portal UI, which consumes its own backend and updates atomically.

The custom_roles.tenant_id and role_assignments.tenant_id columns were renamed to org_id. The JSON tag on the API response payloads renamed correspondingly:

  • Pre-v8.0.0: {"tenant_id": "acme-corp", "role_name": "...", ...}
  • v8.0.0+: {"org_id": "acme-corp", "role_name": "...", ...}

If you wrote a tool that consumes the customer-portal HTTP API for roles or role-assignments directly (your own admin scripts, an SSO provisioning integration, a compliance audit pipeline that polls the role list), update your consumer to read org_id instead of tenant_id. Same semantic meaning, renamed JSON field.

If you write to these endpoints, the request payload accepts both tenant_id and org_id for one compatibility window; the new canonical field is org_id.

To find consumers in your repos:

grep -rnE '(customer-portal/(roles|role-assignments)|/api/v1/(roles|users/.*/roles))' --include='*.py' --include='*.js' --include='*.ts' --include='*.go' .

For each match, check the response handler for tenant_id references in the role / role-assignment payload — those need to become org_id.

7. Tenant-delete admin-pool routing (community-saas operator only)

The tenant-delete (GDPR right-to-erasure) handler in community-saas mode now routes through the admin pool. This closes the silent-deletion-claim failure mode described in section 5 above.

Operationally, this means the customer-saas operator stack must populate AXONFLOW_DB_PLATFORM_ADMIN_URL when /api/v1/tenant/{id}/delete-* endpoints are exposed. The [CSAAS-DELETE] refuse-to-boot guard catches misconfiguration.

For the verification recipe (assert "row STILL EXISTS after 'successful' response" not "500 / 42501" as the failure shape), see the v8.0.0 Enterprise Migration Guide § Source-fork audit recipe.

Additional v8.0.0 hardening

  • Agent agent_heartbeats UPSERT under FORCE RLS — the agent's sendHeartbeat path wraps the UPSERT in an org-scoped transaction so the heartbeat write succeeds against the axonflow_app_role connection without falling back to the admin pool. The boot-time regression guard SUITE_EXPECT_BOOT_RLS_EVIDENCE is live on CI catching any regression of this wrap.
  • AST audit walker for write-path coverage — a build-time guard preventing customized writes from bypassing the three wrap patterns is in place; CI fails on any unwrapped INSERT / UPDATE / DELETE into an RLS-gated table. The source-fork audit recipe in the enterprise migration guide is CI-enforced on the stock codebase — operators maintaining forks inherit the same guard when they pick up the v8.0.0 codebase and customize on top.

See also

Enterprise Rollout Checklist

Use this page as part of the protected enterprise operating model: