Automatisierung¶
Wie sich dieses Repository selbst pflegt: seine 33 Workflows von GitHub Actions in .github/workflows/ prüfen jede Änderung, machen ein Release aus dem, was main erreicht, beantworten Issues und Pull Requests, suchen nach Schwachstellen und halten das Repository aktuell. Die Website schreibt diese Seite bei jedem Build aus den Workflows, mit dem englischen Kommentar am Anfang jedes Workflows, und bleibt so immer auf ihrem Stand.
Was ein Pull Request braucht¶
Ein Pull Request kommt nach main, sobald jede dieser Prüfungen besteht, wie es die Einstellungen in .github/repository.toml und .github/repository.project.toml verlangen:
check (node)aus CI (node)lintaus Lintdiagramsaus Lintdocsaus Docsconventional titleaus Pull request titlecodeqlaus CodeQLdependency-reviewaus Dependency reviewgitleaksaus Secret scan
Auf einen Blick¶
Die Zeiten sind UTC. GitHub startet einen geplanten Lauf, wenn es kann: oft einige Minuten später und zu Spitzenzeiten auch gar nicht.
| Workflow | Wann |
|---|---|
| CI (node) | jeder Push auf main, jeder Pull Request, jeden Mittwoch um 04:27 UTC, von Hand |
| Diagrams | jeder Push auf main, der bestimmte Dateien ändert, jeden Dienstag um 04:42 UTC, von Hand |
| Docs | jeder Push auf main, jeder Pull Request, jeden Samstag um 06:20 UTC, von Hand |
| Links | jeder Push auf main, der bestimmte Dateien ändert, jeder Pull Request, der bestimmte Dateien ändert, jeden Montag um 05:47 UTC, von Hand |
| Lint | jeder Pull Request, jeden Mittwoch um 04:27 UTC, von Hand |
| Newest Node | jeder Push auf main, jeden Dienstag um 03:37 UTC, von Hand |
| Pull request title | jeder Pull Request |
| Build the release | wenn ein anderer Workflow ihn aufruft |
| Release | jeder Push auf main, jeden Tag um 05:22 UTC, von Hand |
| SBOM | jeden Mittwoch um 04:44 UTC, von Hand |
| Release verification | wenn ein anderer Workflow ihn aufruft, jeden Mittwoch um 05:14 UTC, ein Release, von Hand |
| After the checks | nach 13 Workflows |
| Area labels | jeder Pull Request |
| Blueprint update | jeden Dienstag um 04:37 UTC, von Hand |
| Build the image | wenn ein anderer Workflow ihn aufruft |
| Commands | Kommentare |
| Dependabot maintenance | jeder Pull Request |
| Issue assistant | neue und geänderte Issues, Kommentare, von Hand |
| Issue lifecycle | jeden Tag um 06:41 UTC, jeder Pull Request, ein Release, nach 2 Workflows, von Hand |
| Screenshots | jeder Push auf main, nach einem Lauf von Release, jeden Freitag um 04:26 UTC, von Hand |
| Update branches | jeder Push auf main, jeder Pull Request, nach 12 Workflows, alle 6 Stunden um :07, von Hand |
| Welcome | jeder Pull Request |
| CodeQL | jeder Push auf main, jeder Pull Request, jeden Mittwoch um 04:14 UTC, von Hand |
| Dependency review | jeder Pull Request, von Hand |
| Findings | jeden Tag um 07:17 UTC, jeder Push auf main, der bestimmte Dateien ändert, nach 4 Workflows, von Hand |
| OSV-Scanner | jeder Pull Request, der bestimmte Dateien ändert, jeder Push auf main, jeden Montag um 05:30 UTC, von Hand |
| OpenSSF Scorecard | jeder Push auf main, jeden Sonntag um 03:44 UTC, von Hand |
| Secret scan | jeder Pull Request, jeden Freitag um 04:52 UTC, von Hand |
| Workflow security | jeder Push auf main, jeder Pull Request, jeden Dienstag um 05:32 UTC, von Hand |
| Bot health | nach 27 Workflows, jeden Tag um 01:44 UTC, von Hand |
| Clean-up | jeden Sonntag um 05:37 UTC, von Hand |
| Labels | jeder Push auf main, der bestimmte Dateien ändert, von Hand |
| Settings | jeder Push auf main, der bestimmte Dateien ändert, jeden Donnerstag um 06:02 UTC, von Hand |
Prüfungen¶
Sie prüfen jede Änderung, bevor sie main erreicht.
CI (node)
Node: the locked packages of package-lock.json and the checks of scripts/check.sh, the same ones that run locally. The Node version comes from .nvmrc.
- Wann: jeder Push auf
main, jeder Pull Request, jeden Mittwoch um 04:27 UTC, von Hand - Pflichtprüfungen:
check (node) - Quelle:
.github/workflows/ci.yml, aus dem Repo Blueprint
Diagrams
The diagram bot of main. The GitHub app, the stores and other renderers of Markdown show a ```mermaid block as code, so every diagram is a picture of its source in docs/diagrams/, and the check diagrams of each pull request keeps it that way. When main still has a ```mermaid block, a missing or stale picture, or a picture without its source, after the update of the blueprint that brought the pictures, a merge that went around the check or a change of the renderer, this workflow draws the diagrams with scripts/diagrams.sh --extract and keeps one pull request with the fix from the branch bot/diagrams, as the release app, which merges itself once every check passes. It runs after every change of main that touches a diagram or a page of Markdown, and every week; when main is fixed otherwise, it closes the pull request. Drawing runs without secrets; only the job of the pull request has the release app, and runs nothing that it drew; without the release app, the run warns and names the command that fixes main. A failed run opens an issue, which the next weekly run closes once the bot passes again.
- Wann: jeder Push auf
main, der bestimmte Dateien ändert, jeden Dienstag um 04:42 UTC, von Hand - Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY - Quelle:
.github/workflows/diagrams.yml, aus dem Repo Blueprint
Docs
The documentation website. MkDocs with the Material theme builds it from mkdocs.yml and the pages in docs/, strictly, so that a link or an anchor that leads nowhere fails: in every pull request as the check docs, and on main, where the same job hands the website that it built to GitHub Pages, and a second one publishes it. A repository without mkdocs.yml or a home page in docs/ has no website, and the check passes, so that it can be required everywhere. Where another workflow publishes GitHub Pages, as the Dashboard of the blueprint does with its dashboard, a run on main only builds the website; in a fork, where the Dashboard doesn't run, Docs publishes it. A pull request keeps the website that it built as the artifact website for a week, which the report of the PR coach links. The tools are the hash-pinned ones of .github/docs-requirements.txt, which the blueprint keeps current, and the files that Material downloads for the website stay in a cache for a week. After the build, lychee checks every link and anchor of the pages that were built and the links of llms.txt, the map of the website for AI assistants, blueprint.py site-check what the hooks of the website promise, and axe-core the pages in the light and the dark scheme, at the width of a desktop and of a phone, for what WCAG 2.2 A and AA ask, also that no page scrolls sideways on a phone, with the locked tools of .github/a11y/: on a pull request those that differ from main, by the digest that main keeps in the cache, and on main and every week every page. A serious or critical violation fails the check, unless .github/a11y-accepted.toml accepts it with its reason. The job that publishes the website signs its provenance, and the job website, which holds no token, asks the published website for its pages.
- Wann: jeder Push auf
main, jeder Pull Request, jeden Samstag um 06:20 UTC, von Hand - Pflichtprüfungen:
docs - Umgebungen:
github-pages - Quelle:
.github/workflows/docs.yml, aus dem Repo Blueprint
Links
The link bot. lychee checks the links of the documentation, and the anchors that they lead to, also in the README of another repository, on every change of a Markdown file or of a page of HTML in docs/, and every week, since sites move without a change here. A pull request checks the documents that it changes, so that a site that is down for a moment fails only the pull requests that link to it; one that changes the rules or lychee itself, such as an update of its version in .github/lychee.sh, or moves or deletes a file checks every document, as main and the weekly run do. The answers of the sites stay in a cache for a day. A broken link fails the check of a pull request; the weekly run keeps one issue with the broken links open until they are fixed, and closes it then. lychee.toml holds the rules, .lycheeignore the exceptions of this repository. The entry in the changelog that most pull requests bring, in CHANGELOG.md or in a fragment of changelog.d/, starts no check on its own; the weekly run checks the links of the changelog.
- Wann: jeder Push auf
main, der bestimmte Dateien ändert, jeder Pull Request, der bestimmte Dateien ändert, jeden Montag um 05:47 UTC, von Hand - Quelle:
.github/workflows/links.yml, aus dem Repo Blueprint
Lint
The checks every repository of the blueprint shares: the workflows, the license of every file (REUSE), the Markdown of every document with hints at its spelling and style, the pictures of its diagrams, the sign-off of every commit (DCO), the set-up of the issue assistant and a notice for each changed file of the blueprint. In every pull request, not after a merge: main takes a pull request only when it is up to date, so a merge gives main the files that the pull request passed with. And each week on main, for what no commit changes, such as a new rule of a tool: it fails here and repairs itself through the fix bot, not in the next pull request.
- Wann: jeder Pull Request, jeden Mittwoch um 04:27 UTC, von Hand
- Pflichtprüfungen:
lint,diagrams - Quelle:
.github/workflows/lint.yml, aus dem Repo Blueprint
Newest Node
The checks of scripts/check.sh with the newest release of Node, which warns early of what the next Node breaks, while the CI checks the Node of .nvmrc: after every change of main and every week. check-latest takes it from the releases of Node as soon as it is out, not the older Node that the image of the runner keeps in its cache. Not in pull requests: a new Node breaks main and every pull request alike, and no pull request waits for this check. A workflow of its own, so that its warning leaves the CI of main green, whose coverage the report of the PR coach compares every pull request with. Since no pull request shows the warning, a failure keeps one issue open, which names the Node that failed and which the weekly run closes once the checks pass again.
- Wann: jeder Push auf
main, jeden Dienstag um 03:37 UTC, von Hand - Quelle:
.github/workflows/newest-node.yml, aus dem Repo Blueprint
Pull request title
Pull requests are squashed into one commit named after their title, and the release bot builds the version and the changelog from these names. So the title must be a Conventional Commit; its type also sets the label of the pull request. A pull request that changes something for users, a feat, fix or perf, also says so in a fragment of the changelog, a new file in changelog.d/, or under Unreleased in CHANGELOG.md, which becomes the notes of the release.
The check signed commits is here because this event starts on every push, also from a fork whose other workflows wait for the approval of a maintainer, and costs only a question to the API: where the rules of the base branch require signed commits, it fails for each commit of the pull request without a signature that GitHub verified, as GitHub then blocks the merge. It stays out of the required checks: GitHub's own rule already blocks that merge, and a required check would change the settings of every repository for nothing (decision 0098).
The bot for replaced commits is a step of that job for the same reason: the run of a commit that a newer push replaced tells nobody anything, yet it holds a runner of the account, and this job runs on every push anyway, so the bot needs no runner of its own (decision 0108). It cancels only runs of the checks whose commit no open pull request has as its head; the branch bot does the same for the pull requests that merge.
- Wann: jeder Pull Request
- Pflichtprüfungen:
conventional title - Quelle:
.github/workflows/pull-request-title.yml, aus dem Repo Blueprint
Releases¶
Sie machen aus dem, was main erreicht, ein signiertes Release, liefern es aus und prüfen es so, wie seine Nutzer es können.
Build the release
The build of a release, called by the release workflow only: it packages the release, writes the SBOMs of what it ships, the licenses of its third-party components and the advisories that don't affect it, attests the signed provenance of every asset and attaches all of it to the draft. As a reusable workflow of its own, it is isolated from the rest of the release workflow, and the provenance names it as the build, as SLSA Build Level 3 asks; verify-release.yml checks that. A project that ships something of its own, such as the zip of a browser extension, builds it with its scripts/release-assets.sh, in a job of this workflow that may write nothing, and the release attests and attaches it like every other asset.
- Wann: wenn ein anderer Workflow ihn aufruft
- Secrets:
APP_PRIVATE_KEY - Quelle:
.github/workflows/build-release.yml, aus dem Repo Blueprint
Release
The release bot. release-please keeps a pull request for the next release, up to date with main. Its version follows from the Conventional Commit titles merged since the last release (fix: a patch, feat: a minor, ! or BREAKING CHANGE: a major version) and is decided anew with every merge. What the pull requests wrote in the fragments of changelog.d/ and under "## Unreleased" of CHANGELOG.md becomes the section of the release, and the fragments leave with it; without such text, the section lists the pull requests. Merging the pull request creates the release as a draft, on a tag that this workflow signs first, and the build checks the tag before anything else. The jobs below attach the package, its SBOMs (SPDX and CycloneDX), the licenses of its third-party components, the advisories that don't affect it (OpenVEX) and its signed provenance, write the notes, make the release public, announce it in the discussions, and then deliver it where the repository variable PUBLISH_TO says: pypi, npm, ghcr, hacs, nextcloud-appstore, github-action, chrome-web-store, which publish-store.yml takes over once this workflow has passed, cloudflare-workers, which Workers Builds deploys outside GitHub, or none. Last, verify-release.yml checks the release as its users can. A release that only updates dependencies merges itself once its checks pass, once a day, or at once with a fix of a vulnerability.
- Wann: jeder Push auf
main, jeden Tag um 05:22 UTC, von Hand - Umgebungen:
appstore,npm,pypi,release - Secrets:
APPSTORE_TOKEN,RELEASE_AUTOMATION_PRIVATE_KEY - Quelle:
.github/workflows/release.yml, aus dem Repo Blueprint
SBOM
A software bill of materials of the whole repository in SPDX, every week, with the tools of its checks, its website and its workflows, as an artifact of the run. A release carries the SBOMs of what it ships instead (build-release.yml), which its users' scanners read. Not for every change: no pull request reads it, and the dependency review checks what a pull request brings in.
- Wann: jeden Mittwoch um 04:44 UTC, von Hand
- Quelle:
.github/workflows/sbom.yml
Release verification
The release verification bot. It checks a release the way its users can: every asset carries the signed provenance of this repository's release workflow, both in GitHub and in the attached bundle; the SBOMs are attached and describe what the release ships, by its name and version; the release is immutable and its commit signed; and where the repository variable PUBLISH_TO delivers it, the same release is there. The release workflow runs it after every release, it checks the latest release every week, and a release that anybody else publishes, by hand or with a token, at once. A failed check fails the run, which the bot-health bot reports in an issue.
- Wann: wenn ein anderer Workflow ihn aufruft, jeden Mittwoch um 05:14 UTC, ein Release, von Hand
- Quelle:
.github/workflows/verify-release.yml, aus dem Repo Blueprint
Bots¶
Sie beantworten Issues und Pull Requests, beheben, was ein Befehl beheben kann, und bringen die Pull Requests voran.
After the checks
The bots that act on a finished run of the checks and of the release. One workflow for all, so that every run starts one run after it, not one for each bot that mostly has nothing to do. None checks out or runs the code of a pull request.
The flaky-test bot: when a run of the tests fails for the first time, or a job of it runs out of time, it runs the failed jobs once more. A job that passes then failed without a change of the code: its test is flaky, and the bot reports it in one issue, with the step, the test and the error that failed, so that it gets fixed instead of failing pull requests at random: a comment for each run, and in the body how often each job and test flaked, and when it last did. The test is one that pytest names in the log, or else the step or test that the log names last before the failure, after the answer test_marker of the blueprint, such as "Browser step:" before each step of the tests of a browser. A job that fails again is a real failure and stays red, and so does one that failed the same way for the commit before: running it again would only keep a runner busy. A run whose failed jobs ran no step, which GitHub couldn't start, as in its outage of 9 November 2026, it leaves alone with a notice: another try while GitHub fails would only fail and mail again, and a bot that GitHub keeps failing ends with a notice as well (decision 0136). A pull request names its jobs and steps and writes its logs, so the issue shows them only as code, and the branch of a fork not at all.
The bot for cancelled checks: a newer run of a workflow cancels the one still running for the same pull request, and that of a check or a scanner for the push to main before. GitHub doesn't always create the runs in the order of the commits, so a late run for an older commit can cancel the run for the head of the pull request, whose required checks then stay cancelled and block the merge, or that for the head of main, whose coverage, alerts of code scanning and fixes the bots read. When a run for the head of an open pull request or of main was cancelled that way and no newer run of its workflow for the same commit exists, the bot starts it again. A run that a person cancelled, or one whose commit a newer push replaced, stays cancelled. The quick checks avoid the race: their runs for different commits never cancel each other. A job of the first attempt that ran out of time, as one behind Harden-Runner can even after its last step, runs once more, where the flaky-test bot doesn't do it.
A run of a commit that a newer push replaced, or whose pull request has closed, starts no job here that would only find that out, as the concurrency of a workflow and the bot for replaced commits cancel such runs by the hundred on a busy day. The event names the open pull requests of the branch of a run from this repository, so that their heads tell it before a runner starts; a run from a fork names none, and its jobs ask GitHub, as before.
The bot for failed releases: when the release that a merge started fails, such as at a push of its tag that GitHub refused for a moment, it runs the failed jobs once more, where they stopped, instead of leaving the release and its rollout to a person. The release workflow takes up a tag that it pushed already. A release that a person or another bot already runs again, or ran again, is theirs: the bot leaves it alone, and so it does a release that GitHub couldn't start, which the scheduled run of the release takes up.
The PR coach: after every run of the checks of a pull request, one comment on it explains each check that failed: what it found, why that matters and how to fix it, with the commands to run, from the explanations of .github/checks.toml and .github/checks.project.toml. It works for a pull request from a fork as well, whose own runs can't write to it. The comment follows every push and turns into a short all-clear once every check passes. A check that was cancelled, as a job that ran out of time is, hasn't passed either, and commits that block the merge, because the rules of its base branch require a verified signature that they lack, allow no all-clear and no word about the merge, also before their check signed commits has ended: the coach asks GitHub for them itself. It reads the check runs and their annotations from the API and shows their text only as code, and waits up to three minutes for the checks of other apps, such as the alerts of code scanning, which end after the last workflow. The scanners, which run in the pull requests that change what they read, start it as well, and so does the check of the rules of Renovate where Renovate runs in the repository. On a pull request of a person, the comment also says what the pull request makes: the next version, from its title and the release-please files of main, and the entry that it adds to the changelog; the coverage of its tests against that of main, file by file, from the coverage reports that the checks keep as the artifact "coverage", which a pull request from a fork writes as it likes; the website that the check docs built, with the pages that it changes; and the part that a workflow of the project adds, such as one of visual tests: the report.md of its artifact pr-report-<name> for the head, under the title that [report.<name>] of .github/checks.project.toml of main gives it, with its text only as code. A pull request whose checks never failed gets the comment only when it has something of this to say, and one of a bot never.
The fix bot: a check whose findings a command fixes, such as the format of the code, the whitespace of a text file or the rules of markdownlint, runs the commands of autofix in .github/checks.toml when it fails, on the head of the pull request or on main, and keeps the files that they changed as an artifact fixes-*. A check in any workflow of the list below may do so, also in one of the project's own, and no other workflow can: the list of main decides. Once the checks of the commit whose workflows on main keep fixes have ended, the bot takes these files as data: on a pull request from a branch of this repository, also one of Renovate or another bot, it commits them as one commit onto the branch, as the release app, so that the checks run again; on one from a fork, which this bot never pushes to, it suggests them at their lines, at most ten in one review, never one twice, and a person with write access asks for the commit there with /fix, in commands.yml; on main, it keeps one pull request from bot/self-heal with them, which merges itself, and closes it once main needs no fix. Lint and the CI also run on main each week, by their schedule or by hand, as bot health starts a schedule that GitHub missed, so that what no commit changes, such as a new rule of a tool, repairs itself the same way before it fails the next pull request; a weekly run that passes starts no job here, so a quiet week takes no runner of the bot. blueprint.py of main lets through only text files that the commit has already, outside .git and the workflows. It commits at most twice in a row onto its own commits, and leaves a pull request with the label no-bot-fixes alone. When the bot fails, it says so on the pull request; on main, it keeps one issue open until it passes again. A check still running after the wait, such as long end-to-end tests, leaves the commit to the job after its own end, however it ends: so that job starts after every run of a check for the head of a pull request from a branch of this repository, and ends at once when the commit has no fix. A commit before would cancel that run and use up one of the two commits. A fork and main act on what has ended, since a suggestion and the pull request of main cancel no run.
The title and the entry of the changelog fix themselves in a job of their own, after a failed run of the check of the title, on a branch of this repository: the bot sets the title that the PR coach suggests when only its form differs, as the type and the breaking mark decide the version, and commits one draft of the missing entry from that title, once for each pull request. The draft is the one new file that a bot of the fixes adds, which blueprint.py of main names and writes itself in changelog.d/. No artifact and nothing of the code of a pull request reaches this job.
The diagram bot: when the check diagrams of Lint finds a ```mermaid block, which the GitHub app shows as code, or pictures of diagrams that differ from their sources in docs/diagrams/, in a pull request from a branch of this repository, it commits what scripts/diagrams.sh --extract changed in the check onto that branch, as the release app, so that the checks run again, and says in a comment which blocks became pictures. blueprint.py of main takes only sources, SVG pictures and pages of Markdown from the artifact "diagrams". When the bot can't commit, it says so on the pull request, with the command. A pull request from a fork keeps the failing check, with the command that fixes it.
- Wann: nach einem Lauf von CI (node), Docker E2E, CodeQL, Dependency review, Docs, Lint, Pull request title, Secret scan, Fuzzing, Links, OSV-Scanner, Workflow security oder Release
- Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY - Quelle:
.github/workflows/after-checks.yml, aus dem Repo Blueprint
Area labels
The labeler bot. It gives a pull request the labels of the areas whose files it changes, by the paths in .github/labeler.yml, and takes them away when it no longer changes them. The type label comes from the title check.
- Wann: jeder Pull Request
- Quelle:
.github/workflows/area-labels.yml, aus dem Repo Blueprint
Blueprint update
The blueprint bot. Every week, and on demand, it brings the repository up to the latest published release of the blueprint with copier update, once it has verified that the release workflow of the blueprint made that release, and keeps one pull request for it as the release app, so that its checks run: a newer release moves that pull request on. Without conflicts, it merges itself once every check passes; conflicts stay in it as markers for the maintainer, with auto-merge off. Once the maintainer commits to its branch, the bot leaves the branch alone. The repository variable BLUEPRINT_AUTOMERGE set to off makes every update wait.
- Wann: jeden Dienstag um 04:37 UTC, von Hand
- Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY,SETTINGS_APP_PRIVATE_KEY - Quelle:
.github/workflows/blueprint-update.yml, aus dem Repo Blueprint
Build the image
The build of the container image of a release, called by the release workflow only, once the release is public and where PUBLISH_TO is ghcr: it builds the image of the signed tag for linux/amd64 and linux/arm64, pushes it to the GitHub Container Registry with the tags of the version and its SBOM, and attests its signed provenance there. As a reusable workflow of its own, it is isolated from the rest of the release workflow, as build-release.yml is for the other assets, and the provenance names it as the build, as SLSA Build Level 3 asks; verify-release.yml checks that.
- Wann: wenn ein anderer Workflow ihn aufruft
- Quelle:
.github/workflows/build-image.yml, aus dem Repo Blueprint
Commands
The commands that a person gives a pull request in a comment, as its first line.
/fix: the fix bot commits the fixes of the checks of the head of the pull request onto its branch, as the release app, also onto the branch of a fork whose author allows edits by maintainers, which the fix bot after the checks only suggests at their lines. Only a person with write access to the repository starts it, as GitHub answers when the command comes; anybody else gets that answer. The bot takes the fixes that the checks of the head kept, the artifacts fixes-* of the workflows of the list of after-checks.yml of main, as data, once those that keep fixes have ended, and blueprint.py of main lets through only text files that the commit has already, outside .git and the workflows. On a fork, it commits only the files that the pull request changes and none that decides what a workflow runs, such as a file of .github/ or scripts/ or pyproject.toml, whose fix stays with a person. Whether GitHub lets the app push onto the branch of a fork isn't settled, so a refusal is no failure: the bot suggests the fixes at their lines, as a fork gets them without the command, and so it does on a fork that allows no edits. One comment answers each command, with what the bot did and why; the label no-bot-fixes stops the bot's own commits, not those that a person asks for. Nothing of the pull request runs here: the job checks out main alone.
- Wann: Kommentare
- Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY - Quelle:
.github/workflows/commands.yml, aus dem Repo Blueprint
Dependabot maintenance
Dependabot keeps only the Features of the dev container (dependabot.yml); Renovate merges its own updates, those of actions pinned to a commit of a branch included. Routine updates merge on their own once every required check passes; a major update waits for the maintainer. Updates of runtime dependencies are committed as fix(deps) and so lead to a patch release (see release.yml). Auto-merge is turned on as the release app, as Renovate's is: a merge that auto-merge does with the token of a workflow starts no workflow, so the release bot and the branch bot would wait for their schedules, which GitHub runs as it can, often hours late. The merge of the app starts them at once.
- Wann: jeder Pull Request
- Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY - Quelle:
.github/workflows/dependabot-automerge.yml
Issue assistant
A first analysis of new issues, the labels of the issue forms and the answers that the assistant or the maintainer waits for: https://github.com/Dennis-Otto/issue-assistant
The jobs are the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below. event and apply run no AI; analyze runs the engine of .github/issue-assistant/config.toml with a read-only token and read-only tools on the egress-firewall runner (.github/egress-firewall.yaml), and apply checks its answer before anything is written. The permissions below are the most that any of its jobs gets.
Without the engine's secret in the environment issue-assistant, or with the repository variable ISSUE_ASSISTANT_AI set to "off", only labels and the lifecycle work. The issue assistant's check command keeps this file equal to its template.
A run by hand, also through the REST API, answers an issue that has no comment of its task yet. Someone with write access starts it, and may add an instruction; a maintainer, with the role admin or maintain, may tick override to have the assistant answer again past its one comment. The job event checks the role of the person who started the run, and its summary records every override.
- Wann: neue und geänderte Issues, Kommentare, von Hand
- Secrets:
ANTHROPIC_API_KEY,CLAUDE_CODE_OAUTH_TOKEN,COPILOT_GITHUB_TOKEN,GEMINI_API_KEY,OPENAI_API_KEY - Quelle:
.github/workflows/issue-assistant.yml
Issue lifecycle
Without AI: reminds reporters who were asked for information after 15 days, closes their issue after 30 days without an answer, closes a possible duplicate 3 days after the notice unless someone objected, labels the issues that a merged pull request fixes, and closes them with a link once a release ships the fix. Merges and releases start it at once, and every morning catches what was missed. A fixed issue that a release closes is filed under the release's milestone. The job is the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below; it blocks every host but GitHub's. https://github.com/Dennis-Otto/issue-assistant
- Wann: jeden Tag um 06:41 UTC, jeder Pull Request, ein Release, nach einem Lauf von Release oder Release integration, von Hand
- Quelle:
.github/workflows/issue-lifecycle.yml
Screenshots
The screenshot bot. A repository turns it on with scripts/screenshots.sh, which renders its pictures in place, wherever the documentation, the stores or the social preview take them from, and lists in .github/screenshots-paths.txt the files whose change can change them, as the paths of a workflow; without the script, every run ends after its plan. After a change of main that touches a file of the list, after every release, whose version a picture may show, and every week, the plan starts a run that renders, as the branch bot and a person do by hand. That run renders the newest main, one at a time, without secrets, with Docker, the whole history and the tools of the website in .venv-docs as CONTRIBUTING.md sets them up; the script of a new repository photographs the website and, by its kind, the integration in Home Assistant or the app in Nextcloud, each in Docker. .github/screenshots.toml, which belongs to the project, can name shards, which render side by side on runners of their own, each with SCREENSHOTS_SHARD set to its name, the files besides pictures that the script renders, such as a recording that a page plays, and the hosts that the jobs that render may reach, of which Harden-Runner then lets through no other (decision 0120); it can also leave hosts out of the wait, give the script a time limit and name the folder that a failed shard keeps (decision 0124). It compares each picture that changed with the one of main by its pixels: a picture whose pixels stayed the same keeps its file, so that a new encoder, browser or runner changes nothing; for each other one of the same size and frames, it draws the changed pixels in red into diff/ of the artifact, which the bot never commits (decision 0131). When pixels changed, the job collect puts the shards together, and the bot keeps one pull request from the branch bot/screenshots, as the release app, which merges itself once every check passes, and closes it when main looks as rendered without it. When main changed a picture or a page of the pull request while it rendered, as when the pull request before merged, it starts itself anew rather than open one that conflicts; the branch bot starts it for one that conflicts later (decision 0118). The bot commits only pictures and the files of the settings, by plain paths, outside .git and the workflows, and for a picture that came out at another size the width and the height that the pages of main name for it, so that the pull request passes a check of those sizes; without the release app, the run warns and keeps the pictures as an artifact. A failed run keeps an issue of the bot-health bot open until the jobs that failed pass again in a run; a push that only plans leaves it open.
- Wann: jeder Push auf
main, nach einem Lauf von Release, jeden Freitag um 04:26 UTC, von Hand - Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY - Quelle:
.github/workflows/screenshot-bot.yml, aus dem Repo Blueprint
Update branches
The branch bot. main only takes pull requests that are up to date with it, and auto-merge doesn't update a branch by itself. So only one pull request can merge next, and each merge leaves the others behind again: bringing all of them up to date after every merge ran the checks of every waiting pull request for the one that merged. The bot keeps a line instead, the pull requests that wait for auto-merge in the order in which it was turned on, and brings only the first one up to date that can merge, as the release app, so that its checks run again and it merges once they pass. While its checks run, the others wait; its merge, or a required check of it that fails, starts the next run, and turning auto-merge on starts one at once. A pull request whose required check failed waits for a fix and leaves its place to the next one. One that conflicts with main gets the label merge-conflict and one comment. The label goes once it no longer conflicts; the comment stays for the history, so a later conflict brings back only the label. One of a bot that builds its branch anew from main, the screenshot bot, the picture bot or the issue assistant sync, gets the label and no comment, and the bot starts the workflow of that bot once for each conflict (decision 0118). A request that GitHub refuses is a warning about that pull request, and the bot goes on with the next one. The release bot keeps its own pull request current. Renovate's pull requests take their place in the line as well, which spares them the wait for its next run: Renovate commits as the release app too, so it still takes the branch for its own; one that conflicts with main it builds anew itself. A pull request from a fork takes its place as well, once its author allows edits by maintainers; without that, or with a commit that the rules of main refuse for its signature, it waits outside the line, and the summary says so. GitHub holds the runs of each new head of a fork for an approval, so such a head isn't in flight: it waits for a person and leaves its place to the next one, and the bot doesn't update it again until someone approved. Only a head that the bot made itself, on top of commits that a person approved, gets its runs approved by the bot, in the summary of the run, since nothing new from the fork runs then (decision 0099). Every merge leaves the runs of its pull request behind, and every update the runs of the commit that it replaced: after the line, the bot cancels those that no open pull request has as its head any more, as this job runs anyway (decision 0108). The bot checks out main alone, for blueprint.py, which holds the logic, and runs nothing of a pull request.
- Wann: jeder Push auf
main, jeder Pull Request, nach einem Lauf von CI (node), Docker E2E, CodeQL, Dependency review, Docs, Lint, Pull request title, Secret scan, Fuzzing, Links, OSV-Scanner oder Workflow security, alle 6 Stunden um :07, von Hand - Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY - Quelle:
.github/workflows/update-branches.yml, aus dem Repo Blueprint
Welcome
The welcome bot: a person's first pull request in this repository gets a comment with what helps it along. New issues get the issue assistant's analysis instead.
- Wann: jeder Pull Request
- Quelle:
.github/workflows/welcome.yml, aus dem Repo Blueprint
Sicherheit¶
Sie suchen nach Schwachstellen, verratenen Secrets und riskanten Abhängigkeiten.
CodeQL
The code analysis of GitHub. CodeQL reads the code of every language of this repository and its workflows with the queries of security-extended, for every pull request, every push to main and every week, and sends what it finds to code scanning, where a new alert of a pull request stops its merge. A private repository without GitHub Code Security has no code scanning: there the settings bot sets the variable CODE_SCANNING to off, and the check passes without an analysis, because the terms of CodeQL allow it on private code only with GitHub Code Security or Advanced Security.
- Wann: jeder Push auf
main, jeder Pull Request, jeden Mittwoch um 04:14 UTC, von Hand - Pflichtprüfungen:
codeql - Quelle:
.github/workflows/codeql.yml, aus dem Repo Blueprint
Dependency review
The review of the dependencies that a pull request adds or changes: one with a known vulnerability of moderate severity or more, or with a license outside the list of .github/dependency-review.yml, fails it. An advisory that the repository accepts goes into allow-ghsas there, with its reason. Started by hand, it compares two commits. A private repository without GitHub Code Security has no dependency review: there the settings bot sets the variable DEPENDENCY_REVIEW to off, and the check leaves the vulnerabilities of the lock files to OSV-Scanner. In a pull request of Renovate's weekly refresh of the lock files, which merges by itself only from versions at least a week old, it fails on a younger one as well (decision 0137).
- Wann: jeder Pull Request, von Hand
- Pflichtprüfungen:
dependency-review - Quelle:
.github/workflows/dependency-review.yml, aus dem Repo Blueprint
Findings
Without AI, every morning, after each scan of code scanning on main and when the accepted findings change: dismisses the code scanning alerts that .github/findings.toml accepts, with its reason, and fails while any other alert is open. The run names an open alert by its number and link only, which only maintainers can follow; nothing becomes a public issue. The job is the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below; it blocks every host but GitHub's. https://github.com/Dennis-Otto/issue-assistant
- Wann: jeden Tag um 07:17 UTC, jeder Push auf
main, der bestimmte Dateien ändert, nach einem Lauf von CodeQL, OpenSSF Scorecard, Workflow security oder OSV-Scanner, von Hand - Quelle:
.github/workflows/findings.yml
OSV-Scanner
Every lock file of the repository against the OSV database of known vulnerabilities: in every pull request that changes a lock file the vulnerabilities that it brings in, and on main and every week all of them. Findings go to code scanning, where the Findings workflow keeps them fixed or accepted; osv-scanner.toml lists those that the project accepts, each with its reason, such as an advisory in a test base that pins its dependencies. Dependabot doesn't read that file: on main, every week and by hand, the job dependabot alerts closes each Dependabot alert that an acceptance covers, with its reason and its end, and opens again each one that it closed once the acceptance is gone.
- Wann: jeder Pull Request, der bestimmte Dateien ändert, jeder Push auf
main, jeden Montag um 05:30 UTC, von Hand - Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY,SETTINGS_APP_PRIVATE_KEY - Quelle:
.github/workflows/osv-scanner.yml, aus dem Repo Blueprint
OpenSSF Scorecard
The OpenSSF Scorecard: it rates the security practices of the repository, such as its branch protection, its pinned actions and its signed releases, after every push to main and every week, publishes the score for the badge of the README and sends each finding to code scanning.
- Wann: jeder Push auf
main, jeden Sonntag um 03:44 UTC, von Hand - Quelle:
.github/workflows/scorecard.yml, aus dem Repo Blueprint
Secret scan
Gitleaks looks for secrets in the commits of every pull request, and every week in the whole history of every branch. Not after a merge, which brings only the commits of a pull request that it scanned; GitHub's secret scanning with push protection guards every push as well.
- Wann: jeder Pull Request, jeden Freitag um 04:52 UTC, von Hand
- Pflichtprüfungen:
gitleaks - Quelle:
.github/workflows/secret-scan.yml, aus dem Repo Blueprint
Workflow security
zizmor checks every workflow for the ways a workflow gets attacked: template injection, permissions wider than needed, credentials that persist, unpinned actions and dangerous triggers, and asks GitHub for the advisories of the actions that they pin. In every pull request into main, also the release pull request, whatever it changes: the rules of main stop a merge while the pull request adds an alert of zizmor, and while its analysis is missing. On main after every merge and every week, for the analysis that code scanning compares the pull requests with; an advisory published since shows as an alert of the next pull request, until a run on main by hand gives main the alert. Its findings go to code scanning, where the Findings workflow keeps them fixed or accepted; .github/zizmor.yml holds what the repository accepts on purpose.
- Wann: jeder Push auf
main, jeder Pull Request, jeden Dienstag um 05:32 UTC, von Hand - Quelle:
.github/workflows/zizmor.yml, aus dem Repo Blueprint
Pflege¶
Sie halten das Repository, seine Einstellungen, seine Labels und seine Berichte aktuell.
Bot health
The bot-health bot. GitHub mails the failure of a scheduled run only to whoever last changed its schedule, and that of another run to whoever started it, which here is mostly the release app, so a failing bot went unnoticed for days. When a run of a bot or a scheduled workflow ends on the default branch, or the verification of a release that someone published by hand or with a token, this bot runs its failed jobs once more if a second try can pass, as it does with a job that GitHub cancelled at its time limit; a failure that stays keeps one issue per workflow open, with the label bot-failure, the failed jobs, their steps and their first errors, and the next run that passes closes it once every job that failed ran again in it, in every leg of its matrix, and passed: a run that skipped such a job, as a push that only plans the screenshots, leaves it open. Every night it also looks at the latest run of every workflow, those of the project and the checks of main too, in case GitHub lost an event, and starts a workflow whose schedule GitHub missed or switched off. A failure of Lint at a commit that the branch has left says nothing any more, because a pull request reaches the branch only when it passes Lint: it gets no issue, and an open one starts Lint by hand, so that a run that passes closes it. The same look compares the social preview that GitHub shows with .github/social-preview.png, which only a person can upload, and keeps one issue open, Upload the new social preview, until they are the same, in a public repository only, since GitHub shows no social preview of a private one; its label is manual-step, not bot-failure, since nothing fails there. Runs of pull requests start nothing here, and neither does a run that GitHub couldn't start, as in its outage of 9 November 2026: the nightly look runs it again once. A look that GitHub keeps failing ends with a notice, not a failure (decision 0136). The bots of events, Area labels, Welcome, Dependabot maintenance and Commands, also those of a pull request or of a fork, and the workflows that keep an issue of their own, such as Newest Node, get neither a second try nor an issue here, unless Harden-Runner stopped a job of their first attempt: then their failed jobs run once more, as nothing else would run them again (decision 0141). It checks out the default branch only, for blueprint.py, never the code of a pull request; blueprint.py bot-health holds the logic.
- Wann: nach einem Lauf von Blueprint update, Chrome Web Store, Clean-up, Findings, Fuzzing, Issue lifecycle, Labels, Links, Mutation, OSV-Scanner, OpenSSF Scorecard, Property tests, Release, Release verification, SBOM, Screenshots, Settings, Update branches, Upstream, Workflow security, Area labels, Commands, Dependabot maintenance, Welcome, Diagrams, Newest Node oder Newest Python, jeden Tag um 01:44 UTC, von Hand
- Quelle:
.github/workflows/bot-health.yml, aus dem Repo Blueprint
Clean-up
The clean-up bot. Every week it deletes what nobody needs any more: the branches that main holds completely and that no open pull request uses, and the caches of the Actions that belong to closed pull requests. A branch with commits that main doesn't have stays; the bot lists it once it is a month old, so that its owner decides. It never touches main, release, Renovate or Dependabot branches.
- Wann: jeden Sonntag um 05:37 UTC, von Hand
- Quelle:
.github/workflows/cleanup.yml, aus dem Repo Blueprint
Labels
Creates and updates the repository's labels from .github/labels.toml. It never deletes a label; one that is missing from the file is reported in the summary. The job is the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below; it blocks every host but GitHub's. https://github.com/Dennis-Otto/issue-assistant
- Wann: jeder Push auf
main, der bestimmte Dateien ändert, von Hand - Quelle:
.github/workflows/labels.yml
Settings
The settings bot. Every week, and after each change of the settings as code or of its own code, it brings the settings of the repository on GitHub in line with .github/repository.toml, .github/repository.project.toml and .github/labels.toml, as the settings app, a second GitHub App of the owner that only administers, once the variable SETTINGS_APP_CLIENT_ID and the secret SETTINGS_APP_PRIVATE_KEY name it, and as the release app until then, with a token that may write the administration of the repository but neither its code nor its workflows. What the API can't set, such as the value of a secret, and what GitHub refused fail the run and show in its summary, with the command that sets it or the permission that the app lacks.
- Wann: jeder Push auf
main, der bestimmte Dateien ändert, jeden Donnerstag um 06:02 UTC, von Hand - Umgebungen:
release - Secrets:
RELEASE_AUTOMATION_PRIVATE_KEY,SETTINGS_APP_PRIVATE_KEY - Quelle:
.github/workflows/settings.yml, aus dem Repo Blueprint