Skip to main content

Audit Logger

Use audit-logger to add an audit marker to policy results. The evaluator always allows the request. It does not create storage, set retention, make records immutable, or guarantee control-plane delivery.

Outcome

When the entry runs, it contributes this policy result:

FieldValue
policy_kindaudit-logger
phasepreflight
verdictallow
reason_codeaudit_logger.logged
detailsnot included

An allow-only result does not replace the last decision cause. A clean chain ends with verdict allow and cause code ok.

Prerequisites

  • Add audit-logger to the applicable global or route policy chain.
  • Use a connected gateway when the control plane must receive runtime decision events.
  • Configure Trail, event retention, exports, and integrity controls through their owning platform workflows. They are not configured by this policy.

Configuration

Use an empty policy block to configure the active behavior:

pack:
name: audit-logger-example
version: 1.0.0
enabled: true
policies:
chain:
- audit-logger
policy:
audit-logger: {}

The chain entry starts the policy. A policy.audit-logger block without a chain entry is configuration only.

Supported block

audit-logger supports only the empty object form:

  • audit-logger: {}

Configure retention, immutability, HIPAA evidence, and storage guarantees external to this policy block. Use Trail or the owning event or export workflow.

Chain-sequence implications

Policy evaluation stops at the first block or escalate in a stage. A subsequent audit-logger does not add its marker.

Add it before blocking controls when the marker must occur on allowed and blocked input decisions:

policies:
chain:
- audit-logger
- prompt-injection
- pii-detector

This sequence changes marker visibility. It does not change event storage. A standalone gateway can evaluate the marker without a control-plane event.

Test the marker

Create tests/audit-marker.json:

{
"name": "records-audit-marker",
"input": {
"messages": [
{
"role": "user",
"content": "Summarize the release notes."
}
]
},
"expected": {
"verdict": "allow",
"reason_code": "ok"
}
}

Then run:

verdictan policy lint --file policy-config.yaml
verdictan policy test --json

In JSON output, verify:

  • The last verdict is allow.
  • The last reason_code is ok.
  • details.policy_results[] contains audit_logger.logged.

Do not set the golden expectation to audit_logger.logged. It is a nested cause, not the last allow cause.

Roll out and verify

  1. Lint and test the specified pack version.

  2. Run it locally or deploy it to the specified gateway.

  3. Send one allowed request and one request blocked by a subsequent policy.

  4. Query recent runtime decisions with:

    verdictan events tail --since 10m --json
  5. Verify the applied configuration version and the nested audit-logger result where the marker was specified.

  6. Use Trail or the applicable operator workflow to verify retention, integrity, and evidence export.

An unconnected runtime cannot deliver an event to the control plane. A missing event does not prove that the evaluator did not run. Examine gateway connectivity and the local decision path.

Troubleshooting

SymptomLikely causeWhat to examine
No audit-logger resultThe entry is missing from the effective chain, is skipped by targeting/conditions, or follows an earlier stop verdict.Examine the active route chain and move the marker earlier if necessary.
Golden test specifies audit_logger.logged but fails with okThe fixture is asserting the last decision cause.Specify allow/ok, then examine nested policy_results.
No event is available after a connected requestDelivery, query window, gateway identity, or event sink can be incorrect.Make sure that the gateway is connected. Query the correct organization and time window. Correlate by request ID.
Trail does not show each runtime requestTrail and runtime Events are different evidence surfaces.Use runtime Events for request-policy outcomes and Trail for control-plane audit chronology.

Next steps