Skip to content

Live probe: which installation-token permissions the deployment-apply OIDC purpose really needs #26

Open

Description

@immakermatty

Context

Broker 0.13.0 (#25) adds GitHub Actions OIDC purposes. The deployment-apply purpose mints a one-repository installation token for a rollout runner's live Permit evidence and its Permit consumption push. Its permission set is configuration and follows the runner contract:

administration: read, checks: read, contents: write, issues: read, members: read, organization_administration: read, pull_requests: read (+ metadata: read).

Three of these rest on assumptions that GitHub's documentation does not settle for installation tokens.

What a live probe must answer

  1. Organization plan. The evidence reads GET /orgs/{org} and needs its plan field. GitHub documents that "to see information about an organization's GitHub plan, GitHub Apps need the Organization plan permission" (organization_plan: read), not Organization administration. Does an installation token with organization_plan: read (and without organization_administration) receive plan? If so, the purpose should use the narrower permission.
  2. Ruleset bypass actors. The evidence reads GET /repos/{owner}/{repo}/rulesets/{id} with bypass_actors. GitHub documents that bypass_actors "is only returned if the user making the API request has write access to the ruleset". Does an installation token with administration: read receive it, or is administration: write needed (which the broker should not grant to a CI runner without a separate decision)?
  3. Issue events of a pull request. GET /repos/{owner}/{repo}/issues/{n}/events is listed under both the Issues and the Pull requests permission. Does pull_requests: read alone suffice for a pull request, so issues: read can be dropped?

How

On the reference Organization's installation, before its first apply: mint tokens limited to one repository with each candidate set, call the three endpoints, record the status codes and whether the field is present, without creating or changing anything. Record the outcome in the README like #23, and change only the purpose's permissions in the deployment policy; no broker release is needed.

Activity

  1. immakermatty commented on Oct 17, 2026

    @immakermatty
    ContributorAuthor

    Decision (2026-10-17, Organization Admin): deployment-apply uses organization_plan: read instead of organization_administration: read. Question 1 is decided on GitHub's documentation, not yet proven by a probe. The App therefore requests Organization Plan: read and does not request Organization Administration.

    The current state:

    • Reference Organization. It accepted Organization Plan: read on 2026-10-17 between 21:49:00Z and 21:50:17Z. Its broker has run v0.13.0 with this deployment-apply set since 21:55:15Z:

      • administration, checks, issues, members, organization_plan and pull_requests at read;
      • contents at write;
      • two tokens per run.

      Between the acceptance and that deploy, every Workspace token of that broker was 502. This is the exact-installation-gate window that the README's "Deploying OIDC purposes" warns about.

    • The Organization that publishes Machines releases. It has not accepted the permission. Its broker serves only machines-release (contents: read), which does not need it. That Organization's own deployment-apply waits for its acceptance.

    • No broker change. The release stays v0.13.0; only the deployment policies changed.

    Still open, for the first runner apply or the probe described above:

    1. Does GET /orgs/{org} return plan to a one-repository token with organization_plan: read and without organization_administration?
    2. Does administration: read receive bypass_actors?
    3. Does pull_requests: read alone suffice for the issue events, so that issues: read can be dropped?

    Keep this issue open until those answers are recorded.

  2. immakermatty commented on Oct 22, 2026

    @immakermatty
    ContributorAuthor

    Live answer to question 2 (2026-10-22), from the first provider-enforced apply through a rollout runner.

    A Deployment Repo on GitHub Team, with an active no-bypass ruleset on refs/heads/machines-permits-v1 (creation,
    deletion, non_fast_forward) and a default-branch ruleset, ran its first lane apply in runner mode on Machines
    v0.12.188. The run was admitted, joined the tailnet, and its fresh readback matched the reviewed Plan. Permit issuance
    then refused the evidence before any mutation:

    Diagnostics: No active no-bypass GitHub ruleset protects refs/heads/machines-permits-v1 against creation, deletion and non-fast-forward updates
    Machines operate failed: permit-evidence-refused: Permit issuance refused the merged pull request
    

    The same ruleset read with an Organization Owner's token (GET /repos/{owner}/{repo}/rulesets/{id}) returns
    bypass_actors: [] and current_user_can_bypass: "never". permit/github-evidence.mjs (isExactPermitRefRuleset,
    and the same for isExactDeploymentRuleset) requires bypass_actors to be present and empty. So with the
    deployment-apply token (administration: read) the ruleset arrives without bypass_actors, as GitHub documents for
    a requester without write access to the ruleset. The answer to question 2 is therefore no: administration: read
    does not receive bypass_actors. This is inferred from the refusal plus the Owner-token read; the token itself was not
    inspected.

    Consequence: no provider-enforced Record can get a Permit through a runner until either the evidence reads the bypass
    actors with a credential that may see them, or the purpose gets administration: write. The latter is the separate
    decision this issue already names, since such a token could also change the rulesets the evidence relies on. Nothing
    was created, consumed or held: the lease was released and no Permit was published.

    🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions