From 19ecb925a32dfd15c7a0964ed12bd7a3d175b492 Mon Sep 17 00:00:00 2001 From: jun Date: Wed, 2 Sep 2026 19:51:38 +0900 Subject: [PATCH 1/4] =?UTF-8?q?devlog(release):=20080=20=E2=80=94=20bot=20?= =?UTF-8?q?PR=20toggle=20provenance=20and=20decision,=20service-lifecycle?= =?UTF-8?q?=20trigger=20gap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../080_release_automation_followups.md | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md diff --git a/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md b/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md new file mode 100644 index 0000000000..0727a13f67 --- /dev/null +++ b/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md @@ -0,0 +1,46 @@ +# 080 — Release automation follow-ups: bot PR creation, service-lifecycle trigger + +## Provenance: was "Allow GitHub Actions to create and approve pull requests" turned off? + +No. It was never on. + +| date | source | `can_approve_pull_request_reviews` | +|---|---|---| +| 2026-07-27 | chat tool log (`gh api …/actions/permissions/workflow`) | false | +| 2026-08-01 | chat tool log, Windows CI server session | false | +| 2026-09-02 | this train, after release 33617573070 | false | + +No commit, devlog note, or chat turn in the recall index mentions disabling it. GitHub creates +repositories with this toggle OFF, so the value is the default, not a maintainer decision. +#3013 (open bumps as PRs) and #3129 (call the bump from release.yml) both assumed the bot could +open a PR with `GITHUB_TOKEN`; neither was exercised by a live release until v2.40.0, which is +why the gap surfaced only now. + +## Decision + +Flip the repository toggle (option a). Rejected: a PAT secret for `gh pr create` (option b) — +a long-lived write credential in Actions is a wider blast radius than a repo-scoped toggle. + +What the toggle grants: any workflow running with `GITHUB_TOKEN` may create pull requests and +submit approving reviews. What still holds: `Protect dev` requires a reviewed pull request and +blocks direct pushes; `MAINTAINERS.md` forbids self-approval; `dev-version-bump.yml` runs only as +a `workflow_call` from `release.yml` (no `workflow_dispatch`), with `contents: write` scoped to +the unprotected `codex/dev-version-*` branch. A bot-created PR cannot merge itself; it waits for +the same admin merge every bump has had by hand (#3045, #3076, #3127, #3265). + +Route: REST `PUT /repos/{owner}/{repo}/actions/permissions/workflow` with +`can_approve_pull_request_reviews=true` (the user's `gh` session is an admin). Aside against the +Settings page only if the API refuses. + +Verification: re-read the setting; the exact failing step (`gh pr create` under `GITHUB_TOKEN`) +is proven live by the next release's bump job — a synthetic probe would need its own workflow on +`dev` and is not worth landing for one step. + +## service-lifecycle trigger + +`release.yml`'s gate requires a successful `service-lifecycle.yml` run for the release SHA when +any of its watched paths changed since the previous tag. `service-lifecycle.yml`'s own +`push.paths` did not include `.github/workflows/release.yml`, so #3263/#3264 (workflow-only +cherry-picks onto main/preview) produced no run and both v2.40.0 dispatches needed a manual +`workflow_dispatch`. Add `.github/workflows/release.yml` to both trigger path lists and to the +regex the gate applies, so the two stay in sync as the file comment already demands. From eb28dff0fd49dd08a11121529a6dc0cdb6455646 Mon Sep 17 00:00:00 2001 From: jun Date: Wed, 2 Sep 2026 19:51:53 +0900 Subject: [PATCH 2/4] chore(devlog): wp1 provenance closeout marker From 6c05e3ec27748979dcbad22191cb7a490411bf10 Mon Sep 17 00:00:00 2001 From: jun Date: Wed, 2 Sep 2026 19:52:13 +0900 Subject: [PATCH 3/4] =?UTF-8?q?devlog(release):=20080=20=E2=80=94=20toggle?= =?UTF-8?q?=20applied=20via=20REST,=20read-back=20true?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../080_release_automation_followups.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md b/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md index 0727a13f67..5c38f123f3 100644 --- a/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md +++ b/devlog/_plan/260902_windows_ci_release/080_release_automation_followups.md @@ -36,6 +36,11 @@ Verification: re-read the setting; the exact failing step (`gh pr create` under is proven live by the next release's bump job — a synthetic probe would need its own workflow on `dev` and is not worth landing for one step. +Applied 2026-09-02 via `gh api -X PUT repos/lidge-jun/opencodex/actions/permissions/workflow +-f default_workflow_permissions=read -F can_approve_pull_request_reviews=true`; the API accepted +it, so Aside was not needed. Read-back: `{"default_workflow_permissions":"read", +"can_approve_pull_request_reviews":true}`. Default token permission stays `read`. + ## service-lifecycle trigger `release.yml`'s gate requires a successful `service-lifecycle.yml` run for the release SHA when From b84eafcc45206ae9f8cd8cbce9932e564f06d6c0 Mon Sep 17 00:00:00 2001 From: jun Date: Wed, 2 Sep 2026 19:52:50 +0900 Subject: [PATCH 4/4] ci(service-lifecycle): trigger on release.yml changes so the release gate cannot dead-end release.yml requires a service-lifecycle run for the release SHA when any gated path changed since the previous tag, but a release-branch commit that touched only release.yml (the v2.40.0 permissions carry, #3263/#3264) matched no lifecycle trigger path, so both dispatches needed a manual run. The path is now in both trigger lists and the gate regex; tests/ci-workflows keeps the three in sync. --- .github/workflows/release.yml | 2 +- .github/workflows/service-lifecycle.yml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 261aece1d1..f053574295 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -265,7 +265,7 @@ jobs: # Keep in sync with the service-lifecycle.yml trigger paths. src/cli.ts is # the pre-restructure compat stub that durable launchers still execute. - if printf '%s\n' "$changed_files" | grep -Eq '^(src/service\.ts|src/cli\.ts|src/cli/index\.ts|src/lib/bun-runtime\.ts|package\.json|bun\.lock|\.github/workflows/service-lifecycle\.yml)$'; then + if printf '%s\n' "$changed_files" | grep -Eq '^(src/service\.ts|src/cli\.ts|src/cli/index\.ts|src/lib/bun-runtime\.ts|package\.json|bun\.lock|\.github/workflows/service-lifecycle\.yml|\.github/workflows/release\.yml)$'; then service_url="$( gh run list \ --workflow service-lifecycle.yml \ diff --git a/.github/workflows/service-lifecycle.yml b/.github/workflows/service-lifecycle.yml index 8e0513b459..df37f60561 100644 --- a/.github/workflows/service-lifecycle.yml +++ b/.github/workflows/service-lifecycle.yml @@ -14,6 +14,10 @@ on: - "package.json" - "bun.lock" - ".github/workflows/service-lifecycle.yml" + # release.yml gates on THIS workflow having run for the release SHA. A release-branch + # commit that touches only release.yml (e.g. the v2.40.0 permissions carry, #3263/#3264) + # produced no run and the gate dead-ended until a manual dispatch. + - ".github/workflows/release.yml" push: paths: - "src/service.ts" @@ -24,6 +28,10 @@ on: - "package.json" - "bun.lock" - ".github/workflows/service-lifecycle.yml" + # release.yml gates on THIS workflow having run for the release SHA. A release-branch + # commit that touches only release.yml (e.g. the v2.40.0 permissions carry, #3263/#3264) + # produced no run and the gate dead-ended until a manual dispatch. + - ".github/workflows/release.yml" workflow_dispatch: permissions: