mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #291] [MERGED] feat(groom): add extra_denied_paths caller input to extend the builder patch deny-list #295
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#295
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/291
Author: @mattmillerai
Created: 9/16/2026
Status: ✅ Merged
Merged: 9/16/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-4405-groom-extra-denied-paths📝 Commits (1)
567c9f3feat(groom): add extra_denied_paths caller input to extend the builder patch deny-list📊 Changes
5 files changed (+402 additions, -39 deletions)
View changed files
📝
.github/groom/README.md(+32 -10)📝
.github/groom/patch_policy.py(+125 -15)📝
.github/groom/tests/test_patch_policy.py(+150 -0)📝
.github/workflows/groom.yml(+77 -13)📝
docs/callers/groom.md(+18 -1)📄 Description
ELI-5
The groom auto-builder refuses to open an auto-PR when a machine-written patch touches a file your CI runs before a human reviews it (workflow files, lockfiles, build config) — those go to a filed issue instead, so untrusted code never executes with your secrets pre-review. That deny-list lived only in the shared
patch_policy.py, so a repo with its OWN privileged file (a checked-inscripts/ci/entrypoint, a custom build runner) had to edit the shared reusable workflow to protect itself. This adds anextra_denied_pathsinput so a caller lists its own paths in its own caller file. The patterns can only ADD denials (widen), never remove one, and a typo that won't compile fails the run closed rather than silently letting the path it was meant to guard slip through.What changed
groom.yml— newworkflow_callinputextra_denied_paths(type: string, default''), threaded into theCapture patchstep viaenv: EXTRA_DENIED_PATHS: ${{ inputs.extra_denied_paths }}(never inline${{ }}intorun:— matches the file'sSINK/CADENCE/etc. convention). Header comment + commented caller example updated; the "must add it here first" phrasing replaced with "add repo-specific paths viaextra_denied_paths; propose broadly-applicable ones upstream".patch_policy.py—main()readsEXTRA_DENIED_PATHS,compile_extra_patterns()splits on newlines (blank/whitespace lines skipped, each surviving line.strip()-ed and compiledre.IGNORECASEto mirror the built-in_PATTERN), anddenied_paths/denied_entries/_is_deniedOR the compiled patterns onto the built-in test via a new optionalextra_patternsarg (default(), so every existing call site is byte-identical).test_patch_policy.pygains coverage for: an extra pattern matching; extra patterns not affecting the built-ins (and a path only the extra covers not matching without it); additive-only behaviour; flow throughdenied_entries+ the symlink-mode deny; case-insensitive compile; strip/skip-blanks; empty/whitespace no-op; invalid regex raisingInvalidExtraPatternnaming the bad pattern; andmain()end-to-end via the env var, including the fail-closed path and the unset/empty no-op. 51 tests total, all green..github/groom/README.md(patch_policy.pysection + intro) anddocs/callers/groom.md(input table row + a new "Extending the patch deny-list" prose section).Design decision — fail-closed by aborting the step, not by "bail to an issue"
The ticket plan says an uncompilable pattern should "cause the capture step to bail that patch to an issue." I implemented fail-closed as a nonzero exit (
::error::naming the bad pattern → theset -euo pipefail, no-|| truepipeline aborts theCapture patchstep → no PR opens for any finding until the pattern is fixed), rather than emitting a synthetic denied-path so the step files an issue. Two reasons, both about a global config typo (the env var is identical for every matrix leg):build_pr's bail path (file_issue) writes the finding'ssignature_markerinto the issue, so a bail permanently dedups that finding in the ledger. A config typo would therefore file every finding this run as a (misleadingly-reasoned "modifies a CI-privileged path") issue and mark them all done, so they'd never be re-attempted as PRs even after the typo is fixed. Aborting drops nothing to the ledger — findings are simply re-proposed next run.parse_raw_zalready fails closed by raising → aborting the same pipeline ("fails CLOSED (no PR opens)"), and the step's own comment documents that a nonzero exit frompatch_policy.pyfails closed.The ticket's essential requirement — "a typo in a security control must never silently widen the allow side," and the acceptance line "an invalid pattern bails the patch (fail closed), with a clear
::error::naming the bad pattern" — is fully met: fail closed, loud::error::, no PR. Flagging the abort-vs-file-an-issue choice explicitly as a judgment call.Verification
python3 -m unittest discover -s .github/groom/tests -p 'test_*.py'— all groom script suites green (51 intest_patch_policy.py).python3 .github/workflow-pins/check_workflow_pins.py— OK (no reusable defaultsworkflows_ref; every ref checkout guarded).python3 .github/agents-md-integrity/check_agents_md.py --root .— passed (2 pre-existing warnings, unrelated).actionlint 1.7.7ongroom.yml— the only findings are the 16 pre-existing, documentedjob.workflow_shafalse-positives (actionlint'sjob-context schema predates runner v2.334.0; groom.yml's header calls this out). Zero new findings, none near the edited regions.type: string, required: false, default: ''.Residual
builder: truegroom workflow (needs the bot App token, a real repo, and a scheduled/dispatched run). TheCapture patchstep's shell wiring around$EXTRA_DENIED_PATHSis reviewed statically only.comfy-cloud-mcp-server(or any other caller) opting in viaextra_denied_pathsis a separate caller-repo decision and is not part of this PR. This repo's ownci-groom.ymlpin is intentionally left for the standard caller-bump machinery to move post-merge (this is a behavioural change, so it should bump — not aSkip-caller-bumpcase).extra_denied_pathscovers the CI-privileged extension case the README anticipated ("make the class a caller input"); the BE-9609 dataset-of-record tuple remains non-caller-configurable by design and is out of scope here.Provenance
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.