Repository navigation
Adopt workflow execution protections across the portfolio #202
Description
🤖 Generated by the Agentic Engineer
Objective
Adopt GitHub Actions workflow execution protections across every active portfolio repository so only approved actors and events can start each workflow, with stricter policy for deployment and manual-entry workflows.
Context
GitHub made workflow execution protections generally available on 2026-09-17. Policies can restrict actors and events, target specific workflow paths, expose enforcement insights, and be managed through REST at repository, organization, or enterprise scope.
Current verified evidence:
- The monorepo has no
pull_request_targetworkflow. - Its three
workflow_dispatchentry points areaudit-docs.yaml,publish-pages.yaml, andtodos.yaml. - The monorepo repository-level Actions policy inventory is empty.
- Organization-level policy inventory is currently
QUERY-UNKNOWNbecause the routine credential lacksadmin:org; no absence is inferred. - GitHub will enforce its default public-repository
pull_request_targetrestriction on 2026-11-02 for affected repositories.
References:
- https://github.blog/changelog/2026-09-17-workflow-execution-protections-in-github-actions-generally-available/
- https://docs.github.com/en/actions/concepts/about-actions-policies
- https://docs.github.com/en/actions/how-tos/administer/control-workflow-execution
- https://docs.github.com/en/rest/actions/policies
Desired state
Every workflow is covered by a deliberate layered policy. Broad CI remains usable by the contributors and automation that need it; deployment, publication, workflow_dispatch, and repository_dispatch workflows are limited to explicitly approved identities and events. pull_request_target is prohibited by default and permitted only for a reviewed workflow-path exception with a documented threat model.
Acceptance criteria
- Inventory every active, non-archived portfolio repository, workflow path, trigger event, required caller, and current policy inherited from repository/organization/enterprise scope.
- Resolve every required actor to its live GitHub actor type and ID, including trusted humans, repository roles, Dependabot, Renovate, suite-owned Apps/bots, and reusable-workflow callers.
- Classify workflows by exposure: ordinary CI, required reusable workflow, scheduled maintenance, manual/repository dispatch, publication, deployment, and privileged administration.
- Define layered actor/event policies rather than one account-wide allowlist.
- Prohibit
pull_request_targetby default; document and independently review any workflow-path exception before enforcement. - Apply workflow-path targeting to deployment, publication, privileged administration, and manual-entry workflows.
- Preserve required
pull_request,push,merge_group,schedule,workflow_call,workflow_dispatch, andrepository_dispatchevents only where the inventory proves they are needed. - Use Evaluate mode and policy insights where the plan supports it; otherwise stage enforcement through a representative low-risk repository before portfolio rollout.
- Exercise positive controls for every required actor/event pair and safe negative controls through policy insights or a dedicated test repository.
- Verify no required checks, releases, deployments, dependency updates, or scheduled workflows are stranded.
- Manage policies through the reviewed declarative path when supported, otherwise use the versioned REST API and record the remaining GitOps gap under Adopt supported GitHub rulesets and track remaining provider gaps #69.
- Read back policy source, enforcement mode, target repositories, workflow paths, actor IDs, and events after every mutation.
- Add drift coverage so deletion, broadening, or actor/event omission is detected.
- Document staged rollback and the 2026-11-02
pull_request_targetenforcement deadline.
Dependencies
- Parent epic: Adopt supported GitHub rulesets and track remaining provider gaps #69
- Requires organization-administration access to inventory and manage inherited policies.
- Final actor allowlists and enforcement activation require maintainer approval.
- Provider support may lag the REST surface; that must not be misreported as declarative enforcement.
Notes
Do not infer trust from a provider name or repository write access. GitHub features may be exempt for built-in processes, but custom workflows triggered by their identities still require the relevant actor to be allowed.
Blocker: the maintainer approves the world-at-ruin deploy-starter activation by marking #623 ready and merging it | authority | last-verified 2026-10-17: the Data Product Controller trial passed and its outcome is recorded (comment 6229852065); the next activation is prepared with clean actor evidence and waits on that approval | asked pr 2026-10-17
Metadata
Metadata
Assignees
Labels
Type
Fields
Projects
- StatusShow more project fields📥 Backlog
Activity
chore: agent-claim #202 nonce=1d0663c3fe887926db1d05407fc4ba14
devantler commentedon Sep 19, 2026
First inventory, 2026-09-19 ~17:30Z
Ran the read-only inventory from #203 across all 23 active repositories. It exited cleanly, with no unreadable repositories or workflows.
workflow_dispatch/repository_dispatch)workflow_call)pull_request_targetorworkflow_runFindings that shape the policy design:
pull_request_targetmatch is anif:condition inactions/dependency-review.yaml, not a trigger. So the "prohibitpull_request_targetby default" rule can start in enforce mode without breaking anything, and it needs no exceptions today.workflow_dispatch, including 26 release or deploy workflows. Restricting who can dispatch those is the most valuable first rule.Next slice: resolve the live actor identities each workflow needs (people, Dependabot, Renovate, our Apps). Then draft layered policies in Evaluate mode. Organization-scope policies still need an
admin:orgread, which this run cannot do.feat(ci): inventory who and what can start each workflow (#203)
devantler commentedon Sep 20, 2026
Live default-branch inventory — 2026-09-20
Ran the repository's fail-closed
scripts/workflow-execution-inventory.sh --org devantler-techagainst the live organization. Its repository-list completeness check passed, every default-branch workflow document parsed, and the run exited successfully.0.privileged-trigger: no default-branch workflow currently usespull_request_targetorworkflow_run.This closes no acceptance criterion by itself. Repository-level zero does not prove that organization- or enterprise-level inherited policy is absent, and the routine credential still cannot read that scope. The inherited-policy join therefore remains
QUERY-UNKNOWN; no policy mutation or enforcement recommendation was made from this partial view.devantler commentedon Sep 21, 2026
Enforcement path — lead for the policy-design slice (2026-09-21)
This repo manages org settings through
deploy/, which Crossplane's upjet GitHub provider reconciles. It is built on the Terraformintegrations/githubprovider. So whatever policies this issue designs have to be expressible through that provider, or they will drift outside GitOps and get no revert-on-drift.A search of the provider's public registry docs today turned up only the older Actions resources: repository/organization Actions permissions, workflow token permissions, and runner groups. No resource for the workflow execution protections GA'd on 2026-09-17 surfaced. A search is weak evidence, so treat this as a lead: the next run should confirm it against the provider's resource index before designing anything.
If it holds, the design slice splits in two:
12 remaining items
devantler commentedon Sep 25, 2026
The go-template deploy-starter trial is live
6c589b4a), which closed Switch on the go-template deploy-starter policy for a one-week trial #230.UPDATEDfromdisabled, and the other nine policiesIN-SYNC, stilldisabled.cd.yamlandrelease.yamlkeep starting for every portfolio identity, with no run blocked by the policy.Next measurement due: 2026-10-02. On that date, read go-template's runs of those two workflows for the window and record whether the policy should stay on, be widened to the next repository, or be reverted.
devantler commentedon Oct 2, 2026
go-template trial measurement (window 2026-09-25 10:53Z → 2026-10-02 12:00Z)
release.yaml: 14 runs in the window, allsuccess. They were started bybotantler-1[bot](13 runs, allpush) anddevantler(1 run,push). No run was blocked.cd.yaml: not exercised. It starts only on av*tag push (or a manual run). No tag was cut in the window: the newest release is stillv1.5.4from 2026-09-22, before the trial. The success signal for this workflow is therefore unmeasured, not passed.successorskipped. Nothing was stranded.Recommendation: keep the go-template policy on and extend the trial until the next
v*tag runscd.yaml. That run is the missing positive control for the deploy-starter path. Nothing measured points to a rollback, andrelease.yamlis proven for both identities that use it. Widening to a second repository needs the maintainer's approval (see Dependencies), so that call stays open here. Next measurement: the first go-templatecd.yamlrun after a new tag, read the same way.devantler commentedon Oct 3, 2026
The missing deployment positive control has now occurred: go-template CD run 37048903707 completed successfully on 2026-10-02 at exact commit
29e1052dc6620c6342e054850cfb2c51e12d3bb7. Its actual GoReleaser job built and published v1.5.5; this was an executed tag-triggered deployment, not an interface check or a skipped job.Today's policy reconciliation at reviewed
88b17960d56da9328e7f92bae02c9509cfd2c2beread all ten declared policies back IN-SYNC, including the go-template starter policy. Together with the already recorded release controls, this completes the previously missing positive-path observation.Keep the existing pilot active. Policy insights remain UNKNOWN to the routine credential; the direct organization-policy read is rejected for missing administration scope. No clean negative-control verdict or broader rollout is inferred. A second repository still needs a separately reviewed, explicitly approved activation and native actor/event controls. This issue remains open.
feat(ci): switch on the data-product-controller deploy-starter policy…
devantler commentedon Oct 7, 2026
The data-product-controller deploy-starter policy is live. The maintainer approved it in an interactive session on 2026-10-07; #452 merged as
c252e112, and the reconciler run onmain(run 37674569373) updated the live policy and reported the go-template one already in sync.Two of the nine prepared deploy-starter policies are now active. Nothing waits on the maintainer right now, so the blocker line and label are removed: the next step is to prepare the next activation as a draft, which then needs its own approval like this one did.
devantler commentedon Oct 8, 2026
The Data Product Controller trial began with the verified policy update in apply run 37674569373 on 2026-10-07 at 19:34 UTC, after approved activation #452 merged. The existing rollout procedure requires one week of observation and a recorded outcome before activating another policy.
Next measurement: 2026-10-14 at 19:34 UTC. The complete current run census contains eight successful postactivation runs, but none exercises the targeted release workflow. Its latest successful release preceded activation and does not satisfy that control. Observe the first native release after activation, then measure the full week before proposing the next activation with refreshed actor and event evidence. No additional policy was activated.
devantler commentedon Oct 8, 2026
Delivered child #539 in merged PR #544: drift comparison now retains property source and explicitly declared name protection, validates the full selector shape before any writes, and checks targeting again after writes.
Current-head CI and Codex review passed. The automatic live reconciliation at merged commit
e748d78e81dea89471cf1474108cddd65499029dread all ten declarations as IN-SYNC and revoked its App token. v7.6.1 contains the repair.This closes the reconciler defect. #202 remains open for its existing staged activation, actor/event controls and rollout acceptance; no additional policy was activated by this change.
devantler commentedon Oct 17, 2026
Data Product Controller trial outcome: passed. The trial ran from 2026-10-07 19:34 UTC to 2026-10-14 19:34 UTC. I measured it on 2026-10-17, which also covers the days after it ended.
release.yamlran 45 times between 2026-10-08 and 2026-10-16. All 45 succeeded. 23 were started bydevantlerand 22 bybotantler-1[bot], and both identities are on the allowlist.cd.yamlruns succeeded, apart from one run cancelled on a proof tag the maintainer pushed himself.startup_failurerun of any workflow in the window.Next activation: world-at-ruin, whose evidence is the strongest of the remaining eight:
workflow-execution-actors.shexited 0 for 2026-09-17 to today with no UNKNOWN row.cd.yamlwas started only bydevantler(26203420) andbotantler-1[bot](185060876), with 83 tag pushes in 30 days.publish.yamlnorrelease.yamlhas ever run.Gap found: world-at-ruin also has
server-cd.yaml, a second deploy workflow that the prepared policy does not target. Covering it is a separate, reviewed change.The activation pull request follows as a draft for the maintainer's approval.
feat(ci): switch on the world-at-ruin deploy-starter policy for its t…