| title | Roll out GitHub runner governance |
|---|---|
| description | Prove protected environments, OIDC deployment identity, and self-hosted runner approval before privileged GitHub Actions deployments. |
Use this when a GitHub Actions workflow can deploy to cloud infrastructure, run pulumi destroy, or assume a cloud role. The goal is to make the workflow prove three things: the environment exists live in GitHub settings, reviewers are active for production, and runner usage is either GitHub-hosted or explicitly approved.
@hulumi/platform-patternsand@hulumi/policiesinstalled.- GitHub Actions workflows use SHA-pinned actions and top-level minimum permissions.
- Deployment jobs use GitHub OIDC for cloud access.
- For live checks,
gh auth statussucceeds or CI provides a token with read access to repo environments and runner metadata.
- Add the runner governance contract:
import { RunnerGovernanceFoundation } from "@hulumi/platform-patterns";
export const runnerGovernance = new RunnerGovernanceFoundation("runner-governance", {
tier: "startup-hardened",
owner: "example-org",
repository: "service",
environments: [
{
name: "prod",
requiredReviewers: true,
protectedBranches: true,
},
],
privilegedWorkflows: [
{
workflowPath: ".github/workflows/deploy.yml",
jobName: "deploy",
environmentName: "prod",
runsOn: ["ubuntu-latest"],
oidcRequired: true,
},
],
});- Keep self-hosted runners denied unless you have a finite label approval:
approvedSelfHostedRunnerLabels: ["linux", "x64", "deploy-prod"];- Run static workflow governance:
pnpm run lint:workflow-governance- Run live environment checks when
ghcan read repo settings:
pnpm run lint:workflow-governance -- --check-settings- If a self-hosted runner is intentionally approved, pass every non-
self-hostedlabel:
pnpm run lint:workflow-governance -- --check-settings \
--allow-self-hosted-runner-label linux \
--allow-self-hosted-runner-label x64 \
--allow-self-hosted-runner-label deploy-prod- Add the deployment governance policy pack so malformed component props are caught in preview:
runtime: nodejs
policies:
- name: hulumi-deployment-governance
path: node_modules/@hulumi/policies/platform/packs/deployment-governancepnpm --filter @hulumi/platform-patterns test -- --run tests/runner-governance-foundation.test.tspnpm --filter @hulumi/policies test -- --run tests/platform/deployment-governance-pack.test.tspnpm --filter @hulumi/drift test -- --run tests/live-validator.test.tspnpm run lint:workflow-governance
- Disable the affected workflow.
- Inspect recent workflow runs, environment approvals, runner labels, and any newly registered self-hosted runners.
- Rotate any cloud credentials that may have been reachable. Prefer deleting long-lived cloud secrets and restoring OIDC-only deployment.
- Run:
pnpm run lint:workflow-governance -- --check-settings- Re-pin any replaced actions to full 40-character SHAs.
- Re-enable the workflow only after environment reviewers and runner approvals match the governance contract.
WF_ENV_2_LIVE_ENVIRONMENT_EXISTS: the workflow names an environment that GitHub settings cannot resolve. Create or correct the environment before treating the workflow as protected.WF_ENV_3_LIVE_ENVIRONMENT_REQUIRES_REVIEWERS: production exists but lacks required reviewers. Add reviewers or narrow the environment contract.WF_RUNNER_1_SELF_HOSTED_REQUIRES_APPROVAL: a job usesself-hostedwithout a full finite label approval list.GH_RUNNER_2_PAGE_CAP_COMPLETE: the live runner scan hit its page cap. Increase the bounded cap or narrow repo scope; do not mark the check clean.