Owner Authorization
Owner authorization is the provenance channel for an approval. ASF50 distinguishes three:
- Chat authorization — a chat-side message from the owner. Useful for
PAID_MODEL_DISPATCH_APPROVAL(viaowner-cli). Not sufficient for merge/tag/release/promotion. - GitHub review approval — a
gh pr review --approve(or the GitHub UI equivalent) at the exact head. Captured viascripts/goal-runner/ingest_github_review.py. - Signed ticket — an OpenSSH-signed authorization payload that the orchestrator verifies with
ssh-keygen -Y verifyagainst the canonicalallowed_signersfile.
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:
- Owner opens (or reviews) a PR.
- Owner submits an approving review in the GitHub UI (or
gh pr review --approve). scripts/goal-runner/ingest-github-review.ps1ingests the review and materializes anowner_gatesrow withscope: 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_APPROVALdoes 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:
| Dimension | What it answers |
|---|---|
| Authorization | Did a human approve this step? |
| Capability | Can this actor perform the step at all? |
| Gate scope | What 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.