Repository navigation
ci: all CI on our pf-ci pool with the canonical authz guard (no hosted fallback) - #146
Merged
Merged
Conversation
Every job that had its own runs-on in ci.yml, docs.yml and native-feed.yml now
uses the plain pool labels ["self-hosted","pf-ci","pf-ci-x64"]: no expression,
no hosted fallback, pull requests included (they were forced to ubuntu-24.04
before), dependabot included. The native-feed release matrix runs its Linux
x64 leg on the x64 pool labels and its Linux arm64 leg on
["self-hosted","pf-ci","pf-ci-arm64"]; only macos-14 stays on GitHub.
docs.yml deploy (Pages environment) is unchanged.
Each of the three workflows gets a first job `authz` that fails red (exit 1,
never a skip) unless the triggering actor is dependabot[bot] or a repository
collaborator with admin, maintain or write permission, checked with one call to
GET /repos/{repo}/collaborators/{actor}/permission using the default
GITHUB_TOKEN (no new secret). Fork pull requests fail red without a lookup; an
API error or an empty answer fails red. Every other job needs authz, and ci.yml
`ready` fails unless authz succeeded.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
docker, database-e2e, contract and distribution use `!cancelled() && ...` in their `if:`, which replaces the implicit success() over `needs`. On a push where authz failed they would still have run on the pool. Add `needs.authz.result == 'success' &&` to those four conditions so that no job runs unless authz passed (owner rulings B / #800 / #801). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…orkflow tests The workflow tests pinned the old policy (pull requests forced onto hosted runners, no secrets, no needs). Update them to the owner rulings: every job uses the plain pool labels without a hosted fallback, authz is needed by every job and gates release/ready and the runtime jobs, authz may use only secrets.GITHUB_TOKEN with contents: read, and its bot allowlist is the exact dependabot[bot] and pineforge-app[bot]. Each changed pin quotes its old assertion and gains a new rejected case; no test is deleted or loosened. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Replace the API based authz of the three workflows with the canonical job (ci-labels.md, #808): on the pf-ci-x64 pool, pull_request_target fails red, a pull request whose head repository is not this repository fails red, every other event passes. Actors (members, collaborators, dependabot[bot], our release App) are admitted or refused by the dispatcher, not in YAML, and the only secret-free job text is the canonical one. Every other job still needs authz; ci.yml has no paths filter on pull_request and holds the required check, docs.yml and native-feed.yml keep their own authz as a guard. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ailed authz The workflow tests pinned the earlier API based authz. They now pin the canonical same-repository job from ci-labels.md: exact keys, pool labels, single named step, exact env and script, no secrets or permissions anywhere except the Pages deployment, and ci.yml/docs.yml without a pull_request filter (the required authz must run on every PR; native-feed keeps its paths as a guard). Each rewritten pin quotes the removed one and gets new rejected cases. release/ready is the only always() job: following ci-labels.md rule 3a its first step now refuses (exit 1) unless authz succeeded, before any checkout, and its checkout and repo-code steps also require a successful authz. The four runtime jobs carry needs.authz.result == 'success' in their own if. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… #830)
A superseded run that concurrency cancelled must not leave the aggregate job
queued for a runner and block the new head's run. `if: ${{ !cancelled() }}`
still runs release/ready (red) when authz failed; its first step still refuses
unless authz succeeded, before any checkout. Pins that asserted always() now
assert the new condition (old line quoted), and a new pin forbids always() in
the three PR-tier workflows with a rejected case. The canon authz block was
re-compared with ci-labels.md ff778494 and is unchanged in all three files.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ier workflow The previous commit message claimed a rejected case for the new pin; only ready was covered, by another assertion. Add the case for all three workflows. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…tep on authz Rule 3a / ci-policy-check R5: docker, database-e2e, contract and distribution start with the canonical refusal step and every checkout, local-action and run step requires needs.authz.result == 'success'; release/ready's gate step too. Pins extended to the five jobs with rejected cases. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…runner per leg
authz is the canonical job copied as is (ALLOWED_BOTS dependabot[bot] and
pineforge-app[bot]) in ci.yml, docs.yml and native-feed.yml. release/ready is
back to if: always() (a cancelled run must not skip the required aggregate).
native-feed's release matrix gives every leg its own runner (x64 list, arm64
list, macos-14) and runs-on: ${{ matrix.runner }}. Pins for always() flipped;
the authz and matrix pins follow in the next commit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…x runner pins (vp110a, before canon delta)
…e pull_request arm) Only the pull_request arm changes (ci.yml, docs.yml, native-feed.yml); ALLOWED_BOTS stays dependabot[bot] pineforge-app[bot]. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ssion lookup) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s included Claude read of the delta: the helper that dropped comment lines weakened the copy-as-is pin. Back to full-text equality, now line by line so newlines (shell syntax) are not collapsed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
luisleo526
force-pushed
the
data-vp/ci-pool-canon-tests
branch
from
October 20, 2026 09:07
442d24f to
b21be27
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
All CI of this repo runs on our own machines (pf-ci pool), pull requests included, and every workflow starts with the canonical
authzjob from the org CI-label file (ci-labels.md, #808).runs-onnow uses the plain pool labels ([self-hosted, pf-ci, pf-ci-x64]): no expression, no hosted fallback. Before, pull requests were forced ontoubuntu-24.04and only pushes used the pool.ci.yml(changes,test,docker,database-e2e,contract,distribution,ready),docs.yml(build),native-feed.yml(asan-ubsan,tsan, release matrix Linux x64 leg).ci.yml,docs.yml,native-feed.yml, copied from the canon d7ba0680.pull_request_targetand any event not in the canon's list fail red; a pull request from another repository or from a fork fails red;push,workflow_dispatch,schedule,merge_group,release,workflow_callandrepository_dispatchpass.workflow_runpasses only when the triggering run's head repository is this repository and its triggering actor is an allowlisted bot or has admin/maintain/write on this repository, read with onegh api repos/<repo>/collaborators/<actor>/permissioncall; a failed lookup refuses.permissions: {}— no workflow permission is granted, andGH_TOKEN: ${{ github.token }}serves only that read-only lookup.ALLOWED_BOTS: "dependabot[bot] pineforge-app[bot]"(same-repository pull requests only). Apull_requestfrom this repository passes whenauthor_associationis OWNER/MEMBER/COLLABORATOR or the author is an allowlisted bot; otherwise it passes only with admin/maintain/write read from GitHub — a member whose org membership is private shows as CONTRIBUTOR, and a failed lookup refuses. Every other jobneeds: authz.release/readyfails unlessauthzsucceeded. The four runtime jobs (docker,database-e2e,contract,distribution) also requireneeds.authz.result == 'success'in theirif:(the!cancelled()they use replaces the implicit success check, so without this they ran on a push even if authz failed).needs); they now pin the new ones, and each changed pin quotes its old assertion and has new rejected cases.Native feed runs of this PR
native-feed.ymlis paths-filtered and not a required check (the requiredauthzis inci.yml, which has no filter). Its runs on this PR were CANCELLED by@pineforge-ci-dispatcher[bot](raw annotation: "The run was canceled by @pineforge-ci-dispatcher[bot]."): theRelease (ubuntu-24.04-arm)job asks forpf-ci-arm64, a class that is not live yet, and the whole run (the x64 legs and the macOS leg too) was cancelled. laneboss confirms this is a known dispatcher defect: a job that targets a class that is not live cancels the whole run. Native feed runs are cancelled by the dispatcher untilpf-ci-arm64is live (about 21:00 tonight, laneboss); re-run after. After that a refused-class job stays queued and a re-run keeps all legs.native-feed.ymlis intentionally not changed for this (owner CI-ARM = C).Barrier and visible check
all_external_contributors, read by L6 on the org and on this repo): a fork run waits inaction_requiredbefore any job starts. Second layer: laneboss's dispatcher identity gate (thepineforge-ci-dispatcherapp), which also admits actors (members, collaborators,dependabot[bot], the release Apppineforge-app[bot]). Its state read 2026-10-20 16:50 Taipei: it postspf-ci gateon this PR's head442d24ff(failure, summarylabel_mismatch, 08:44:12Z) — the label gate, not the identity gate, refuses right now.authzis the visible red check for a member's own fork and forpull_request_target.ci.ymlhas nopaths:/branches:filter onpull_request(ci.yml line 6), so the requiredauthzcheck runs on every PR.docs.ymlhas none either.native-feed.ymlkeeps itspaths:filters (lines 6 and 8); its ownauthzis a guard there, not the required check.needs.authz.result == 'success': they can be skipped only whenauthzhas already failed, and the red requiredauthzthen blocks the merge anyway (canon item 3); without the condition they would run on the pool after a failedauthzon a push.always()/!cancelled()that needauthz):release/readyinci.yml(line 268,if: always()) now starts with a dedicated refusal step (line 276:if: needs.authz.result != 'success',run: exit 1) before any checkout; its first gate step also exits 1 on a failed authz; its checkout (line 327),setup-pythonand the evidence aggregation step requireneeds.authz.result == 'success'. The four runtime jobsdocker(line 104),database-e2e(128),contract(187),distribution(210) use!cancelled()and are covered byneeds.authz.result == 'success'in their ownif:(they run no step when authz failed).docs.ymlandnative-feed.ymlhave noalways()or!cancelled()job.pineforge-4pass/pineforge-data.authzis the frozen org canonci-labels.mdd7ba0680 (sha256d7ba0680766031a4416f5d24da6ec4d392784ab0dba474d422c51128ed2c28c0) copied as is inci.yml,docs.ymlandnative-feed.yml; the only per-repository edit isALLOWED_BOTS: "dependabot[bot] pineforge-app[bot]"(owner #801 and CI-RELBOT = A). Thepull_requestarm also asks GitHub for the author's permission, for members shown as CONTRIBUTOR. Proof (canon list): item 1/2 = the policy pins intests/test_pr_tier_workflows.pyandtests/test_release_adapter.py(authz copy-as-is pin line by line with comments, structure and runner pins with rejected cases, the authz script executed with a fakeghfor the decision cases withfail(), allowlist and permission-list mutations) andci-policy-check.py(tool sha b3adc5cc) run aspython3 -I ci-policy-check.py --canon ci-labels.md --not-required docker,database-e2e,contract,distribution <repo>: it leaves only R6 fordocs.ymldeployin these three workflows (raw:".github/workflows/docs.yml": job="deploy" step=- R6: runs-on must resolve to canonical labels or a macOS hosted label; no fallback) plus the release/pineforge-release/release-report workflows, which VP-111 (merged first) covers; the four runtime jobs are--not-required(R7) because the required checks areauthzandrelease/ready.if:conditions that can skip them (docs-only PRs skip the four runtime jobs; the runtime jobs also carry!cancelled() && needs.authz.result == 'success'). They are not required checks; the required checks areauthzand the aggregaterelease/ready(if: always(), refuse-first), which fails unless each of them is success, or skipped for the declared docs-only reason after authz success. A decision test pins that a skipped job without the docs-only reason makes the aggregate red.pull_requestGitHub runs the workflow file from the PR merge ref, so a fork PR could change this file; only the approval policy and the dispatcher stop it, not YAML.ci-policy-check R6, pending pf-ci-release (tool sha256 b3adc5cc7340f0071ba78a5029e7db0e4702709789cb614a59b52e18b2277f56)
ci-policy-check.pyon this branch reports no R1-R5 finding. The only findings left are R6 ("runs-on must resolve to canonical labels or a macOS hosted label; no fallback") for jobs that stay hosted on purpose until laneboss'spf-ci-releaseclass is live; they use release credentials, App tokens, OIDC or environments and are NOT touched here:docs.yml:deploy(Pages environment,deploy-pages)pineforge-release.yml:reconcilerelease-report.yml:reportrelease.yml:claim-name,manual-pr,prepare,build,github-release,publish,verify(
native-feed.ymlreleaseis resolved here: every matrix leg has its ownrunner,macos-14is the one hosted macOS leg.)always()is used by the aggregate jobrelease/ready(not!cancelled()): a cancelled run skips a!cancelled()job and GitHub counts a skipped required check as success;readyrefuses first whenauthzdid not succeed.Pending / follow-ups (not in this PR)
native-feed.ymlrelease matrix:ubuntu-24.04-armruns on[self-hosted, pf-ci, pf-ci-arm64](owner choice CI-ARM = C, never GitHub). The label is listed inci-labels.md(laneboss 5cb38079); the runner goes live at about 21:00 tonight (laneboss) and the leg queues until then.macos-14stays on GitHub (no Mac hardware).pf-ci-x64until laneboss posts "pf-ci-crj live"; then the non-Docker jobs move topf-ci-crj.pf-ci-releaseis live:docs.ymlbuild(uploads the Pages artifact thatdeploypublishes) moves there;release.ymlbuild,github-release,verifyand the jobs with secrets/environments (claim-name,manual-pr,prepare,publish,report,release-report.yml,pineforge-release.yml) are not touched here.docs.ymldeploy(Pages environment) stays onubuntu-latestfor now.ci.ymldistributionbuilds evidence (the release rebuilds the published distribution inrelease.ymlbuild), so it stays on the pool.🤖 Generated with Claude Code