mirror of
https://github.com/Comfy-Org/comfy-typescript-sdk.git
synced 2026-11-04 23:47:27 +00:00
[PR #170] [MERGED] ci(workflow-pins): fail closed on a job-level uses: this scanner cannot read #174
Labels
No labels
audit:ai-readiness
audit:community
audit:github
audit:health-scoring
audit:policy
audit:release
audit:supply-chain
bug
cursor-review-pin
effort:medium
effort:small
effort:trivial
priority:nice-to-have
priority:recommended
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-typescript-sdk#174
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/comfy-typescript-sdk/pull/170
Author: @mattmillerai
Created: 9/21/2026
Status: ✅ Merged
Merged: 10/9/2026
Merged by: @mattmillerai
Base:
matt/be-16299-check-workflow-pins-regression-suite← Head:matt/be-16336-check-workflow-pins-fail-closed📝 Commits (10+)
04eba98ci(cursor-review): read the watched pathspecs from upstream, and stop reading faults as verdictsb541197ci(cursor-review): read a vanished bump workflow as broken, not as a faultd80dbd4ci(cursor-review): stop the watchdog reading faults, decoys and magic as verdicts278ec24Merge remote-tracking branch 'origin/matt/be-15270-resync-cursor-review-pins' into matt/be-16336-check-workflow-pins-fail-closedfcfbab4ci(workflow-pins): fail closed on a job-level uses: this scanner cannot read42365c0ci(cursor-review): close the round-5 holes in the pin-freshness watchdog5596838Merge remote-tracking branch 'origin/matt/be-15270-resync-cursor-review-pins' into matt/be-16336-check-workflow-pins-fail-closedecfcaddci(workflow-pins): match the reusable's owner/repo case-insensitivelybb3c999ci(cursor-review): close the panel's round-9 fail-open holes31d999bMerge remote-tracking branch 'origin/matt/be-15270-resync-cursor-review-pins' into matt/be-16336-check-workflow-pins-fail-closed📊 Changes
4 files changed (+2901 additions, -206 deletions)
View changed files
📝
.github/dependabot.yml(+44 -6)📝
.github/workflows/ci.yml(+1938 -120)📝
scripts/check-workflow-pins.mjs(+716 -75)📝
scripts/check-workflow-pins.test.ts(+203 -5)📄 Description
STACKED — merging lands on
matt/be-16299-check-workflow-pins-regression-suite(owned by @mattmillerai, PR #169), NOTmain. #169 is itself stacked on #153. GitHub retargets this PR as each foundation merges; do not read the checks below as "safe to merge into main".One consequence a reviewer should know:
ci.ymltriggers onpull_request: branches: [main], so while this PR is stacked the repo's own gates —test,workflow-pins,public-repo-hygiene,build-check— do not run on it at all. That is pre-existing behaviour for every stacked PR here (it applies to #169 and #153 too), not something this change introduced. They were all run locally; see Verified below, and they will run for real once GitHub retargets this PR tomain.ELI-5
scripts/check-workflow-pins.mjsreads workflow YAML one line at a time, so it only recognises a reusable-workflow call written as one plain line. Write the same call a different but perfectly legal way — folded (uses: >-), with the value pushed onto the next line, or with the whole job spelled as a flow mapping (review: { uses: ... }) — and the scanner saw nothing there at all. Put one of those next to a normal caller and the lint happily reported "all pins agree" over a genuinely split pin, while--print-pinhanded the daily freshness watchdog the other job's SHA as if it were the only pin in the repo. Now the scanner tells those three apart from "no caller here": it reports the file and line, says which spelling it choked on, tells you to writeuses: …@<sha>on one line, and exits 1 in both modes.What changed
scripts/check-workflow-pins.mjs, text-level only — noyamlimport, because the two CI jobs that run this script deliberately have nopnpm install.USES_KEY_REmatches ausesKEY with any value, including none on the line. The gap between it andUSES_RE(which matches only the values the scanner can read) is exactly the set of lines that used to vanish.unreadableUsesReasonclassifies that gap: a quote that never closes (multi-line quoted scalar), or anything else still naming the org's reusables (owner/path/ref did not parse). The other two shapes, a block-scalar header and an empty value with the value on the next line, are now caught earlier by #153's ownUSES_BLOCK_SCALAR_RE/USES_EMPTY_VALUE_REchecks. Those read the folded value and fail in both modes with #153's message. This PR originally classified them here too (folded/literal block scalar,value on a continuation line); those arms were removed atf462d5cbecause they could no longer fire. It returnsnull— a silent skip, as today — for a single-line value naming some other owner (./.github/workflows/local.yml,octo/repo/.github/workflows/x.yml@v1): those pin once and have noworkflows_refto disagree with.FLOW_JOB_REcatches a job whose whole body is a flow mapping, positioned by its owning key being a ROOTjobs:(asked structurally off #153'sowningKeyChain, the same way #153'sisJobLevelUsesasks it) rather than by hardcoding two-space indent.findCallersnow returns{ callers, unreadable }. Both modes readunreadableand both report it before their own checks —--print-pinwriting nothing whatsoever to stdout, since ci.yml captures that mode with$(...)and any stray byte would become the "pin" it feeds to git.uses: >-, a flow mapping" as one half of an either/or; those are now reported by name, so reaching that guard really does mean no job-leveluses:exists.scripts/check-workflow-pins.test.tsgainsdescribe("spellings the scanner cannot read fail closed"), now eight cases, each asserting the lint mode and--print-pintogether. Every positive fixture places the unreadable job beside a plain, correctly-pinned sibling, because that sibling is what made the old silence survivable; without it the zero-caller guard would have caught the file and the case would prove nothing.Two design calls worth a reviewer's eye
A flow-mapping job is reported even if it calls nothing. A flow mapping nests to any depth on one line, so "does this contain a
uses:" is precisely the question a line-anchored scanner cannot answer — guessing would reinstate the silent skip. No workflow here is written that way, and the remedy is a reformat.--print-pinrefuses when the unreadable job is in a different file than the reusable it was asked about. Deliberate: an unreadable job anywhere could be a second caller of that same reusable, which is exactly the ambiguity--print-pinalready refuses to resolve.Falsification of the "cannot read" claim
This diff adds a deny path, so the premise was checked empirically rather than asserted, on the two paths that could make it false:
require('node:module').builtinModulesmatches nothing for/yaml/i;import('node:yaml')→ERR_UNKNOWN_BUILTIN_MODULE;node:utilexposes onlyparseEnvandparseArgs.yamldevDependency is genuinely unreachable in the CI shape.import('yaml')from a tree with nonode_modules→ERR_MODULE_NOT_FOUND.yamlis indevDependenciesonly, and bothworkflow-pins(ci.yml:231) andcursor-review-pin-freshnessrun checkout + setup-node +node scripts/…with no install step — unchanged by this PR.Note the outcome is not a capability the author loses: the error names the spelling to write instead, and the one-line form is already what every caller in the repo uses.
Corpus sweep — including the half not fixed
Swept all 5 files under
.github/workflows: 22uses:lines, 21 of them step-level and 1 job-level (the real caller, readable, still the only thing the lint reports). Zero occurrences today of any shape this guard does not cover — 0 flow-mapping jobs, 0 alias-valueduses: *ref, 0 multi-document files, 0 merge-key anchors. So the guard changes nothing about the current tree and the remaining gaps are hypothetical rather than latent.Review round 6 — cursor-review panel
The panel raised 10 findings. Only one of them is in this PR's own commit (
fcfbab4, which touchesscripts/check-workflow-pins.mjsand its test and nothing else); the other nine are in.github/workflows/ci.ymland incommentShaCandidates, both of which reach this diff only because the branch merges #153's branch.comfy-org/github-workflows/...— which GitHub resolves to the very same repo and calls successfully — matched neitherUSES_REnorunreadableUsesReason, and was skipped in silence. Reproduced against the pre-change script on a two-job fixture pinned to two different SHAs:1 caller(s) checked, all pins agree, exit 0, with--print-pinreturning the other job's SHA. Fixed inecfcaddwith a regression test.GIT_NO_LAZY_FETCHexistence check, the block-scalar-header comment, the:^exclusion synonym and the dash-column block indent were all fixed by #153's42365c0. #153 has since landedbb3c999("close the panel's round-9 fail-open holes"), re-merged here in31d999b, which also fixes the fifth —commentShaCandidatesnow discriminates dates by LENGTH (!/^[0-9]{8}$/) on both branches instead of dropping every all-digit token, so a 7-digit abbreviation is checked like any other and the ~1-in-27 silent skip of assertion (3) is closed. Those five threads are resolved.ageclamp does not bound the mute — a future-dated commit yieldsstate=gracedaily) and three Low/Nit (the unprobed wildcard pathspec, the per-line-anchoredpin_outguard, andalways()where!cancelled()is meant). All four are in thecursor-review-pin-freshnessjob inci.yml— #153's code — and all four were re-checked againstbb3c999and still stand; that commit fixed a different nine. #153 is open and merges first, so patchingci.ymlfrom here would only collide with its next round. Those four threads are deliberately left unresolved and are itemised on #153 (comment5757140139). #153 has since fixed three of them:56a738bstops a future-dated commit past the skew tolerance from counting as grace, thepin_outguard is a whole-value=~match, and the steps use!cancelled().f462d5cmerges that tip, so those three threads are resolved. The unprobed-wildcard thread is still open because the code is unchanged at56a738b.Residual
USES_REto match the owner/repo case-insensitively, which supersedes this PR's choice to keep it case-sensitive. The concern that choice rested on (the lint exiting 0 on a split pair across two spellings) is answered on #153's side by its spelling lint (4), which names the non-canonical caller and exits 1.--print-pinsees two callers and refuses. The letter-case test now asserts both.unreadableUsesReasonstill matches case-insensitively for a lowercase owner/repo thatUSES_REcannot parse.uses:is still a silent skip.uses: *some_anchorreads as a single-line non-org value, sounreadableUsesReasonreturnsnulland it is skipped — yet the alias could resolve to an org reusable with a pin the lint never checks. Resolving anchors means tracking&anchordefinitions across the file, which is a second parser's worth of work and outside this ticket's one guard. 0 occurrences in the tree today. Worth its own ticket if anchors ever appear in these workflows.jobs:block written wholly as a flow mapping is still a silent skip.FLOW_JOB_RErequires the line's owning key to be the column-0jobs:;jobs: { review: { uses: … } }has no owning key, so nothing reports it. Same fix family as the alias gap. 0 occurrences today.<<: *base) are unhandled by the scanner generally — not introduced here, not fixed here. 0 occurrences today.all pins agree,--print-pinreturned the sibling SHA) before any code was written.ci.ymlis scoped topull_request: branches: [main]and this PR's base is a stacked branch. Every one of them was run locally instead and is listed under Verified; the first CI-side run oftest/workflow-pins/public-repo-hygiene/build-checkagainst this diff happens after retargeting. Nothing here can substitute for that.f462d5c: disabling the flow-job check reddens 1 of 34 tests. Disabling theunreadablekey path reddens the 2 cases added at that merge. Before those cases were added it reddened nothing, because the letter-case case no longer reaches that path. Earlier mutations, also not committed — nothing in CI re-runs it. With bothunreadable.pushsites commented out, exactly the 4 original positive cases go red and the negative case plus all 26 pre-existing cases stay green; withunreadableUsesReason'sreturn nullflipped to a reason, the negative case goes red (as does the pre-existingother-org/sharedcase). The case-insensitivity case added in review round 6 was mutation-checked the same way: reverting thetoLowerCase()reddens that case and only that case, 1 of 32.Provenance
f462d5c(merge of #153's tip56a738b, with thefindCallersconflict resolved):pnpm vitest run scripts/check-workflow-pins.test.ts: 34 passed, 0 failed.pnpm test: 654 passed, 0 failed across 27 files.pnpm lint,pnpm format:check,pnpm typecheck,pnpm check:spec-drift,node scripts/check-public-repo-hygiene.mjs: all clean.node scripts/check-workflow-pins.mjson the real tree: exit 0,1 caller(s) checked, all pins agree.--print-pin cursor-review.yml: bare 40-hex SHA, exit 0. Two mutation runs as described under Residual..github/is byte-identical to56a738b. These are LOCAL results: the repo's own gates still do not run in GitHub Actions against this PR while it is stacked, for the reason given at the top.isJobLevelUses,owningKeyandblockScalarMaskactually live), so #153's branch is merged in —ci.ymlis byte-identical to #153's tip (re-verified at31d999bagainstbb3c999;git diffagainst that ref is empty) and carries no newpnpm install. The unreadable-value check is written in theif (!USES_RE.exec(...))branch rather than as a separate pass before it; same set of lines, one regex evaluation instead of two. Review round 6 added the owner/repo case-insensitivity fix and re-merged #153's tip to pick up its round-5 watchdog fixes; a later pass re-mergedbb3c999to pick up its round-9 fixes, which is the only change in31d999b. No other scope change.f462d5cre-merged #153 at56a738b, which conflicted infindCallers. #153 had replaced theowningKey(lines, …)walk-back withowningKeyChain, and it had added its own block-scalar and continuation-lineuses:checks. This PR's call sites were moved to the chain API. The twounreadableUsesReasonarms those checks superseded were removed, and the affected tests now assert #153's messages. Two cases were added so theunreadablepath stays covered.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.