Repository navigation
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.
Trial checkpoint — 26 October 2026
The one-week World at Ruin window has ended. Its measurement records 14 observed deployment starts, 13 successes and one executed publication failure. Other allowed actors, policy insights, negative controls and broader rollout remain unproven. The next step is refreshed actor/event evidence and a separately reviewed activation; no additional policy is approved here. Original acceptance criteria remain unchanged.
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:
18 remaining items
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…
devantler commentedon Oct 24, 2026
Tracker correction: the recorded blocker had already cleared. The maintainer approved the World at Ruin deploy-starter activation, #623 merged on 2026-10-19 at 14:10 UTC, and the apply run put the policy in place as active.
I replaced the blocker line with the event this issue now waits on: the end of that one-week trial on 2026-10-26 at 14:10 UTC. Next, after that time: measure the trial the same way as the Data Product Controller one (runs of the targeted workflow, who started them, any failure to start), record the outcome here, then prepare the next activation. The uncovered second World at Ruin deploy workflow noted on 2026-10-17 is still a separate change. GitHub's default restriction on
pull_request_targetfor public repositories still takes effect on 2026-11-02.No policy was changed in this update.
chore: agent-claim #202 nonce=40ca227f4e5b210ac55b80d4636d534b
devantler commentedon Oct 26, 2026
World at Ruin trial checkpoint — 26 October 2026
The recorded one-week window has ended: 19 October 14:10 UTC through 26 October 14:10 UTC. A complete targeted-workflow inventory contains 14 unique runs, matching GitHub's advertised count. All 14 started on
pushunderbotantler-1[bot], an allowed identity.ba5706161be44aaa9450371a2e7557e33fa29861. Its complete seven-job graph contains two successes, two failures and three skips. The publication job and final CD aggregate failed. This is an executed publication failure, not an observed policy startup refusal; its publication root cause is not determined by this measurement.startup_failureconclusion. This does not establish that an expected run was never prevented from being created.The latest native policy reconciliation, attempt 1 at
c2b06a1ac224a57750cd66aec571701c4b546b30, succeeded and explicitly read this policy backIN-SYNCat 05:53:27 UTC on 26 October, before the window ended. The current declaration retains the same active policy and targets onlycd.yaml. This earlier reconciliation is not a fresh post-window administration read.Keep the existing pilot active. The observed bot path worked throughout the window, but the other allowed identities, policy insights, negative controls and the separate
server-cd.yamlcoverage remain unproven. No clean verdict for those controls or portfolio-wide completion is inferred. Refresh the actor/event evidence before preparing the next separately reviewed activation; the existing maintainer-approval requirement remains. No policy, permission or workflow was changed by this measurement, and #202 stays open.devantler commentedon Nov 1, 2026
The World at Ruin trial it waited on ended on 2026-10-26 and nothing outside this lane holds the next step, refreshing the actor and event evidence for the next separately reviewed activation, so the issue returns to selection.
devantler commentedon Nov 1, 2026
Checked against tomorrow's
pull_request_targetdefault (2026-11-02): no workflow here should be affected. A code search across the organization's workflow files returns one match,dependency-review.yamlin.github, and it only names the event in anif:condition and a comment. Its triggers areworkflow_call,pull_requestandmerge_group. This search reads default branches, so it says nothing about other branches. The remaining work here, refreshing the actor and event evidence for the next reviewed activation, has no deadline from that change.