Policy Engine
The policy engine evaluates the active policy version deterministically and returns ALLOW, BLOCK or REQUIRE_APPROVAL. The same request context and policy version always produce the same outcome — "AXIS does not guess with AI."
Policy shape
{
"schema_version": "1.0",
"policy_version": "prod_main@1.0.0",
"defaults": {
"read": "ALLOW",
"write": "BLOCK",
"ddl": "REQUIRE_APPROVAL"
},
"write_rules": [
{
"id": "rule-1",
"action": "REQUIRE_APPROVAL",
"match": { "operation": "UPDATE", "condition": "batch_scope" },
"approver_group": "db-ops-review",
"reason_code": "approval_required_batch"
}
]
}
Defaults: reads default ALLOW, writes default BLOCK, DDL defaults REQUIRE_APPROVAL. Accepted action values: ALLOW, BLOCK, REQUIRE_APPROVAL (the alias APPROVAL_REQUIRED is accepted in policy deserialization). Rules carry IDs, match conditions, optional approver_group and reason_code.
Manifest-authoritative startup
At startup the manifest (policies/policy_manifest.json) is authoritative. It points to the active policy file, declares the expected policy version, and stores the raw policy file SHA-256. Startup sequence:
Open and verify audit WAL continuity.
Load and validate the policy manifest.
Resolve and hash the active policy file (SHA-256 over raw bytes).
Parse and validate the policy model (schema + semantic validation).
Run the deterministic activation dry-run corpus.
Write policy lifecycle audit events.
Start accepting traffic.
Failure anywhere in this chain prevents healthy startup — there is no permissive fallback policy. The SHA-256 check detects wrong files, unexpected local changes and version mismatches; it is not attestation, signing, consensus or KMS-backed distribution.
Policy lifecycle
Lifecycle endpoints
| Endpoint | Behavior | Auth |
|---|---|---|
POST /policy/validate | Read-only structural + semantic validation (rule IDs unique, action values valid, typed fields deserialize). Emits warnings for dangerous production wildcard ALLOW, too-permissive defaults, missing DELETE-without-WHERE / batch guards, shadowed rules. Never reloads, executes SQL, creates approvals or writes audit evidence. | none |
POST /policy/diff | Added/removed/modified rules by rule ID (fallback: normalized JSON fingerprint); flags action changes and removal of protections as higher risk. | none |
POST /policy/dry-run | Returns decision, reason, SQL fingerprint, classification details, matched rule trace, would_execute: false, audit_written: false. Unsupported/unparsable SQL fails safe with a blocking preview; prepared EXECUTE dry-run fails safe as unresolved. | none |
POST /policy/candidates | Stores a new immutable candidate version with optional operator note. | operator token |
POST /policy/activate | Requires candidate status candidate, expected_hash match, stored file hash match against manifest, re-validation. On failure AXIS keeps the previous active policy. | operator token |
POST /policy/rollback | Target must exist and not be rejected; validates before activation; current active becomes archived. | operator token |
GET /policy/status / GET /policy/versions | Read-only status: loaded, version, path, rule count, operator_auth_enabled; version list with statuses. | none |
Operator token: AXIS_OPERATOR_TOKEN, sent as X-AXIS-Operator-Token or Authorization: Bearer <token>. If unconfigured, local development stays unblocked and /policy/status reports operator_auth_enabled: false.
Semantic warnings surfaced by validation
- Dangerous production wildcard
ALLOWrules - Too-permissive default write / DDL
- Unknown SQL shape fallback that is not a hard block
- Missing DELETE-without-WHERE, batch UPDATE, batch DELETE or DDL guards
- Duplicate match conditions; shadowed rules
- Broad migration-oriented allow rules; unknown environment labels
Runtime state
ActivePolicy= policy model + metadata (policy_id,policy_version,policy_sha256, manifest path, policy path, load time); metadata is carried into decisions, audit records, health and policy status responses.- Controlled reload is internal-only in v0.9 and disabled by default (
AXIS_ENABLE_POLICY_RELOAD=false); there is no HTTP reload endpoint. - Invalid policy JSON prevents healthy startup; invalid candidates are rejected; activation keeps the previous active policy on failure paths.
- Old policy versions are never deleted during activation — rollback stays possible against archived versions.
"AXIS is only as good as its policy." Policy quality is a deployment responsibility: review candidates, use diff and dry-run, avoid unsafe default allows, and audit policy changes.
Related: SQL Classification · Approval Workflow · Configuration