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
3 changes: 2 additions & 1 deletion .github/workflows/enforce-pr-target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ jobs:
github.event.label.name == 'test-exception-approved' ||
github.event.label.name == 'suppression-approved' ||
github.event.label.name == 'generated-change-approved' ||
github.event.label.name == 'dependency-change-approved'))
github.event.label.name == 'dependency-change-approved' ||
github.event.label.name == 'attribution-approved'))
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
2 changes: 1 addition & 1 deletion structure/ops/docs-and-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ cannot supply a write-job PR number. If no unique local current-head candidate r
| `.github/workflows/deploy-docs.yml` | `push` to `main` touching `docs-site/**` or the workflow, or manual dispatch | Build and publish the Astro/Starlight docs site to GitHub Pages. This is the deploy path; the pull-request build gate is the `docs-site-build` job in `ci.yml`. |
| `.github/workflows/service-lifecycle.yml` | `pull_request` to `main`/`dev` and `push` to `main`/`preview`, both filtered on the service path set (`src/service.ts`, `src/cli.ts`, `src/cli/index.ts`, `src/lib/bun-runtime.ts`, `package.json`, `bun.lock`, the workflow), or manual dispatch | Service-lifecycle smoke on three platforms: Linux systemd, macOS launchd, and Windows Scheduled Tasks. Each installs, verifies, stops via `ocx stop`, and uninstalls. The path list is kept in sync with the `release.yml` service-gate regex. |
| `.github/workflows/catalog-async-contracts.yml` | `push` to `dev`/`main`/`preview` and any `pull_request`, both filtered on `src/**`, the diagnostic crate, the setup action, the workflow, `package.json` and `bun.lock`; or manual dispatch | Runs the Rust-owned Bun-module catalog contracts on Linux, macOS and Windows with synthetic homes and cleared child environments. Read-only (`contents: read`), no secrets, no release-eligibility effect. Pull-request runs share one concurrency group per PR and cancel superseded runs; push and manual runs each get their own group. |
| `.github/workflows/enforce-pr-target.yml` | `pull_request_target` (opened, reopened, edited, labeled, unlabeled, ready_for_review, synchronize) plus default-branch `status` events filtered to successful `CodeRabbit` statuses | The `enforce-target` gate: rejects pull requests whose head ancestry sits on the `main` tip while far behind `dev`, rejects empty or malformed descriptions, requires a GUI screenshot when the title/body mentions `gui` (immediately waivable with the maintainer-controlled `gui-screenshot-waived` label; legacy maintainer comments remain compatibility evidence on later PR events), keeps contributor PRs in draft until a four-box readiness checklist is complete, verifies the CI / latest-dev / Codex+CodeRabbit-findings claims (review threads plus current-head CodeRabbit review-body findings outside the diff range), and adds a `review-ready` status label at the ready moment. CodeRabbit status SHAs must resolve to exactly one open current-head PR before writes. Stacked child PRs targeting another open PR's head skip the wrong-base gate. |
| `.github/workflows/enforce-pr-target.yml` | `pull_request_target` (opened, reopened, edited, labeled, unlabeled, ready_for_review, synchronize) plus default-branch `status` events filtered to successful `CodeRabbit` statuses | The `enforce-target` gate: rejects pull requests whose head ancestry sits on the `main` tip while far behind `dev`, rejects empty or malformed descriptions, requires a GUI screenshot when the title/body mentions `gui` (immediately waivable with the maintainer-controlled `gui-screenshot-waived` label; legacy maintainer comments remain compatibility evidence on later PR events), keeps contributor PRs in draft until a four-box readiness checklist is complete, verifies the CI / latest-dev / Codex+CodeRabbit-findings claims (review threads plus current-head CodeRabbit review-body findings outside the diff range), and adds a `review-ready` status label at the ready moment. CodeRabbit status SHAs must resolve to exactly one open current-head PR before writes. Stacked child PRs targeting another open PR's head skip the wrong-base gate. `labeled`/`unlabeled` wake the gate only for `gui-screenshot-waived` and the `HYGIENE_GATE_LABELS` exported by `.github/scripts/pr-hygiene.cjs`; `tests/ci-workflows/ci-workflows.test.ts` pins the two lists together. |
| `.github/workflows/enforce-issue-quality.yml` | `issues` (opened, edited, reopened), `issue_comment` (created, edited), or manual dispatch with an issue number | Issue-template compliance gate. |
| `.github/workflows/issue-quality-tests.yml` | `pull_request` and `push` to `main`/`preview` filtered on the issue/PR automation scripts, templates, and their workflows | Tests the issue and PR automation scripts themselves, so the gates cannot rot silently. |
| `.github/workflows/issue-triage.yml` | `issues` (opened) | Duplicate detection and triage labeling for new issues. |
Expand Down
19 changes: 12 additions & 7 deletions tests/ci-workflows/ci-workflows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test";
import { fileURLToPath } from "node:url";
import { mkdtempSync, readFileSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { createRequire } from "node:module";
import { join } from "node:path";
import {
SCRIPT_BINDINGS,
Expand Down Expand Up @@ -1213,13 +1214,17 @@ describe("GitHub Actions hardening", () => {
expect(String(resolver?.["if"] ?? "")).toContain("github.event.state == 'success'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.sender.login == 'coderabbitai[bot]'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.sender.id == 136622811");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.label.name == 'gui-screenshot-waived'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.label.name == 'intake: hygiene-blocked'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.label.name == 'maintainer-sponsored'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.label.name == 'test-exception-approved'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.label.name == 'suppression-approved'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.label.name == 'generated-change-approved'");
expect(String(resolver?.["if"] ?? "")).toContain("github.event.label.name == 'dependency-change-approved'");
// Every label that can clear or reinstate a hygiene failure must wake the
// gate (#7651). Derive the list from HYGIENE_GATE_LABELS instead of
// restating it, so a label added there without a wake condition fails here.
const { HYGIENE_GATE_LABELS } = createRequire(import.meta.url)(
join(repoRoot(), ".github", "scripts", "pr-hygiene.cjs"),
) as { HYGIENE_GATE_LABELS: string[] };
const wakeLabels = [
...String(resolver?.["if"] ?? "").matchAll(/github\.event\.label\.name == '([^']+)'/g),
].map(match => match[1]);
expect(new Set(wakeLabels).size).toBe(wakeLabels.length);
expect([...wakeLabels].sort()).toEqual([...HYGIENE_GATE_LABELS, "gui-screenshot-waived"].sort());

const hygieneWorkflow = Bun.YAML.parse(
await readText(".github/workflows/pr-hygiene.yml"),
Expand Down
Loading