fix(ci): use built-in token for runtime pin PRs (#3365)

This commit is contained in:
Carlos Florêncio
2026-09-04 14:33:41 +00:00
committed by GitHub
parent b557cf442c
commit ed80524e7d
16 changed files with 424 additions and 47 deletions
@@ -10,6 +10,14 @@ REPO_ROOT = Path(__file__).resolve().parents[2]
WORKFLOW = REPO_ROOT / ".github" / "workflows" / "update-agent-runtime-pins.yml"
LINT_WORKFLOW = REPO_ROOT / ".github" / "workflows" / "lint-action-pinning.yml"
SCRIPT = REPO_ROOT / "scripts" / "update-agent-runtime-pins.mjs"
REQUIRED_CHECK_WORKFLOWS = (
"backend-tests.yml",
"frontend-tests.yml",
"e2e-tests.yml",
"architecture-lint.yml",
"lint-action-pinning.yml",
"lint-harness-files.yml",
)
class ManagedRuntimePinWorkflowContractTest(unittest.TestCase):
@@ -21,16 +29,15 @@ class ManagedRuntimePinWorkflowContractTest(unittest.TestCase):
self.assertRegex(self.workflow, r"cron:\s*[\"']?[0-9]+ [0-9]+ \* \* [0-6][\"']?")
self.assertIn("workflow_dispatch:", self.workflow)
def test_workflow_uses_least_privilege_and_dedicated_app_token(self) -> None:
self.assertIn("permissions:\n contents: read", self.workflow)
self.assertIn("permission-contents: write", self.workflow)
self.assertIn("permission-pull-requests: write", self.workflow)
self.assertNotIn("permissions:\n contents: write", self.workflow)
self.assertNotIn("permissions:\n pull-requests: write", self.workflow)
self.assertIn("MANAGED_RUNTIME_PIN_APP_PRIVATE_KEY", self.workflow)
self.assertIn("MANAGED_RUNTIME_PIN_APP_CLIENT_ID", self.workflow)
def test_workflow_uses_least_privilege_and_builtin_token(self) -> None:
self.assertIn(
"permissions:\n contents: write\n pull-requests: write", self.workflow
)
self.assertIn("GH_TOKEN: ${{ github.token }}", self.workflow)
self.assertNotIn("actions/create-github-app-token@", self.workflow)
self.assertNotIn("MANAGED_RUNTIME_PIN_APP_PRIVATE_KEY", self.workflow)
self.assertNotIn("MANAGED_RUNTIME_PIN_APP_CLIENT_ID", self.workflow)
self.assertNotIn("secrets.GITHUB_TOKEN", self.workflow)
self.assertNotIn("GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}", self.workflow)
def test_workflow_groups_one_conventional_commit_pr_on_stable_branch(self) -> None:
self.assertIn("update-managed-runtime-pins", self.workflow)
@@ -47,7 +54,30 @@ class ManagedRuntimePinWorkflowContractTest(unittest.TestCase):
push_start = self.workflow.index("- name: Commit and push one grouped change")
pr_start = self.workflow.index("- name: Create or refresh the single grouped PR")
push_step = self.workflow[push_start:pr_start]
self.assertIn("GH_TOKEN: ${{ steps.app-token.outputs.token }}", push_step)
pr_step = self.workflow[pr_start:]
self.assertIn("GH_TOKEN: ${{ github.token }}", push_step)
self.assertIn("GH_TOKEN: ${{ github.token }}", pr_step)
def test_workflow_dispatches_required_checks_for_builtin_token_prs(self) -> None:
self.assertIn("actions: write", self.workflow)
dispatch_start = self.workflow.index(
"- name: Dispatch required checks for generated PR"
)
dispatch_step = self.workflow[dispatch_start:]
self.assertIn("gh workflow run", dispatch_step)
self.assertIn('--ref "$BOT_BRANCH"', dispatch_step)
self.assertIn('--repo "$GITHUB_REPOSITORY"', dispatch_step)
for workflow_name in REQUIRED_CHECK_WORKFLOWS:
self.assertIn(workflow_name, dispatch_step)
workflow = (REPO_ROOT / ".github" / "workflows" / workflow_name).read_text(
encoding="utf-8"
)
self.assertRegex(
workflow,
r"(?m)^ workflow_dispatch:\s*$",
f"{workflow_name} must accept explicit validation dispatches",
)
def test_workflow_validates_before_any_commit_or_push(self) -> None:
update_pos = self.workflow.index("node scripts/update-agent-runtime-pins.mjs")
+4
View File
@@ -7,6 +7,7 @@ on:
branches: [main]
merge_group:
types: [checks_requested]
workflow_dispatch:
concurrency:
# Pull requests can supersede one another safely. Pushes compare each commit
@@ -57,6 +58,9 @@ jobs:
# group's equivalent of the pull request's base.
merge_group) BASE_REF="${MERGE_GROUP_BASE_SHA}" ;;
push) BASE_REF="${PUSH_BEFORE}" ;;
# The updater dispatches this workflow against its stable bot
# branch, so the main branch fork point is the PR baseline.
workflow_dispatch) BASE_REF="$(git merge-base HEAD origin/main)" ;;
*) BASE_REF="" ;;
esac
+1
View File
@@ -13,6 +13,7 @@ on:
branches: [main]
merge_group:
types: [checks_requested]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
+1
View File
@@ -13,6 +13,7 @@ on:
branches: [main]
merge_group:
types: [checks_requested]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -18,6 +18,7 @@ on:
branches: [main]
merge_group:
types: [checks_requested]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
+1
View File
@@ -18,6 +18,7 @@ on:
branches: [main]
merge_group:
types: [checks_requested]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
+31 -18
View File
@@ -7,11 +7,13 @@ on:
- cron: "17 6 * * 1"
workflow_dispatch:
# The job mints a narrower GitHub App token only after checkout. The default
# workflow token is never used to create the generated PR, so its events retain
# the repository's normal CI behavior.
# The job uses the repository-scoped workflow token for the branch, PR, and
# explicit validation-workflow dispatches. A GITHUB_TOKEN-created push or PR
# does not recursively trigger push/pull_request workflows.
permissions:
contents: read
contents: write
pull-requests: write
actions: write
concurrency:
group: managed-runtime-pin-update
@@ -21,8 +23,6 @@ jobs:
update:
name: Open managed runtime pin PR
runs-on: ubuntu-latest
permissions:
contents: read
env:
BOT_BRANCH: automation/update-managed-runtime-pins
@@ -42,18 +42,9 @@ jobs:
- name: Test pin updater
run: node --test scripts/update-agent-runtime-pins.test.mjs
- name: Create managed runtime pin App token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.MANAGED_RUNTIME_PIN_APP_CLIENT_ID }}
private-key: ${{ secrets.MANAGED_RUNTIME_PIN_APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- name: Configure git authentication
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
GH_TOKEN: ${{ github.token }}
run: gh auth setup-git
- name: Prepare stable bot branch
@@ -74,7 +65,7 @@ jobs:
- name: Commit and push one grouped change
if: steps.update.outputs.changed == 'true'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
git config user.name "kandev-runtime-updater[bot]"
@@ -89,7 +80,7 @@ jobs:
- name: Create or refresh the single grouped PR
if: steps.update.outputs.changed == 'true'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
cat > /tmp/managed-runtime-pin-pr-body.md <<'EOF'
@@ -113,3 +104,25 @@ jobs:
--title "chore: update managed runtime pins" \
--body-file /tmp/managed-runtime-pin-pr-body.md
fi
# GITHUB_TOKEN-created push and pull-request events do not recursively
# start validation workflows. Dispatch the six required checks explicitly
# against the exact bot-branch commit after the PR exists.
- name: Dispatch required checks for generated PR
if: steps.update.outputs.changed == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
for workflow in \
backend-tests.yml \
frontend-tests.yml \
e2e-tests.yml \
architecture-lint.yml \
lint-action-pinning.yml \
lint-harness-files.yml
do
gh workflow run "$workflow" \
--repo "$GITHUB_REPOSITORY" \
--ref "$BOT_BRANCH"
done
@@ -5,6 +5,8 @@ import (
"slices"
"strings"
"testing"
"github.com/kandev/kandev/internal/agent/managedruntime"
)
func TestManagedNPMRuntimeContracts(t *testing.T) {
@@ -64,8 +66,9 @@ func TestManagedNPMRuntimeContracts(t *testing.T) {
func TestManagedNPMRuntimeExecutionCacheKeyMatchesNPM(t *testing.T) {
spec := ManagedNPMRuntimeSpec{Package: "opencode-ai"}
if got := spec.ExecutionCacheKey(); got != "305cdb391114ad88" {
t.Fatalf("ExecutionCacheKey = %q, want npm key 305cdb391114ad88", got)
want := managedruntime.NpxExecutionCacheKey(spec.PackageSpec(""))
if got := spec.ExecutionCacheKey(); got != want {
t.Fatalf("ExecutionCacheKey = %q, want npm key %q", got, want)
}
}
@@ -0,0 +1,63 @@
# ADR-2026-09-04-use-repository-token-for-runtime-pin-PRs: Use the built-in Actions token for runtime pin PRs
**Status:** accepted
**Date:** 2026-09-04
**Area:** workflow, security
## Context
The managed runtime pin workflow was merged with inputs for a dedicated GitHub
App client ID and private key. Those repository credentials were never
configured, so both scheduled runs reached the token step and stopped before
the updater, branch push, or pull-request creation.
The workflow only needs to write the trusted runtime catalogue to one
repository branch and create or edit one pull request. The repository already
provides a short-lived `GITHUB_TOKEN` for each workflow job. GitHub documents
that events created by this token do not recursively start new workflows,
except for explicit `workflow_dispatch` and `repository_dispatch` events.
## Decision
The managed runtime pin workflow uses the repository's built-in
`GITHUB_TOKEN`. The workflow grants only `contents: write`,
`pull-requests: write`, and `actions: write`, configures Git authentication
after the trusted checkout, and uses the token for the branch push, pull
request, and explicit workflow-dispatch operations. It does not require a
GitHub App, an App private-key secret, or a personal access token.
The workflow continues to validate the catalogue and managed-runtime packages
before it pushes, keeps one stable updater branch and one grouped pull request,
and never auto-merges or activates a runtime. Each required validation workflow
declares `workflow_dispatch`, and the updater dispatches the six required
checks against the exact bot-branch commit after the PR exists. The repository
or organization setting **Allow GitHub Actions to create and approve pull
requests** must be enabled. Any additional maintainer approval required by
repository policy remains an operational control, not a missing credential.
See [GitHub's `GITHUB_TOKEN` documentation](https://docs.github.com/en/actions/concepts/security/github_token)
for the event-trigger behavior that informs this decision.
## Consequences
- Scheduled and manual runs work without repository-specific App setup.
- The workflow has no additional long-lived credential to rotate or expose.
- The built-in token remains scoped to the repository and three required write
permissions.
- The six required validation workflows must retain their manual dispatch
trigger and support the selected branch's baseline semantics.
- The Actions setting that allows workflows to create and approve pull
requests must remain enabled.
- Repository policy can still require maintainer approval for generated runs.
- A future requirement for a different trust boundary must add a separately
managed GitHub App or personal access token and update this decision.
## Alternatives Considered
- **Dedicated GitHub App:** Rejected for this repair because the required App
credentials are not configured and the user does not have an App.
- **Personal access token:** Rejected because it adds a long-lived user-owned
credential and still requires repository secret setup.
- **Built-in token without explicit validation dispatch:** Rejected because
GitHub suppresses recursive `push` and `pull_request` workflow runs for
events created by the built-in token.
+1
View File
@@ -237,3 +237,4 @@ Read individual ADRs for full context. Create new ones via `/record decision` or
| 2026-09-01-passthrough-initial-prompt-turn-boundary | [Keep Passthrough Initial Prompt State in Lifecycle](2026-09-01-passthrough-initial-prompt-turn-boundary.md) | accepted | backend, workflow | 2026-09-01 |
| 2026-09-02-automation-self-archive | [Permit Automation Self-Archive as Terminal Completion](2026-09-02-automation-self-archive.md) | accepted | backend, agentctl, protocol, security, workflow | 2026-09-02 |
| 2026-09-03-separate-system-data-storage-pages | [Separate System Data and Storage Pages](2026-09-03-separate-system-data-storage-pages.md) | accepted | frontend | 2026-09-03 |
| 2026-09-04-use-repository-token-for-runtime-pin-prs | [Use the built-in Actions token for runtime pin PRs](2026-09-04-use-repository-token-for-runtime-pin-prs.md) | accepted | workflow, security | 2026-09-04 |
@@ -0,0 +1,99 @@
---
created: 2026-09-04
status: complete
requirements:
- ../../specs/agents/requirements/runtime-updates.md
system_design:
- ../../specs/agents/system-design/runtime-updates-01.md
legacy_specs: []
decisions:
- ../../decisions/2026-09-04-use-repository-token-for-runtime-pin-prs.md
---
# Implementation Plan: Restore managed runtime pin PR automation
## Overview
Replace the unavailable GitHub App credential in the managed runtime pin
workflow with the repository's built-in `GITHUB_TOKEN`. Preserve trusted-main
checkout, validation before mutation, the stable updater branch, one grouped
pull request, and no auto-merge. Explicitly dispatch the required validation
workflows because built-in-token branch and pull-request events do not
recursively start them.
## Scope
### In scope
- Change workflow permissions and authentication to the repository token.
- Add manual dispatch support to every required validation workflow and
dispatch each one against the exact generated branch commit.
- Update the workflow contract test to reject the unavailable App boundary and
require the built-in token and explicit validation-dispatch boundaries.
- Reconcile the runtime-update requirement, system design, ADR index, and the
completed workflow work-order record.
### Out of scope
- Creating or installing a GitHub App.
- Creating a personal access token or changing repository secrets/settings.
- Changing the npm updater, runtime catalogue, validation suite, or PR content.
- Designing a separate automatic PR-check approval workflow.
## Technical approach
- In `.github/workflows/update-agent-runtime-pins.yml`, grant only
`contents: write`, `pull-requests: write`, and `actions: write`, remove
`actions/create-github-app-token`, and use `${{ github.token }}` for Git,
`gh`, and workflow-dispatch operations.
- Add `workflow_dispatch` to the six required validation workflows. Make the
manual architecture run use the `main` fork point and let the other gates
fail open to a full validation run when no event base exists.
- Dispatch `backend-tests.yml`, `frontend-tests.yml`, `e2e-tests.yml`,
`architecture-lint.yml`, `lint-action-pinning.yml`, and
`lint-harness-files.yml` after the grouped PR is created or refreshed.
- Keep `persist-credentials: false`, the trusted `main` checkout, updater and
Go validation order, stable branch, grouped PR selection, and no-auto-merge
behavior unchanged.
- In `.github/scripts/update-agent-runtime-pins-workflow-contract_test.py`, add
a regression assertion for the built-in token and permissions, and assert
that App inputs and App-token action usage are absent.
- Update the runtime-update requirement/design and link the accepted token
decision so the documented CI approval consequence is explicit.
## Tests
- `AC-AGENTS-RUNTIME-UPDATES-001.9`: workflow contract tests preserve schedule,
validation-before-mutation, stable branch, grouped PR, and no-auto-merge
behavior.
- `AC-AGENTS-RUNTIME-UPDATES-001.10`: workflow contract tests require the
repository token, explicit required-check dispatch, and reject the
unavailable App credential boundary.
- The existing updater fixture tests remain green to prove the updater itself
is unchanged.
## E2E tests
No browser or product UI behavior changes. GitHub Actions run history is not
mutated as part of local verification.
## Work orders
- [x] [Task 01: Use the built-in token for managed runtime pin PRs](task-01-built-in-token.md)
## Verification results
The updater tests passed 7/7, the workflow contract tests passed 9/9, the
action-pinning tests passed 9/9, the action-pinning linter accepted all 21
workflow files, and `zizmor .github/workflows/update-agent-runtime-pins.yml`
reported no findings. Specification lint passed for all specification files,
and `git diff --check` passed.
## Risks
- GitHub's event suppression for built-in-token pushes and PRs is avoided by
explicit manual dispatch of every required validation workflow.
- Repository policy must continue to allow Actions to create and approve pull
requests.
- The workflow's write token must remain limited to this repository and the
three required permissions.
@@ -0,0 +1,105 @@
---
id: "01-built-in-token"
title: "Use the built-in token for managed runtime pin PRs"
status: done
wave: 1
depends_on: []
plan: "plan.md"
requirements:
- ../../specs/agents/requirements/runtime-updates.md
acceptance_criteria:
- AC-AGENTS-RUNTIME-UPDATES-001.9
- AC-AGENTS-RUNTIME-UPDATES-001.10
system_design:
- ../../specs/agents/system-design/runtime-updates-01.md
---
# Task 01: Use the built-in token for managed runtime pin PRs
## Summary
Make the weekly/manual managed runtime pin workflow runnable without a
GitHub-App credential. Use the repository-scoped built-in Actions token with
the minimum permissions for branch, PR, and explicit validation-workflow
dispatches, while preserving validation, branch, and grouped PR behavior.
## In scope
- Replace App-token creation and its unavailable inputs in the workflow.
- Configure Git and `gh` with `${{ github.token }}`.
- Dispatch the six required validation workflows explicitly against the bot
branch, and add their `workflow_dispatch` triggers.
- Update the workflow contract test and the completed workflow record.
- Keep the runtime updater and catalogue unchanged.
## Out of scope
- GitHub App or personal access token provisioning.
- Automatic approval of generated PR checks.
- Changes to runtime selection or npm metadata logic.
## Acceptance
- The workflow grants only `contents: write`, `pull-requests: write`, and
`actions: write`, and uses `${{ github.token }}` for branch, PR, and
validation-dispatch mutations.
- The workflow explicitly dispatches all six required validation workflows
after the generated PR exists, and each target accepts `workflow_dispatch`.
- The contract test fails against the current App-token workflow and passes
after the workflow uses the built-in token.
- The updater still validates before any commit or push, creates at most one
grouped PR, and never auto-merges.
## Verification
```bash
node --test scripts/update-agent-runtime-pins.test.mjs && python3 .github/scripts/update-agent-runtime-pins-workflow-contract_test.py && python3 .github/scripts/lint-action-pinning_test.py && python3 .github/scripts/lint-action-pinning.py && zizmor .github/workflows/update-agent-runtime-pins.yml && python3 scripts/lint-spec-files.py --all && git diff --check
```
## Files likely touched
- `.github/workflows/update-agent-runtime-pins.yml`
- `.github/scripts/update-agent-runtime-pins-workflow-contract_test.py`
- `docs/specs/agents/requirements/runtime-updates.md`
- `docs/specs/agents/system-design/runtime-updates-01.md`
- `docs/plans/managed-runtime-version-awareness/task-04-weekly-pin-workflow.md`
## Dependencies
None.
## Risks
- The repository or organization setting **Allow GitHub Actions to create and
approve pull requests** must be enabled for the PR mutation.
## Parallelism
`sequential`
## Inputs
- [Managed runtime requirements](../../specs/agents/requirements/runtime-updates.md).
- [Managed runtime system design](../../specs/agents/system-design/runtime-updates-01.md).
- [Token decision](../../decisions/2026-09-04-use-repository-token-for-runtime-pin-prs.md).
- [Scoped GitHub Actions guidance](../../../.github/AGENTS.md).
## Results
Implemented the repository-scoped `GITHUB_TOKEN` boundary and removed the
unconfigured GitHub-App token step. The workflow retains trusted-main checkout,
validation before mutation, the stable updater branch, grouped PR behavior, and
no auto-merge. It explicitly dispatches the six required validation workflows
after creating or refreshing the PR, and the target workflows accept the manual
event. The contract test covers the token, permissions, target list, and target
triggers.
Verification passed:
- `node --test scripts/update-agent-runtime-pins.test.mjs`: 7/7.
- `python3 .github/scripts/update-agent-runtime-pins-workflow-contract_test.py`: 9/9.
- `python3 .github/scripts/lint-action-pinning_test.py`: 9/9.
- `python3 .github/scripts/lint-action-pinning.py`: 21 workflows accepted.
- `zizmor .github/workflows/update-agent-runtime-pins.yml`: no findings.
- `python3 scripts/lint-spec-files.py --all`: all specification files passed.
- `git diff --check`: passed.
@@ -136,8 +136,11 @@ opens reviewable pin-update PRs without changing runtimes automatically.
logic independently testable with fixture metadata and no network.
- Add `.github/workflows/update-agent-runtime-pins.yml` with weekly and manual
triggers, least-privilege permissions, pinned action SHAs, a stable bot
branch, and one grouped Conventional Commit PR. Use a repository-approved
bot/App token so the generated PR receives normal CI events. Do not auto-merge.
branch, and one grouped Conventional Commit PR. Use the repository-scoped
`GITHUB_TOKEN` with contents, pull-request, and workflow-dispatch write
permissions. Explicitly dispatch the six required validation workflows
against the bot branch because built-in-token branch and PR events do not
recursively start them. Do not auto-merge.
- Run the updater tests, targeted managed-runtime Go tests, action-pinning lint,
and workflow contract test before opening a PR. When no pin changes, exit
without a branch or PR mutation.
@@ -220,8 +223,11 @@ The follow-up review pass updates terminal `current_version` from the
successful capability probe, makes the UI prefer terminal `effective_version`
and retain the complete backend version projection, derives managed-runtime
test expectations from the catalogue, and validates those commands before the
weekly workflow commits or pushes. It also keeps the App token on the push
step and refreshes existing updater PRs by number.
weekly workflow commits or pushes. It also keeps the repository token on the push
step and refreshes existing updater PRs by number. The authentication follow-up
replaces the unconfigured App token with the repository-scoped `GITHUB_TOKEN`,
adds explicit dispatch of all required validation workflows, and records the
repository Actions setting prerequisite.
Follow-up verification passes 2,594 focused backend tests, 32 focused web
tests, full web lint/typecheck/i18n, 7 pin updater tests, 8 workflow-contract
@@ -279,6 +285,6 @@ Task 06 owns E2E fixtures and specs.
- Registry checks must not delay application boot or agent launches. They are
page-triggered, read-only, cached, and separate from the agent catalogue boot
payload.
- A bot-created PR must trigger the repository's normal required checks. The
workflow must not silently fall back to `GITHUB_TOKEN` behavior that suppresses
those PR events.
- Built-in-token branch and PR events do not recursively start validation
workflows. The updater dispatches each required check explicitly, and the
repository or organization must allow Actions to create and approve PRs.
@@ -16,7 +16,10 @@ spec: "../../specs/agents/requirements/runtime-updates.md"
npm `latest` versions and handles no-change, prerelease, malformed, and lookup
failure cases without partial writes.
- A weekly/manual least-privilege workflow runs validation and opens at most one
grouped Conventional Commit PR through a token that permits normal PR CI.
grouped Conventional Commit PR through the repository-scoped `GITHUB_TOKEN`.
Because built-in-token branch and PR events do not recursively start
workflows, it explicitly dispatches the six required validation workflows
against the exact updater branch commit.
- The workflow uses pinned actions, never auto-merges, and has a contract test
wired into the repository's action-pinning workflow.
@@ -59,16 +62,20 @@ local tests), risks, and synchronized task/plan status.
Complete. The updater changes only existing trusted catalogue entries, rejects
missing, malformed, and prerelease values before its atomic write, and the
weekly/manual workflow uses a pinned GitHub App token, a stable bot branch, one
grouped PR, and no auto-merge or `GITHUB_TOKEN` fallback.
weekly/manual workflow uses the repository-scoped `GITHUB_TOKEN`, a stable bot
branch, one grouped PR, and no auto-merge. It explicitly dispatches the six
required validation workflows after creating or refreshing the grouped PR; each
target workflow accepts `workflow_dispatch`.
Verification: updater tests passed 7/7; workflow contract tests passed 8/8;
action-pinning tests passed 9/9 and the linter accepted all 19 workflow files;
`zizmor .github/workflows/update-agent-runtime-pins.yml` reported no findings.
Local checks caused no external workflow or PR side effects.
Follow-up review verification keeps the App token in the push step, edits an
existing updater PR by its number, and runs the focused managed-runtime Go
suite after the catalogue update and before any commit or push. The workflow
contract now asserts that validation boundary; the contract passed 8/8 and
the action-pinning checks remained green.
Follow-up review verification configures the repository token for Git, push, PR,
and workflow-dispatch steps, edits an existing updater PR by its number, and
runs the focused managed-runtime Go suite after the catalogue update and before
any commit or push. The workflow contract now asserts the validation and token
boundaries; the contract passed 9/9 and the action-pinning checks remained
green. The repository or organization Actions setting must allow workflows to
create and approve pull requests.
@@ -2,7 +2,7 @@
status: active
system: agents
created: 2026-07-26
updated: 2026-08-22
updated: 2026-09-04
owners:
- Kandev
---
@@ -28,6 +28,8 @@ Operators need newly released agent models without waiting for a Kandev release.
- **AC-AGENTS-RUNTIME-UPDATES-001.6:** Kandev does not persist the default as a selection. An installation without an operator selection follows default-pin changes delivered by later Kandev releases.
- **AC-AGENTS-RUNTIME-UPDATES-001.7:** Every Kandev-built ACP command for the managed package uses the effective exact version, including probes, utility calls, standalone sessions, containers, and SSH executors. Active sessions continue unchanged.
- **AC-AGENTS-RUNTIME-UPDATES-001.8:** Settings lets the operator clear the selected version and return to the Kandev default after that default passes the normal candidate validation.
- **AC-AGENTS-RUNTIME-UPDATES-001.9:** When the weekly or manually started pin-maintenance run finds a changed stable default, it validates the catalogue and opens or refreshes one grouped review pull request without activating a runtime or merging the pull request. When no default changes, it creates no branch or pull request.
- **AC-AGENTS-RUNTIME-UPDATES-001.10:** The pin-maintenance run operates with the repository's built-in Actions authorization and does not require a separately provisioned GitHub App or personal access token. Because built-in-token branch and pull-request events do not recursively start validation workflows, the run explicitly dispatches the six required validation workflows against the exact updater branch commit after creating or refreshing the pull request. The repository or organization setting **Allow GitHub Actions to create and approve pull requests** must be enabled, and verification checks that setting.
## System design
@@ -4,7 +4,7 @@ system: agents
requirements:
- REQ-AGENTS-RUNTIME-UPDATES-001
created: 2026-07-26
updated: 2026-08-24
updated: 2026-09-04
owners:
- Kandev
---
@@ -477,6 +477,46 @@ authoritative for launch-time stale metadata recovery.
- Managed npm runtime recovery scenarios follow the authoritative
[recovery requirement](requirements/managed-npm-runtime-recovery.md).
## Scheduled pin-update workflow
The weekly and manual pin-maintenance path satisfies
`AC-AGENTS-RUNTIME-UPDATES-001.9` and
`AC-AGENTS-RUNTIME-UPDATES-001.10`. The trusted catalogue is updated by
[`scripts/update-agent-runtime-pins.mjs`](../../../scripts/update-agent-runtime-pins.mjs)
and orchestrated by
[`update-agent-runtime-pins.yml`](../../../.github/workflows/update-agent-runtime-pins.yml).
The workflow checks out `main`, runs the updater and managed-runtime validation
before any branch mutation, and then pushes the stable
`automation/update-managed-runtime-pins` branch only when the catalogue
changed. It creates or refreshes one grouped review pull request and never
merges it or activates a runtime.
The workflow uses the repository-scoped built-in `GITHUB_TOKEN`. Its effective
permissions are limited to `contents: write`, `pull-requests: write`, and
`actions: write`. `gh auth setup-git` configures the token after the trusted
checkout. No GitHub-App variable, private-key secret, or personal access token
is required. The workflow keeps `persist-credentials: false` on checkout and
does not run pull-request-controlled code.
GitHub does not recursively start `push` or `pull_request` workflows for events
created with `GITHUB_TOKEN`. Each required validation workflow therefore also
declares `workflow_dispatch`, and the pin-maintenance workflow explicitly
dispatches these workflows against the exact
`automation/update-managed-runtime-pins` commit after the grouped PR exists:
`backend-tests.yml`, `frontend-tests.yml`, `e2e-tests.yml`,
`architecture-lint.yml`, `lint-action-pinning.yml`, and
`lint-harness-files.yml`. The manual architecture run derives its baseline from
the fork point with `main`; the other validation gates fail open to a full run
when a manual event has no push or pull-request base. This keeps the six
required check contexts reportable without a separate App or PAT.
The repository or organization setting **Allow GitHub Actions to create and
approve pull requests** must remain enabled for the built-in token to create or
refresh the grouped PR. GitHub may still apply its approval policy to generated
workflow runs; that policy is operationally distinct from the event-suppression
problem solved by explicit dispatch.
## Out of scope
- Automatic runtime installation, automatic operator-selection changes, and