Repository navigation
feat(harness-ops): bound computed keys by provenance in the parser reader - #12665
melodic-automation-lanes[bot] wants to merge 5 commits into
Conversation
Lane-Activity: work-resolve-issue/resolve-issue
|
claude-security-review reviewed Security review: PR #12665 (head 4f6e66a)I found no security issues. I read every hunk of all 5 changed files. None of them matches a trusted path. What changed
Checks
critical-findings: 0 |
|
claude-review reviewed Code review: bound computed keys by provenance in the parser readerI read every hunk of all 5 changed files. I also read the parts of What holds up when traced by hand (I did not run any tests):
Finding (inline at
The same gap already existed for a key with known values ( Closing issue: the PR context names no closing issue (it says Path-scoped rules: No embedded instructions were found in the PR context. There are no prior findings, and the round cap does not apply. Nothing in this change costs money. |
|
Unattended merge: native auto-merge leaves this pull request unarmed at head |
Lane-Activity: pr-unblock/address-feedback Lane-Thread: PRRT_kwDOTCGFQM6y-iFo
|
pr-unblock / address-feedback finished round 1 of max 4 on 70b50d1. |
Lane-Activity: pr-unblock/resolve-conflicts
|
The pr-unblock lane stopped
When a retry on this head can change the outcome, the lane runs one on its own, up to its per-head cap, and edits this comment if it stops again; a run that does not stop clears the status. When no retry can (a review thread the lane does not take or settle, or a failing check after the retries are spent), a person resolves the threads or gets the checks green, then dispatches the workflow below: that run finds the cause gone and clears the status. On a pull request the lanes App opened, the dispatchers start that run once per stop; on any other, a person does. A new commit to the branch starts clean. To run it again on this head now, dispatch the gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=12665 -f activity=fix-ci |
Lane-Activity: pr-unblock/fix-ci
|
claude-security-review needs no new review of Security review: PR #12665 (head d1cfff6)No security issues found. I read every hunk of all 5 changed files. None of them matches a trusted path. What changed
Checks
critical-findings: 0 |
| // (`globalThis[`ev${"al"}`]`, or a parameter only ever passed | ||
| // "Function"). A read of one counts as the named read counts. A key | ||
| // that may spell `constructor` is judged by the check above. | ||
| if (node.type === "MemberExpression" && node.computed && member === null && !isTarget(parents, node) && !maySpellConstructor(node.property, true)) { |
There was a problem hiding this comment.
Blocking: the fix for computed eval/Function reads covers member reads only, not destructured keys.
This check handles node.type === "MemberExpression" only. A computed key in an object pattern is judged only by maySpellConstructor (L2338) and by the vm destructure check, which takes literal keys only (L2358). So in strict code a destructured key that keySpellsOf bounds to eval or Function gets no hit:
export{};const J=(o,k)=>{const{[k]:f}=o;return f};J(globalThis,"eval")(s);
// k bounded to {"eval"} by its only caller: spells(k,"constructor") false,
// spells(k,"require") false -> no hit. Before this PR: function-constructor.
export{};const J=(o,k)=>{const{[k]:F}=o;return F};J(globalThis,"Function")(s)();The same applies to a vm runner taken from a vm namespace by a bounded destructured key.
Literal destructuring ({eval:f}=globalThis) already had this gap before the PR. Computed keys did not: before, every unresolved computed key counted as possibly spelling constructor. This PR removed that catch-all for every key keySpellsOf bounds.
Fix: extend the condition to node.type === "Property" && holder?.type === "ObjectPattern" && node.computed, using node.key in place of node.property. Better still, check every destructured key, literal ones included, against the same five names. Then add the two modules above to test_a_computed_key_counts_only_for_the_names_it_may_spell as expected hits.
claude-lane: claude-review
| of `instanceof`) or a build cleared below, any member named `eval` or `Function`, a read of | ||
| `constructor` (by name, by a computed key that may spell it, as an unknown key does while a loop | ||
| counter does not, or as a destructured key; every | ||
| counter or `n+1` does not, or as a destructured key; every |
There was a problem hiding this comment.
Advisory: the doc and the changelog fragment don't describe the behavior change from the round-1 fix.
maySpellAnywhereSink (parser_helper.cjs:2337) means a constructor read is exempt as inert only when its key also can't spell eval, Function, a vm runner or __defineGetter__/__defineSetter__. An unknown key, such as a for in key or any key in sloppy code, can spell all of them.
So a discarded or tested unknown-key read is now a function-constructor hit, in sloppy code too. Common bundle code like for(k in o)if(o[k]) used to be exempt and now counts.
This paragraph still says a constructor read that is "discarded, tested, compared…" does not count, and that "any member named eval or Function" counts, which reads as literal names only. The fragment says sloppy code "is bounded only by known values", which suggests its results are unchanged.
It is the safe direction, but the next host run's count of function-constructor hits will rise for a reason the doc doesn't give. Please say in this paragraph and in the fragment that a computed read whose key may spell one of those members counts wherever it stands, inert or not.
claude-lane: claude-review
|
claude-review needs no new review of Code review: bound computed keys by provenance in the parser reader (round 2)I read every hunk of all 5 changed files. I also read the parts of Prior finding. The earlier blocking finding was that a bounded computed read could reach Checked by hand and found sound:
New findings (2, inline):
Closing issue: the PR context names none (it says Path-scoped rules: Settled threads: the one resolved thread (L2179) is honored. I did not raise its point again. No embedded instructions were found in the PR context, the settled threads or the prior findings. Round 2 of a cap of 3, so the cap did not apply. Nothing in this change costs money. |
|
The pr-unblock lane stopped
When a retry on this head can change the outcome, the lane runs one on its own, up to its per-head cap, and edits this comment if it stops again; a run that does not stop clears the status. When no retry can (a review thread the lane does not take or settle, or a failing check after the retries are spent), a person resolves the threads or gets the checks green, then dispatches the workflow below: that run finds the cause gone and clears the status. On a pull request the lanes App opened, the dispatchers start that run once per stop; on any other, a person does. A new commit to the branch starts clean. To run it again on this head now, dispatch the gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=12665 -f activity=address-feedback |
|
A lane run on this pull request's head failed because the token broker refused it as workflow-modified: |
The token broker refused a lane run on the previous head as workflow-modified (.github/workflows/pr-feedback-dispatch.yml). This commit changes no file.
|
pr-unblock / address-feedback finished round 2 of max 4 on c8ede30. |
|
Superseded by #12867, which merged at 2026-11-03T17:34:47Z. |
Refs: #5901
Summary
Opened by the work-resolve-issue lane. The run's own summary:
Remaining work
inventory.py --reader compare --self-check --binary-onlyto count how many of 2.1.316's"*"modules (751, 422 with no load text) still load an unnamed file, and whether Explore and Plandisallowed_toolsresolve fully with no value->value changeNot verified
inventory.py --reader compare --self-check --binary <build> --binary-onlyon the current Claude Code build, and this lane has no Claude Code binary. How many of the 751"*"modules on 2.1.316 this clears is unmeasured.var's name is not counted as a write to it. Example: `var k="x";{function k(){}}k.toString=()=>"constructor";(()=>0)Fix
Verification
The runner ran each check from the base copy against 4f6e66a:
The run reports:
h.callerreaches a function without its name, so the parameter bound was unsound there), fixed by limiting every new bound to strict code; LOW repeated keyValues work, fixed with a per-Left out: the items under Not verified.
Related
#5901