Skip to content

feat(update-consumers): fork-PR fallback, caller-permissions sync, dry-run - #92

Merged
Sayt-0 merged 1 commit into
mainfrom
feat/update-consumers-fork-fallback
Aug 25, 2026
Merged

feat(update-consumers): fork-PR fallback, caller-permissions sync, dry-run#92
Sayt-0 merged 1 commit into
mainfrom
feat/update-consumers-fork-fallback

Conversation

@Sayt-0

Copy link
Copy Markdown
Member

Summary

update-consumers.yml can now deliver version-bump PRs to consumer repos where the machine user has no write access (fork fallback), and keeps those PRs from breaking callers whose permissions: grants are below what the pinned review-pr.yml requires (issue #72: v2.0.3 raised actions: read to write and broke callers still granting read).

Routing (ported from migrate-consumers.yml)

RouteConditionBehavior
directmachine user has pushsigned commit on a branch, same-repo PR (unchanged)
forkno push, allow_forkingfork under the machine user, readiness polling, parent-verification guard against name collisions, gh repo sync --force, signed commit on the fork, cross-repo PR (owner:branch)
skipno push and forking disabledwarning + job-summary entry (needs a write grant or manual update)

Caller-permissions sync (new src/sync-caller-permissions)

resolve $VERSION @ $SHA
-> fetch review-pr.yml at $SHA
-> per consumer: sed re-pin -> sync-caller-permissions -> route -> signed commit -> PR
  • Computes what the target version's review-pr.yml requires from callers, reusing the caller-permissions extractor already used by the release-notes safeguard, so the two tools can never disagree on a release's requirement.
  • Edits the consumer's permissions: block in place, in the same PR: raises insufficient levels, appends missing scopes. Block maps and inline {} maps supported; comments, indentation and CRLF preserved; grants are never reduced. The comparison is absolute (requirement vs granted), so a consumer that was already under-granting gets fixed regardless of the version it comes from.
  • Fail-safe: an unparseable file degrades to a warning and the version bump still goes out. Cases that cannot be edited safely (no explicit permissions: block, read-all shorthand, * pseudo-scope) are surfaced in the consumer PR body as a manual action instead of guessed: inventing a block would zero unlisted scopes, and the repo-default grant is unknowable from outside.
  • CLI stdout protocol, one line per increase: changed|manual <block> <scope> <from> <to>.

New workflow_dispatch inputs

InputDefaultPurpose
dry-runtrueprints the route and the diff that would be committed, performs zero writes (not even the fork). Safe default: the workflow is dispatch-only, nothing in release.yml triggers it
repos""comma-separated allowlist for pilot runs (entries trimmed, matched on the repo field)

A job summary (DRY RUN / EXECUTED) lists PRs opened (with URLs) and skipped repos with reasons.

Fixes that came with the port

IssueFix
per-iteration trap ... EXIT (traps do not stack, skip paths leaked workdirs)single cleanup_workdir trap + explicit calls on every skip path
--base-ref main hardcodedresolved default branch (also required by the fork sync)
gh pr list --jq '.[0].number' can print the literal string "null"// empty (same fix migrate-consumers documents)
existing-PR lookup does not support owner:branch headsREST pulls?head=owner:branch on the fork route

Validation

CheckResult
unit tests (24 new, incl. pins on the real review-pr.yml requirement and the README quick-start caller block)1043/1043 pass
tsc, biome ci, actionlintclean
harness executing the extracted step script with a fake gh (3 fixture consumers: direct on main, fork on a non-main default branch, skip)dry run: zero writes, routes and diffs reported; execute: signed-commit and pr-create argv correct per route (--base-ref trunk, --head owner:branch); allowlist: whitespace trim and single-repo filtering verified

Suggested first rollout

  1. Dispatch with defaults: dry run over all consumers, review the job summary.
  2. dry-run=false + repos=<one fork-route repo>: validates live fork creation, sync, signed commit on the fork, cross-repo PR.
  3. dry-run=false with no allowlist: full propagation.

…y-run
Open a cross-repo PR from a machine-user fork when the consumer repo
denies write access (same routing as migrate-consumers), and raise the
caller's permissions: grants to what the pinned review-pr.yml requires
(issue #72: actions read -> write) so a version bump can no longer break
callers at startup validation. Add dry-run (default true) and a repos
allowlist for pilot runs, plus a job summary for triage.
@Sayt-0
Sayt-0 enabled auto-merge (squash) August 24, 2026 16:20
@Sayt-0
Sayt-0 merged commit 757e5c9 into mainAug 25, 2026
14 checks passed
@Sayt-0
Sayt-0 deleted the feat/update-consumers-fork-fallback branch August 25, 2026 08:20
Sayt-0 added a commit that referenced this pull request Aug 25, 2026
## Summary
The first live dry run of `update-consumers.yml` (run
[32826389044](https://github.com/docker/docker-agent-action/actions/runs/32826389044),
after #92) discovered the action repo itself as a consumer and showed a
diff that would have mangled the workflow's own discovery query. This PR
excludes the action repos from discovery.
| | |
|---|---|
| Cause | the code-search query inside `update-consumers.yml` contains
`docker/docker-agent-action/.github/workflows/review-pr.yml@` as a
literal string, so the repo matches its own search |
| Why latent until now | while the repo still had a `pr-review.yml`
caller, `unique_by(.repo)` picked that file (updated by #86 and earlier
releases); since the rename to `self-review-pr.yml`, which calls the
reusable workflow via a local ref (`uses:
./.github/workflows/review-pr.yml`, no `@`), the only remaining match in
the repo is the query string itself |
| Impact if executed for real | a self-addressed PR rewriting the query
line (quote, filters and line continuation destroyed), breaking the
workflow |
| Handled by | dropping `^docker/(docker-agent-action|cagent-action) `
lines right after discovery, mirroring the migrate-consumers guard;
`cagent-action` is excluded too since it holds a copy of these workflows
|
## Dry-run evidence
```
Processing docker/docker-agent-action (.github/workflows/update-consumers.yml)...
DRY RUN - route: direct; diff that would be committed:
- -f q='org:docker "docker/docker-agent-action/.github/workflows/review-pr.yml@" language:YAML path:.github/workflows' \
+ -f q='org:docker "docker/docker-agent-action/.github/workflows/review-pr.yml@06e1767 # v2.0.5
```
No writes were performed (dry run). The rest of the run was nominal: 49
repos routed (17 direct / 29 fork / 3 skip), 33 consumers flagged for
the `actions: read` to `write` caller bump.
## Validation
| Check | Result |
|---|---|
| actionlint, `bash -n` on the extracted step script | clean |
| harness with the action repos injected into the fake search results |
self repos never cloned nor processed; direct/fork/skip routing
regression intact in both dry-run and execute modes |
Sign up for freeto 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.

2 participants

@Sayt-0@ronan-thibaut-glitch