OAP Decisions vs Harness Enforcement
Purpose
Open Agent Passport (OAP) separates two concerns:
- Policy decision: the verifier answers whether the requested action is authorized by the passport and policy.
- Harness enforcement: the runtime integration decides what to do with that decision in the local product experience.
This split keeps the OAP standard deterministic and auditable while still allowing teams to roll out guardrails in report-only mode before they make checks blocking.
Architectural Decision
OAP decisions remain binary:
{
"decision_id": "8f38c4e7-9f2d-4d60-8619-fcc8b2c8f23a",
"policy_id": "system.command.execute.v1",
"agent_id": "ap_example",
"allow": false,
"reasons": [
{
"code": "oap.command_not_allowed",
"message": "Command is not in the passport allowlist"
}
],
"signature": "ed25519:...",
"kid": "oap:registry:key-2025-01"
}
The verifier should not return warn as a third authorization state. A deny is still a deny: the action did not satisfy the policy.
The harness may be configured to treat that deny as:
| Harness mode | OAP decision | Runtime behavior | Intended use |
|---|---|---|---|
enforce
|
allow: false
|
Block the action | Default for production and protected workflows |
warn / report-only
|
allow: false
|
Show a warning and let the action continue | Policy tuning, audit rollout, developer adoption |
fail-open-on-api-error
|
Infrastructure error, not a policy deny | Let the action continue with an explicit fail-open warning | Narrow availability exception only |
warn mode must not rewrite the decision to allow: true. It records the original signed denial and separately records that the operator configured a non-blocking rollout. A pre-action verifier can derive what the harness is expected to do, but it cannot prove the tool actually ran unless the harness reports the runtime result after the action.
Why This Belongs Outside the Core OAP Decision
OAP is the policy decision point. Claude Code, Cursor, LangChain, CrewAI, OpenClaw, GitHub Actions, MCP gateways, and custom applications are policy enforcement points.
Keeping enforcement disposition out of allow has four benefits:
- Backward compatibility: existing OAP consumers already understand
allow: true | false. - Audit integrity: the signed decision says what the policy concluded, not what a local UI chose to do during rollout.
- Security clarity: production systems can fail closed on any unknown state instead of interpreting a new tri-state incorrectly.
- Framework flexibility: every harness has different UX mechanics for blocking, warning, annotating, requesting approval, or continuing.
This is the same broad separation used by mature authorization systems: the authorization service returns a decision, while the relying party or policy enforcement point performs the local action.
Reconciling Dashboard Deny With Harness Warn
A dashboard or audit view should show both layers when both are available:
| Field | Meaning |
|---|---|
policy_decision
|
The signed OAP decision: allow or deny
|
decision_id
|
Stable join key for audit, logs, and runtime telemetry |
enforcement_mode
|
Harness configuration: enforce, warn, or another explicit local mode
|
expected_runtime_disposition
|
Pre-action expectation derived from the decision and reported harness mode: allowed, blocked, continued_after_warning, continued_after_fail_open, not_reported
|
runtime_disposition
|
Optional post-action report of what actually happened locally: allowed, blocked, continued_after_warning, continued_after_fail_open, not_reported
|
Example:
{
"decision_id": "8f38c4e7-9f2d-4d60-8619-fcc8b2c8f23a",
"policy_decision": "deny",
"enforcement_mode": "warn",
"expected_runtime_disposition": "continued_after_warning",
"runtime_disposition": "not_reported",
"enforced_by": "cursor",
"reported_at": "2026-09-05T14:30:00Z"
}
In the UI, this should not be presented as a contradiction. Recommended labels:
- Policy decision: Denied
- Expected runtime disposition: Warned and continued
- Runtime disposition: Not reported
- Operator mode: Report-only
For analytics, count this as a policy denial in risk and posture metrics. Count it separately as non-blocking in rollout and adoption metrics.
If a harness does not report runtime disposition back to APort, the dashboard should only claim the signed policy decision. It should not infer whether the tool actually ran.
Implementer Requirements
Harnesses and SDKs that support report-only rollout should follow these rules:
- Default to
enforceunless the operator explicitly chooseswarnorreport-only. - Never let the agent choose or override enforcement mode through tool-call input. Hosted integrations should send enforcement mode as trusted request metadata, not inside policy
context. - Preserve the signed OAP decision exactly as returned by the verifier.
- Display a clear warning when a deny decision is allowed to continue.
- Redact secrets and sanitize untrusted tool names, paths, reasons, and policy messages before printing to terminals or CI logs.
- Join any runtime telemetry to the OAP decision with
decision_id. - Treat infrastructure fail-open separately from policy warn mode. A real policy deny is not an API outage.
Current Implementation Status
Current APort guardrail harnesses support local enforce and warn modes, with enforce as the default. The hosted verifier can accept harness-reported runtime metadata on the verification request so hosted decisions can be stored and displayed with both layers:
- Signed OAP decision: binary
allow. - Harness-reported pre-action metadata:
enforcement_mode,enforced_by, andexpected_runtime_disposition. - Optional post-action telemetry:
runtime_dispositionwhen a harness reports what actually happened.
Pure local/offline passport verification can only appear in the hosted dashboard if the operator opts into telemetry. Otherwise it remains a local audit-log concern.
GitHub Repository Guard
For GitHub Actions, report-only means the APort Action can produce a deny decision or high-risk evidence while the workflow still exits successfully. Blocking requires a trusted enforcement path, usually:
mode: hosted- A required branch-protection check
- Explicit protected-path or push enforcement where needed
The job summary should still make deny decisions prominent. A passing report-only workflow should say the repository needs review when the signed decision is allow: false; it should not present the result as clean.
Future Standard Extension
If OAP later standardizes enforcement telemetry, the safer path is a separate optional object or event, not changing allow to a tri-state:
{
"type": "oap.enforcement_result",
"decision_id": "8f38c4e7-9f2d-4d60-8619-fcc8b2c8f23a",
"enforcement_mode": "warn",
"expected_runtime_disposition": "continued_after_warning",
"runtime_disposition": "continued_after_warning",
"enforced_by": "github-actions",
"created_at": "2026-09-05T14:30:00Z"
}
High-assurance environments may require this event to be signed by the harness, CI provider, or gateway. That can be added without changing the core OAP decision schema.