Take over each verified release of the issue assistant with a bot of the blueprint, not with Renovate¶
- Status: accepted
- Date: 2026-10-14
Context¶
The four workflows of the issue assistant, issue-assistant.yml, issue-lifecycle.yml, labels.yml and findings.yml, and its firewall policy .github/egress-firewall.yaml are templates of its release. Its command check, which the required check issue-assistant of the Lint workflow runs in the version that it pins, compares the workflows of a repository with the templates of that version, ignoring only the refs of the actions. The blueprint keeps copies of these files in .github/, and every repository made from it renders them, so they belong to the blueprint: a repository that changed them would lose the change with the next update.
Taking a release over took a person: install of the release in the root of the blueprint, the firewall policy copied by hand, since install keeps a policy that a repository has already, and the pin of the check in the Lint workflow moved as well. Renovate would only have moved the pins, and with templates that changed, its pull request fails the check that it updates. So releases of the issue assistant, with their security fixes, reached no repository for days, and the blueprint pinned a release that its release workflow had not even made. Since issue-assistant 1.3.0, its templates live in templates/ and a pull request there can change them; the train from a change of a template to every repository needed its last step automated.
Options¶
- Renovate moves the pins, and a person copies the templates. Two pull requests, one of which fails until the other merges, and every release waits for a person.
- The blueprint renders the workflows from the issue assistant at copy time, with Copier. Copier would need the network and a release of the issue assistant during every copy and update, and the blueprint could no longer check what it brings.
- A bot of the blueprint takes over each release as a person would, once it has verified the release, and keeps one pull request with the result; Renovate leaves the issue assistant alone.
Decision¶
Option 3. The Issue assistant sync (.github/workflows/sync-issue-assistant.yml, in the blueprint alone) takes the latest published release of the issue assistant every morning and on demand, and verifies it as the blueprint bot verifies a release of the blueprint (0020): the release is immutable, GitHub's attestation of it holds (gh release verify), its tag points at a commit of the issue assistant's main, and the release workflow of the issue assistant signed the tag, as .github/sign-tag.sh verify checks it. Any other release fails the run before anything is installed. Then sync_issue_assistant.py adopt runs install of exactly the verified commit in the root of the blueprint, takes over the firewall policy of templates/, moves every pin of the action to the release, also those outside the four templates, and gives a workflow that is new in the release the file in template/.github/workflows/ that renders it. A release whose install changes any other file fails the run, and the maintainer takes it over by hand.
Installing runs in a job without secrets. The job of the pull request has the release app and runs nothing of the release: sync_issue_assistant.py of main takes from the artifact only workflows, the firewall policy and the files of the template that render workflows, by plain paths, and commits them through GitHub's API onto the commit that was installed on. The pull request, fix(deps): update the issue assistant to vX.Y.Z from bot/issue-assistant, merges itself once every check passes; it is a fix, so that the blueprint releases it, and one of dependencies, so that a release of nothing else publishes itself. The bot moves an open pull request on to a newer release, closes it when main has the release without it, and leaves a branch alone once someone else committed to it. The rules of Renovate in every repository disable the updates of Dennis-Otto/issue-assistant. The bot checks itself in every pull request that changes it, with a dry run that verifies and installs the latest release without a pull request.
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TB
accTitle: How a release of the issue assistant reaches every repository
accDescr: Every morning, the sync bot of the blueprint takes the latest published release of the issue assistant and verifies it: the release must be immutable, GitHub's attestation of it must hold, its tag must point at a commit of the main branch of the issue assistant, and its release workflow must have signed the tag. Any other release fails the run, and nothing changes. Otherwise the bot runs install of the release in the root of the blueprint, which writes the four workflows and the firewall policy of the release and moves every pin of the action, and keeps one pull request with the result, which merges itself once every check passes. The next release of the blueprint brings it to every repository with the blueprint bot.
release(["A release of the<br>issue assistant"])
bot(["Sync bot<br>every morning"])
verified{"Immutable, attested,<br>on main, signed by<br>its release workflow?"}
refused(["Fails the run<br>nothing changes"])
install["install of the release<br>in the blueprint: the four workflows,<br>the firewall policy, every pin"]
pr["Pull request from<br>bot/issue-assistant<br>merges itself once<br>every check passes"]
blueprint["The next release<br>of the blueprint"]
fleet["Every repository,<br>with its blueprint bot"]
release --> bot
bot -- "the latest<br>published release" --> verified
verified -- "no" --> refused
verified -- "yes" --> install --> pr --> blueprint --> fleet
classDef bot fill:#526cfe2e,stroke:#526cfe,stroke-width:2px
classDef person fill:#f59e0b2e,stroke:#f59e0b,stroke-width:2px
classDef done fill:#16a34a2e,stroke:#16a34a,stroke-width:2px
class bot,install,pr,blueprint bot
class release,refused person
class fleet done
Consequences¶
A release of the issue assistant reaches the blueprint within a day, and every repository with the next release of the blueprint and its Rollout, without a person; its check runs in the same version as its workflows. The review of the release pull request of the issue assistant is the last look of a person at a change of its templates, since a release of the blueprint with only this update publishes itself. A release that its release workflow didn't make, such as one of the releases before the issue assistant took the release workflow of the blueprint over, never reaches the blueprint; the bot fails on it every morning until a release that passes is out, and the bot-health bot (0019) keeps one issue open about it, with the reason of the refusal.
When a release needs more than install, such as a check of the blueprint that has to learn something new of the templates, the pull request fails that check, and the maintainer commits the adaptation to its branch, which the bot then leaves alone; the adaptation for the queue of a concurrency group, which actionlint 1.7.12 doesn't know, is in .github/actionlint.yaml already. A starter file that is new in a release, such as a new settings file, fails the run, since the blueprint renders those from templates of its own, config.toml with the hosts of each kind of project for example, and only a person can bring it into the template.