Skip to content

bot-token, merge-key-check, notify-umbrella and gemini-review on marola-pr-bot (MIP-0086 row 2) - #110

Merged
brunogbv merged 14 commits into
mainfrom
mip-0086/2-bot-token
Oct 13, 2026
Merged

brunogbv merged 14 commits into
mainfrom
mip-0086/2-bot-token

Conversation

@brunogbv

@brunogbv brunogbv commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary: The devkit side of MIP-0086's two Apps. A bot-token composite action mints a scoped marola-pr-bot or marola-merge-bot token for named repos, merge-key-check keeps the merge bot's key out of jobs that run third-party code, and notify-umbrella and gemini-review move to the PR bot with the old names as fallback. Closes #79.

MIP MIP-0086 §5.4 to §5.6, tasks row 2
Tested ✅ gates · ⬜ e2e · ✅ live · ⬜ ci-only: release.py and merge_key_check.py self-tests red then green; actionlint; devkit quality gate run outside Nix (ruff 0.17.0 from a venv, flake.nix unevaluated). Live: bot-token test passed against the real PR_BOT_KEY on the final head in run 38465551179.

What changed

  • release.py moves marola-dev/marola-devkit/.github/actions/<name>@vX.Y.Z pins, so consumers' bot-token pin follows a release.
  • .github/actions/bot-token: mints with an explicit repo list under owner: marola-dev. It refuses an empty or malformed list (the token action reads "\r\n" as no list, which would cover every installed repo) and a call with no permission-* set (which would inherit every permission the App holds). The bot's git identity goes to a gitconfig under $RUNNER_TEMP, exported as GIT_CONFIG_GLOBAL, so it ends with the job even on a self-hosted runner.
  • .github/workflows/bot-token-test.yml: the refusals, then a token for marola-devkit with contents: write only. It must list exactly that repo, get 403 on pulls, succeed on a git push --dry-run to marola-devkit and be refused (403) on one to marola-site, and commit as <id>+marola-pr-bot[bot]. A {} POST to git/refs is not used: it returned 422 on marola-site as well, so it shows nothing about permission.
  • scripts/merge_key_check.py, in just quality, tests/self-tests.sh and the flake's tools: MERGE_BOT_KEY (matched case-insensitively, as GitHub resolves secret names) may appear only in workflows listed in .github/merge-key-allowlist. A keyed job fails on a third-party action, a reusable call other than a listed local one receiving the key under its own name, container/services, a shell other than bash or sh (step or defaults), workflow-level env carrying the key, or nix/npm/pip/curl and the like in run:. Once the allowlist exists, secrets: inherit fails in every workflow of the repo.
  • notify-umbrella takes pr_bot_key and mints an umbrella-only Contents-write token; the token PAT is read only when pr_bot_key is absent.
  • gemini-review reads PR_BOT_* first, GEMINI_* second; GEMINI_APP_PRIVATE_KEY is no longer required.
  • Docs: marola-gemini-bot is marola-pr-bot in present-tense prose; the action, the check and pr_bot_key are in the reference pages; gemini-review's caller example passes secrets explicitly; one line in the unreleased v0.9.0 CHANGELOG entry.

No consumer breaks at its next pin bump: callers passing only token, or GEMINI_* secrets, behave as before.

What this leaves for later rows: merge-key-check blocks secrets: inherit in any repo holding the merge key, so marola-dev/marola#766 (row 4) and #80 (row 8) must switch their gemini.yml to explicit secrets before adding an allowlist. The check reads workflows only; a checked-in script that itself runs nix or curl is outside what it can see.

This branch and mip-0086/3-merge-bypass both add a line to the v0.9.0 CHANGELOG entry; whichever merges second rebases.

brunogbv and others added 14 commits October 12, 2026 21:33
… §5.4)

Tested: release.py --self-test red then green; devkit quality gate
Co-Authored-By: Claude <[email protected]>
…86 §5.4)

Composite action over actions/create-github-app-token: refuses an empty
repositories list, always passes owner plus the named repos, and sets git
to the bot's noreply identity. bot-token-test.yml proves the refusal and
the one-repo, no-pull-request-write scope live.

Tested: actionlint; the live bot-token test runs on the PR
Co-Authored-By: Claude <[email protected]>
…ssert the probes

Refuse a token with no permission-* input (v3 skips empty ones, so it
would hold every App permission). Clean the repositories list in bash
and pass that to the mint step, refusing blanks and non-bare names.
Write the bot identity to a job-scoped GIT_CONFIG_GLOBAL file instead of
the runner's global config. The test mints with contents write, adds a
positive control, and asserts marola-site is 403 or 404.

Tested: actionlint; guard step exercised locally; the live bot-token test runs on the PR
Co-Authored-By: Claude <[email protected]>
…party code (MIP-0086 §5.6)

Tested: merge_key_check.py --self-test red then green; devkit quality gate
Co-Authored-By: Claude <[email protected]>
…, containers and custom shells

Tested: merge_key_check.py --self-test red then green; devkit quality gate
Co-Authored-By: Claude <[email protected]>
…rit in any workflow once an allowlist exists

Tested: merge_key_check.py --self-test red then green; devkit quality gate
Co-Authored-By: Claude <[email protected]>
…mes as fallback (MIP-0086)

notify-umbrella mints a marola-pr-bot token for the umbrella from pr_bot_key and still reads
the old PAT in `token` when it is absent. gemini-review reads PR_BOT_* first, falls back to
GEMINI_*, and no longer requires GEMINI_APP_PRIVATE_KEY.

Tested: actionlint; devkit quality gate
Co-Authored-By: Claude <[email protected]>
…086)

Tested: actionlint; devkit quality gate
Co-Authored-By: Claude <[email protected]>
…erit message

A keyed job may call a local reusable workflow only when that file is
itself on the allowlist, so the callee is scanned under the same rules.

Tested: merge_key_check.py --self-test (red before, green after), merge_key_check.py ., ruff
Co-Authored-By: Claude <[email protected]>
…y and the PR bot

bot-token-test jobs get contents: read for checkout. The mint steps pass
client-id (app-id is deprecated in create-github-app-token v3); actionlint's
bundled v3 metadata predates it, so notify-umbrella.yml ignores those two
messages. gemini-review callers pass secrets explicitly, since merge-key-check
rejects inherit. The docs name the real secrets and the persist-credentials trap.

Tested: merge_key_check.py --self-test and ., actionlint, devkit-quality.sh (quality rc=0)
Co-Authored-By: Claude <[email protected]>
…own name; back to app-id

A caller could map `k: ${{ secrets.MERGE_BOT_KEY }}` to a listed local callee that
only reads secrets.k, so the callee never named the key and was never scanned.
The mapping entry must now be called MERGE_BOT_KEY. The mint steps pass app-id
again and the actionlint ignore block is gone; the README no longer claims the
GEMINI_APP_* names work next to a snippet that does not pass them.

Closes #79

Tested: merge_key_check.py --self-test (red without the fix, green with) and ., mkc-review probes a-d, actionlint, devkit-quality.sh (quality rc=0)
Co-Authored-By: Claude <[email protected]>
…run push (MIP-0086 §7)

The first live run (38305859769) failed at the marola-site API probe with a code that was never
printed. probe now prints the code and GitHub's message, the cross-repo API probe only fails on a
2xx, and a git push --dry-run with the bot token to devkit (must succeed) and marola-site (must be
refused) is the scoping test §7 asks for.

Tested: actionlint; devkit quality gate; probe() exercised unauthenticated
Co-Authored-By: Claude <[email protected]>
…othing

Run 38306845732 printed `422 Invalid request.` for a `{}` POST to git/refs on both
marola-devkit and marola-site, a repo the token cannot reach: that endpoint validates the
body before checking permission, so 422 is not evidence of write access. The dry-run pushes
(devkit ok, marola-site 403) already prove contents scoping; the pulls probe stays, since
it returned 403 before validation.

Tested: actionlint; devkit quality gate (outside Nix); run 38306845732's printed codes
Co-Authored-By: Claude <[email protected]>
Resolve the CHANGELOG and docs/4-reference_tools.md conflicts with #109: keep both v0.9.0
bullets, and main's ruleset-sync row followed by this branch's merge-key-check row.

Tested: devkit quality gate (outside Nix) on the merge result
Co-Authored-By: Claude <[email protected]>
@brunogbv
brunogbv merged commit 81ba602 into main Oct 13, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MIP-0086 task 2: bot-token action, merge-key-check, notify-umbrella and gemini-review on marola-pr-bot

1 participant