Use this GitHub Action to verify a proposed AI-agent action against an existing
signed Agent Mandate before a workflow continues. It is deliberately
fail-closed: anything other than a complete, cardinality-matched set of
allow receipts fails the step.
Store the caller's Agent Mandate API key as AGENT_MANDATE_API_KEY and the
complete signed mandate envelope as AGENT_MANDATE_SIGNED_JSON. Then add a
workflow step like this:
- name: Verify proposed agent actions
uses: API-Disk-Integrations/agent-mandate-action@v1
with:
actions-file: mandate/proposed-actions.json
env:
AGENT_MANDATE_API_KEY: ${{ secrets.AGENT_MANDATE_API_KEY }}
AGENT_MANDATE_SIGNED_JSON: ${{ secrets.AGENT_MANDATE_SIGNED_JSON }}For the strongest supply-chain guarantee, replace v1 with the immutable
40-character commit SHA from the release you reviewed.
The Action sends one validated request to
POST https://agentmandate-api.com/v1/verify. A caller supplies an existing
signed mandate plus one proposed action or an ordered batch of at most 500.
The Action preserves each exact server decision: allow, deny, or
requires_approval.
The CI step succeeds only when response cardinality exactly matches the
request and every receipt is allow. Any denial, approval requirement,
malformed or incomplete response, timeout, network failure, API error, or
unexpected receipt count fails closed. The Action does not issue or revoke a
mandate, approve an action, execute an action, move money, change data, call
billing, write to GitHub, or retry a request.
The accepted endpoint contract makes agent optional syntactically while
explicitly instructing callers to supply it to prevent replay by a different
agent. This security-focused Action profile therefore requires agent on
every proposed action. It also refuses wildcard proposals because the
contract defines wildcards as grants, not concrete actions. These are local
client restrictions; they do not claim different API semantics.
Map two user-controlled GitHub secrets into environment variables:
AGENT_MANDATE_API_KEY: the caller's Agent Mandate API key.AGENT_MANDATE_SIGNED_JSON: the complete JSON object returned byPOST /v1/mandates, including its signature.
Neither value is declared as an Action input. Attempts to pass api-key or
mandate-json as plain inputs fail closed. The API key, detached signature,
and any supplied approvalToken are registered with the runner's masking
protocol before the request. The implementation never logs the signed
mandate, API key, approval token, proposal, raw response, server message, or
receipt identity fields.
The candidate validates the documented {mandate, signature} envelope and
v1:<hex> detached-signature format locally. It never attempts local
cryptographic verification; the accepted /v1/verify service performs that
account-bound check.
Supply exactly one proposal source:
action-json: one documented action object; oractions-file: a repository-relative regular JSON file containing an ordered array of 1–500 documented action objects.
An action requires agent and action; it may contain resource,
amountMinor, currency, priorSpendMinor, priorCount, approvalToken,
and at. amountMinor is a nonnegative integer and requires currency.
Explicit at values make the evaluation instant reproducible. Unknown action
fields, final symlinks, path escapes, invalid JSON, oversized inputs, and
ambiguous sources are rejected before the API request.
The signed mandate is limited to 256 KiB, inline action JSON to 64 KiB, batch files and responses to 1 MiB. The Action makes exactly one request with a 30-second timeout and no retry. One verification request can still consume a metered unit per proposed action under the product contract.
This example excludes pull requests and pull_request_target so secrets are
not exposed to untrusted code. Replace each placeholder with the immutable
40-character commit SHA you reviewed.
name: Agent Mandate verification
on:
workflow_dispatch:
push:
branches: [main]
permissions:
contents: read
jobs:
authorize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<REVIEWED_FULL_40_CHARACTER_COMMIT_SHA>
with:
persist-credentials: false
- name: Verify proposed actions only
uses: API-Disk-Integrations/agent-mandate-verify@<REVIEWED_FULL_40_CHARACTER_COMMIT_SHA>
with:
actions-file: mandate/proposed-actions.json
env:
AGENT_MANDATE_API_KEY: ${{ secrets.AGENT_MANDATE_API_KEY }}
AGENT_MANDATE_SIGNED_JSON: ${{ secrets.AGENT_MANDATE_SIGNED_JSON }}Never expose these secrets to forked or otherwise untrusted pull-request code.
Do not add pull_request_target, a plain secret input, a writable GitHub token,
an unpinned third-party Action, or a later execution step that ignores this
step's failure.
The Action sets all-allowed, receipt-count, and report-path. It writes a
new file at .agent-mandate/verification-report.json; a pre-existing report
directory is rejected to prevent symlink or hard-link overwrite attacks.
The report contains only per-receipt order, exact decision, violation count, validated SHA-256 evaluation digest when present, aggregate decision counts, and the exact receipt count. It excludes mandate ID, principal, agent, proposed action, resource, amount, approval token, matched grant, violation codes/details, raw mandate, API key, and raw response. The step summary contains only aggregate counts and the relative report path.
npm ci --offline --ignore-scripts --no-audit --no-fund
npm run check
npm audit --offline --omit=dev
npm pack --dry-run --jsonAll tests use deterministic local fetch mocks and sentinel noncredentials. The bundle has no runtime install, does not use the GitHub API, and makes no production request during build or test.
- Immutable releases use semantic tags such as
v1.0.0. - The
v1major alias may advance only to a reviewed compatible release. - Pin the immutable commit SHA when your workflow requires strict provenance.
- Open a GitHub issue for defects. Do not include API keys, signed mandates, approval tokens, request bodies, receipts, or customer data.
The Action calls the production Agent Mandate verification API, but a listing, install, download, or test run is not evidence of customer activation or revenue.