ci(terraform-isolation): re-evaluate the gate on label changes

This commit is contained in:
Adam Moussa 2026-09-10 20:11:20 -04:00
parent 763b82a77d
commit a95c11527c
No known key found for this signature in database
5 changed files with 61 additions and 11 deletions

View file

@ -3,6 +3,16 @@ name: Frontend checks
on: on:
pull_request: pull_request:
branches: [main, dev, staging] branches: [main, dev, staging]
# labeled/unlabeled re-evaluate terraform-isolation when the override
# label is added or removed. Without them a mixed PR can keep a stale
# green isolation check after the label is taken off. Other jobs skip
# on those events so a label change does not re-run the suite.
types:
- opened
- synchronize
- reopened
- labeled
- unlabeled
push: push:
branches: [main, dev, staging] branches: [main, dev, staging]
workflow_dispatch: {} workflow_dispatch: {}
@ -13,12 +23,15 @@ permissions:
jobs: jobs:
build-and-test: build-and-test:
name: Build and test name: Build and test
# Skipped jobs satisfy the required checks on the unchanged SHA.
if: github.event_name != 'pull_request' || (github.event.action != 'labeled' && github.event.action != 'unlabeled')
# Org reusable workflow (Node 24): format check, lint, build, unit tests. # Org reusable workflow (Node 24): format check, lint, build, unit tests.
uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-frontend.yaml@af0f002e14a08cdbfd879c1183bfe7eb2604bce9 # v1.0.8 uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-frontend.yaml@af0f002e14a08cdbfd879c1183bfe7eb2604bce9 # v1.0.8
with: with:
node-version: "24" node-version: "24"
governance: governance:
if: github.event_name != 'pull_request' || (github.event.action != 'labeled' && github.event.action != 'unlabeled')
# Repo-owned guarantee that every frontend quality gate runs from this # Repo-owned guarantee that every frontend quality gate runs from this
# repository, independent of (and in addition to) the reusable workflow. # repository, independent of (and in addition to) the reusable workflow.
# `npm run verify` is the single command that chains: format check, lint # `npm run verify` is the single command that chains: format check, lint
@ -76,8 +89,9 @@ jobs:
# application code (scripts/check-terraform-isolation.mjs). A merge that # application code (scripts/check-terraform-isolation.mjs). A merge that
# does both queues an HCP VCS run and a content release at the same time, # does both queues an HCP VCS run and a content release at the same time,
# and the two race for the workspace lock. The # and the two race for the workspace lock. The
# `terraform-isolation-override` label is the reviewed exception; it is # `terraform-isolation-override` label is the reviewed exception. This
# read when the job runs, so re-run this workflow after labeling. # job runs on labeled/unlabeled as well as the default PR types so the
# check matches the labels currently on the PR.
name: Terraform and application changes are isolated name: Terraform and application changes are isolated
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -97,6 +111,7 @@ jobs:
visual-regression: visual-regression:
name: Visual regression name: Visual regression
if: github.event_name != 'pull_request' || (github.event.action != 'labeled' && github.event.action != 'unlabeled')
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: mcr.microsoft.com/playwright:v1.61.1-noble container: mcr.microsoft.com/playwright:v1.61.1-noble
steps: steps:

View file

@ -49,10 +49,13 @@ and synthesis. A task is not done until this is green.
against synthetic plan JSON. Real import and controlled-update plans from HCP against synthetic plan JSON. Real import and controlled-update plans from HCP
are migration evidence reviewed by a human before an approved apply are migration evidence reviewed by a human before an approved apply
(`terraform/README.md`). (`terraform/README.md`).
- **The isolation gate reads the override when it runs** — the - **The isolation gate re-evaluates on label changes** — the
`terraform-isolation-override` label is the only way to merge a mixed `terraform-isolation-override` label is the only way to merge a mixed
Terraform/application PR, the gate logs the override on the run, and the Terraform/application PR. `ci.yaml` runs `terraform-isolation` on
workflow must be re-run after the label is added or removed. `labeled` and `unlabeled` as well as the default pull-request types, so
adding or removing the label re-checks the current labels. The other CI
jobs skip on those events. Removing the label fails a mixed PR that had
previously passed with the override.
## Where the gates run ## Where the gates run

View file

@ -17,7 +17,9 @@
// TERRAFORM_ISOLATION_OVERRIDE=true downgrades a failure to a warning. CI sets // TERRAFORM_ISOLATION_OVERRIDE=true downgrades a failure to a warning. CI sets
// it only when the PR carries the `terraform-isolation-override` label, which // it only when the PR carries the `terraform-isolation-override` label, which
// reviewers grant to the rare change that must introduce Terraform variables // reviewers grant to the rare change that must introduce Terraform variables
// together with the workflow that consumes them. // together with the workflow that consumes them. The checker has no memory of
// a previous pass: the same mixed diff fails again as soon as the override
// env is unset (label removal).
import { execFileSync } from "node:child_process"; import { execFileSync } from "node:child_process";
import { readFileSync } from "node:fs"; import { readFileSync } from "node:fs";
import path from "node:path"; import path from "node:path";

View file

@ -109,6 +109,33 @@ test("CLI override downgrades a mixed change to a warning that names the label",
assert.equal(notTrue.status, 1); assert.equal(notTrue.status, 1);
}); });
test("removing the override fails a mixed change that was previously green", () => {
const files = ["terraform/live/dev/main.tf", ".github/workflows/deploy.yml"];
const previouslyGreen = runGate(files, {
TERRAFORM_ISOLATION_OVERRIDE: "true",
});
assert.equal(
previouslyGreen.status,
0,
previouslyGreen.stdout + previouslyGreen.stderr,
);
assert.match(previouslyGreen.stdout, /WARNING/);
// CI sets TERRAFORM_ISOLATION_OVERRIDE from contains(...labels), which is
// the string "false" after the label is removed. A stale green check must
// not survive that.
const afterLabelRemoved = runGate(files, {
TERRAFORM_ISOLATION_OVERRIDE: "false",
});
assert.equal(
afterLabelRemoved.status,
1,
afterLabelRemoved.stdout + afterLabelRemoved.stderr,
);
assert.match(afterLabelRemoved.stdout, /FAIL/);
assert.match(afterLabelRemoved.stdout, /deploy\.yml/);
});
test("CLI refuses to run without a base ref or --stdin", () => { test("CLI refuses to run without a base ref or --stdin", () => {
const result = spawnSync(process.execPath, [SCRIPT], { encoding: "utf8" }); const result = spawnSync(process.execPath, [SCRIPT], { encoding: "utf8" });
assert.notEqual(result.status, 0); assert.notEqual(result.status, 0);

View file

@ -221,11 +221,14 @@ the labels. Push-to-`dev` releases return behind the repository variable
`.github/workflows/ci.yaml` enforces this; documentation and the `.github/workflows/ci.yaml` enforces this; documentation and the
`scripts/*terraform*` tooling are allowed alongside. A reviewer may add the `scripts/*terraform*` tooling are allowed alongside. A reviewer may add the
`terraform-isolation-override` label for the rare change that must introduce `terraform-isolation-override` label for the rare change that must introduce
Terraform variables together with the workflow that consumes them (PR A and Terraform variables together with the workflow that consumes them (PR C).
PR C), then re-run the workflow so the job reads the label. The label is the Adding or removing that label re-runs `terraform-isolation` against the
approval record. The override is temporary: a follow-up PR after PR C labels currently on the PR; the other CI jobs skip on those events so a
removes the label path from the checker and workflow so the gate has no label change does not re-run the suite. Removing the label fails a mixed
exception. PR that had previously passed with the override, so a stale green check
cannot merge. The label is the approval record. The override is temporary:
a follow-up PR after PR C removes the label path from the checker and
workflow so the gate has no exception.
- **Every Terraform merge produces a VCS run.** A human confirms or discards - **Every Terraform merge produces a VCS run.** A human confirms or discards
it before the next content release. Do not leave a pending run on the it before the next content release. Do not leave a pending run on the
workspace. workspace.