Skip to main content

Owner Authorization

Owner authorization is the provenance channel for an approval. ASF50 distinguishes three:

  1. Chat authorization — a chat-side message from the owner. Useful for PAID_MODEL_DISPATCH_APPROVAL (via owner-cli). Not sufficient for merge/tag/release/promotion.
  2. GitHub review approval — a gh pr review --approve (or the GitHub UI equivalent) at the exact head. Captured via scripts/goal-runner/ingest_github_review.py.
  3. Signed ticket — an OpenSSH-signed authorization payload that the orchestrator verifies with ssh-keygen -Y verify against the canonical allowed_signers file.

These three mechanisms are not interchangeable. Each scope (MERGE_APPROVAL, TAG_APPROVAL, RELEASE_APPROVAL, PHASE_00_RESUME_APPROVAL, PRODUCTION_PROMOTION, PAID_MODEL_DISPATCH_APPROVAL) accepts a specific subset. See Human Gates → Scopes for the matrix.

Chat authorization

Chat authorization is captured through scripts/goal-runner/goal-gate.ps1 -Action approve. It accepts only the PAID_MODEL_DISPATCH_APPROVAL scope. For all other scopes, the CLI rejects chat authorization with a fail-closed error.

GitHub review approval

The flow:

  1. Owner opens (or reviews) a PR.
  2. Owner submits an approving review in the GitHub UI (or gh pr review --approve).
  3. scripts/goal-runner/ingest-github-review.ps1 ingests the review and materializes an owner_gates row with scope: MERGE_APPROVAL, source: github-review-approval, approver: <GitHub login>, subject_sha: <PR head SHA>.

The orchestrator then re-runs. When it observes the gate at the exact head, it consumes the gate and proceeds.

Signed ticket

A signed ticket is an OpenSSH-signed JSON payload bound to a ticket_id, a gate_id, a goal_id, a subject_sha, a production_target, an issuer principal, a namespace, a payload_digest, and the allowed_signers file path. The owner signs the payload offline with ssh-keygen -Y sign; the orchestrator verifies with ssh-keygen -Y verify before consuming the gate.

Signed tickets are the canonical mechanism for PRODUCTION_PROMOTION. They are also accepted for MERGE_APPROVAL, TAG_APPROVAL, RELEASE_APPROVAL, and PHASE_00_RESUME_APPROVAL.

What authorization is NOT

  • It is not the ability to perform the operation. The orchestrator must still execute the operation; authorization is a precondition.
  • It is not retroactive. A gate issued after the operation already happened is invalid.
  • It is not generic. A MERGE_APPROVAL does not authorize a tag or a release.

Sources

The three provenance sources are described above: Chat authorization (captured via goal-gate.ps1 -Action approve -Source owner-cli), GitHub review approval (captured via ingest-github-review.ps1), and OpenSSH signed tickets (verified via signed_ticket_verifier.py). Each scope accepts a specific subset of these sources; see Human Gates → Scopes for the matrix.

Authorization, capability, gate scope

Three dimensions that are easy to confuse:

DimensionWhat it answers
AuthorizationDid a human approve this step?
CapabilityCan this actor perform the step at all?
Gate scopeWhat kind of step is being approved?

A Builder has the capability to stage files. A Builder does not have the authorization to merge to main. A MERGE_APPROVAL gate is the only thing that grants the merge authorization, and only when the gate's subject matches the current head.