Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor/skills/devops-why-my-pr-not/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Walk down this checklist in order. Stop at the first match per dimension; print
| # | Symptom (from PR JSON / checks JSON) | Diagnosis | Cite |
|---|---|---|---|
| C1 | PR `isDraft == true` AND a workflow has `pull_request: types: [opened, synchronize, reopened]` (default) | Draft PRs do not fire `pull_request` events for `ready_for_review` excluded triggers. Mark the PR as ready or push a new commit. | GitHub default `pull_request` event semantics |
| C2 | Workflow runs are present but jobs gated on `needs.label-gate.outputs.authorised == 'true'` are SKIPPED, AND `verified` label is missing | The `label-gate` denied because `verified` is not applied. Ask any active member of `@tetherto/qvac-internal-dev` / `-merge` / `-release` to apply it. | `docs/ci/LABELS.md Β§ verified`, `label-gate/README.md Β§ Trust model` |
| C2 | Workflow runs are present but jobs gated on `needs.label-gate.outputs.authorised == 'true'` are SKIPPED, AND `verified` label is missing | The `label-gate` denied because `verified` is not applied. Ask any active member of `@tetherto/qvac-internal-dev` / `-merge` / `-release` or `@tetherto/qvac-collabora` to apply it. | `docs/ci/LABELS.md Β§ verified`, `label-gate/README.md Β§ Trust model` |
| C3 | Same SKIPPED jobs, `verified` is present, but the latest `synchronize` event was a push by a non-trusted actor | `label-gate` strips `verified` on every `synchronize` from a non-trusted actor. A trusted actor must re-apply after reviewing the new commits. | `LABELS.md Β§ verified β€” Behaviour on synchronize`, `label-gate/README.md Β§ Strip policy` |
| C4 | `verified` label was *applied* by a non-trusted actor (look at the labeled-event applier in the timeline) and was immediately stripped | `label-gate` strips on apply by non-trusted actor (avoids a misleading "verified" social signal). | `LABELS.md Β§ verified β€” Behaviour on apply by non-trusted actor`, `label-gate/README.md Β§ Strip policy` |
| C5 | PR is from a fork (`headRepositoryOwner.login != tetherto`) AND only secret-bearing jobs are missing | `pull_request` from a fork gets a read-only `GITHUB_TOKEN` and no secrets. The `verified`-gated jobs intentionally won't run until a trusted actor verifies. | `LABELS.md Β§ verified` |
Expand Down
3 changes: 2 additions & 1 deletion .github/actions/label-gate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ which will fall through to the standard `not currently applied` deny.
| Name | Required | Default | Description |
| -------------- | :------: | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `label` | no | `verified` | Label name required for PR-event authorisation. |
| `teams` | no | `qvac-internal-dev`, `qvac-internal-merge`, `qvac-internal-release` | Comma- and/or newline-separated team slugs (within the repository owner's org). Empty allowed if `users` is non-empty. |
| `teams` | no | `qvac-internal-dev`, `qvac-internal-merge`, `qvac-internal-release`, `qvac-collabora` | Comma- and/or newline-separated team slugs (within the repository owner's org). Empty allowed if `users` is non-empty. |
| `users` | no | `""` | Comma- and/or newline-separated user logins. Authorised regardless of team membership. Login comparison is case-insensitive. |
| `github-token` | **yes** | β€” | PAT with `read:org` (team membership lookups) and write access to PR labels (for stripping the label on non-trusted apply OR non-trusted synchronize). |

Expand Down Expand Up @@ -90,6 +90,7 @@ jobs:
qvac-internal-dev
qvac-internal-merge
qvac-internal-release
qvac-collabora
users: |
release-bot
github-token: ${{ secrets.PAT_TOKEN }}
Expand Down
1 change: 1 addition & 0 deletions .github/actions/label-gate/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ inputs:
qvac-internal-dev
qvac-internal-merge
qvac-internal-release
qvac-collabora
users:
description: >
Comma- and/or newline-separated list of GitHub user logins that are
Expand Down
4 changes: 2 additions & 2 deletions docs/ci/LABELS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This is the label that gates every secret-bearing PR job in the repo.
| | |
|---|---|
| **Purpose** | Authorise the `label-gate` composite action so that secret-bearing jobs (sanity-checks, prebuilds, publish, deploy, etc.) are allowed to run on a PR. |
| **Who can apply** | Active member of `@tetherto/qvac-internal-dev`, `@tetherto/qvac-internal-merge`, or `@tetherto/qvac-internal-release`. See [TEAMS.md](TEAMS.md). |
| **Who can apply** | Active member of `@tetherto/qvac-internal-dev`, `@tetherto/qvac-internal-merge`, `@tetherto/qvac-internal-release`, or `@tetherto/qvac-collabora`. See [TEAMS.md](TEAMS.md). |
| **What it gates** | Every secret-bearing workflow under `.github/workflows/` (108 workflows as of QVAC-18612). Specifically, every job downstream of `needs: [..., label-gate]` whose `if:` includes `needs.label-gate.outputs.authorised == 'true'`. |
| **Behaviour on `synchronize`** | When a non-trusted actor pushes new commits to a verified PR, `label-gate` strips the label automatically. A trusted actor must re-apply it after reviewing the new commits. This prevents authorisation from silently inheriting across content changes by an untrusted contributor. |
| **Behaviour on apply by non-trusted actor** | The label is stripped immediately and the gate denies. This avoids a "look, it's verified" social signal that doesn't actually mean the PR is authorised. |
Expand All @@ -22,7 +22,7 @@ This is the label that gates every secret-bearing PR job in the repo.

### When CI is blocked by `label-gate`

If your PR's secret-bearing jobs are skipping with a `label-gate.outputs.authorised != 'true'` condition, ask any member of the three teams above to apply `verified`. There is intentionally no self-service path β€” the whole point of the gate is that someone other than the PR author signs off.
If your PR's secret-bearing jobs are skipping with a `label-gate.outputs.authorised != 'true'` condition, ask any member of the trusted teams above to apply `verified`. There is intentionally no self-service path β€” the whole point of the gate is that someone other than the PR author signs off.

---

Expand Down
3 changes: 2 additions & 1 deletion docs/ci/TEAMS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GitHub Teams β€” CI access reference

The four teams that show up in this repo's CI configuration. This doc names them and what they're for; everything else (membership, permission tiers, internal escalation, on-call) lives off-repo.
The teams that show up in this repo's CI configuration. This doc names them and what they're for; everything else (membership, permission tiers, internal escalation, on-call) lives off-repo.

> **Membership and access** β€” managed in GitHub at <https://github.com/orgs/tetherto/teams>. This file does not enumerate members; the source of truth is GitHub.

Expand All @@ -14,6 +14,7 @@ The four teams that show up in this repo's CI configuration. This doc names them
| `@tetherto/qvac-internal-merge` | Internal reviewers / merge approvers (tier-1 reviewer slot). |
| `@tetherto/qvac-internal-release` | Release approvers β€” sign off on npm publishes and `release-*` branch operations. |
| `@tetherto/qvac-external` | External contributors. Open PRs from forks; do not authorise secret-bearing CI. |
| `@tetherto/qvac-collabora` | Collabora engineers contributing to QVAC. Trusted to apply the `verified` label and to push without deauthorising it. |

---

Expand Down
Loading