Skip to content

fix(eslint-factory): withhold prefer-structured-clone suggestion when the cloned value carries function properties - #50846

Merged
pelikhan merged 3 commits into
mainfrom
copilot/prefer-structured-clone-fix
Aug 6, 2026
Merged

fix(eslint-factory): withhold prefer-structured-clone suggestion when the cloned value carries function properties#50846
pelikhan merged 3 commits into
mainfrom
copilot/prefer-structured-clone-fix

Conversation

Copilot AI commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

prefer-structured-clone offered its structuredClone(x) suggestion unconditionally, but the two forms are not equivalent: JSON.stringify silently drops function values while structuredClone throws a synchronous DataCloneError. Applying the suggestion at actions/setup/js/safe_outputs_tools_loader.cjs:244 — where the JSON round-trip deliberately strips tool.handler before re-attaching it — would replace working code with code that throws on every call.

// Flagged today, suggestion would break it: `tool.handler` is a live function
toolToRegister = JSON.parse(JSON.stringify(tool));
if (tool.handler) {
  toolToRegister.handler = tool.handler; // drop-and-reattach, on purpose
}

Rule logic (src/rules/prefer-structured-clone.ts)

  • Matches are collected during traversal and reported on Program:exit, so evidence found anywhere in the file is available at report time.
  • The suggestion is withheld (diagnostic still reported, suggest: []) when the cloned expression is an Identifier for which the file contains any of:
    • a function-literal property assignment — x.p = () => {} / function () {}
    • an object literal with a function-valued property — const x = { p: () => {} }, { p() {} }
    • a typeof x.p === "function" check
  • Non-identifier cloned expressions and identifiers with no such evidence are unaffected.

Docs

  • meta.docs.description now states that the suggestion assumes the cloned value carries no function-valued properties, and describes when the guard withholds it.

Tests (src/rules/prefer-structured-clone.test.ts)

  • Regression cases for the loader drop-and-reattach shape, the typeof check shape, and the object-literal shape — each expecting an error with an empty suggestions array.
  • A JSON-sourced case mirroring generate_safe_outputs_tools.cjs:280 that still receives the suggestion, pinning the safe path against regressions.

Checked against the real sources with the built rule: safe_outputs_tools_loader.cjs:244 yields 0 suggestions, generate_safe_outputs_tools.cjs:280 yields 1.

Scope is eslint-factory/** only; no app code under actions/setup/js/** is touched. The guard is a heuristic — "is this object JSON-safe" is not statically decidable in general — so it errs toward withholding the suggestion rather than offering an unsafe one.

Copilot AI and others added 2 commits August 6, 2026 12:32
…d properties

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…roperties

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix prefer-structured-clone rule to handle function-valued properties fix(eslint-factory): withhold prefer-structured-clone suggestion when the cloned value carries function properties Aug 6, 2026
Copilot AI requested a review from pelikhan August 6, 2026 12:37
@pelikhan
pelikhan marked this pull request as ready for review August 6, 2026 12:42
Copilot AI balanced review requested due to automatic review settings August 6, 2026 12:42
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

No ADR enforcement needed: PR does not have the 'implementation' label and has 0 new lines of code in business logic directories (≤100 threshold).

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

⚠️ PR Code Quality Reviewer failed during code quality review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a conservative guard preventing unsafe structuredClone suggestions when function-valued properties are detected.

Changes:

  • Collects function-property evidence before reporting suggestions.
  • Adds regression tests and documentation.
  • Includes an unrelated workflow-skill index update.
Show a summary per file
File Description
prefer-structured-clone.ts Guards suggestions and updates rule documentation.
prefer-structured-clone.test.ts Tests guarded and safe suggestion paths.
agentic-workflows/SKILL.md Adds an unrelated designer mapping reference.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment on lines +121 to +125
context.report({
node,
messageId: "preferStructuredClone",
data: { arg: clonedExpressionText },
suggest: carriesFunctionProperties
- `.github/aw/debug-agentic-workflow.md`
- `.github/aw/dependabot.md`
- `.github/aw/deployment-status.md`
- `.github/aw/designer-mappings.md`
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 1 test(s) (4 sub-cases): 1 design, 0 implementation, 0 violation(s).

📊 Metrics (1 test block, 4 sub-cases)
Metric Value
Analyzed 1 (Go: 0, JS/TS: 1)
✅ Design 1 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (100%)
Duplicate clusters 0
Inflation No (52 test lines / 75 prod lines = 0.69:1)
🚨 Violations 0
Test File Classification Issues
it("invalid: no suggestion when the cloned identifier carries function-valued properties") eslint-factory/src/rules/prefer-structured-clone.test.ts design_test, behavioral_contract, high_value None

Verdict

Passed. 0% implementation tests (threshold: 30%). All sub-cases verify observable linting behavior (error presence and suggestion list shape).

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 23.3 AIC · ⊞ 7.7K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 100/100. 0% implementation tests (threshold: 30%).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — approving with two minor suggestions.

📋 Key Themes & Highlights

Key Themes

  • Root cause properly addressed: the fix defers reporting to Program:exit so evidence from the whole file is available — not just a local-scope guard.
  • Suggestion vs. diagnostic correctly separated: still reports the diagnostic when the guard fires, enabling manual review without silently ignoring the pattern.
  • Test coverage is solid: three detection-pattern regression tests plus a safe-path pin.

Minor Suggestions

  1. Non-identifier boundary test (test file, line 135) — no test pins that member-expression clones (obj.sub) still receive the suggestion even when the object carries function properties.
  2. Heuristic scope comment (rule file, line 77) — the aliased-variable limitation is not documented inline; future contributors may attempt to extend the guard unnecessarily.

Positive Highlights

  • ✅ Excellent Program:exit two-pass design — clean and correct.
  • ✅ All three detection shapes are tested independently.
  • docs.description updated to explain when the suggestion is withheld.
  • ✅ PR body references the real affected file with a concrete reproducer.
> 🧠 *Reviewed using Matt Pocock's skills by [Matt Pocock Skills Reviewer](https://github.com/github/gh-aw/actions/runs/31102532835)* · sonnet46 · 44.9 AIC · ⊞ 7.1K > Comment /matt to run again

],
});
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The guard at prefer-structured-clone.ts:119 only suppresses suggestions when clonedExpression is an Identifier — non-identifier expressions (e.g. JSON.parse(JSON.stringify(obj.sub))) always get the suggestion. A test pinning this boundary would prevent a future regression if the guard logic is widened.

💡 Suggested test case to add inside this `it` block
{
  // member-expression clone: guard does NOT apply even though `tool` carries a function property
  code: [
    `function register(tool) {`,
    `  tool.handler = () => {};`,
    `  return JSON.parse(JSON.stringify(tool.data));`,
    `}`,
  ].join('\n'),
  errors: [{
    messageId: 'preferStructuredClone',
    suggestions: [{ messageId: 'replaceWithStructuredClone', output: ... }],
  }],
},

@copilot please address this.

const candidates: { node: TSESTree.CallExpression; clonedExpression: TSESTree.Node }[] = [];

return {
AssignmentExpression(node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/diagnosing-bugs] The AssignmentExpression visitor only detects direct identifier targets (x.prop = () => {}). Aliased or destructured parameters like const t = tool; t.handler = () => {} bypass the guard. This is an inherent heuristic limitation — consider adding a code comment acknowledging it so future contributors don't try to "fix" the check into something more complex than the risk warrants.

💡 Suggested comment
// Heuristic: only tracks direct identifier targets (x.prop = fn).
// Aliased or destructured variables (const t = tool; t.prop = fn) are not tracked.
// This is intentional — over-suppression is preferable to offering an unsafe suggestion.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

The implementation is correct and well-structured. Defers reporting to Program:exit so file-wide evidence (function-property assignments, object literals with methods, typeof guards) can be collected first. The suggestion is withheld — not the diagnostic — for identifiers carrying function-valued properties. All three evidence patterns handle edge cases correctly, no cross-file leakage from per-create() state, and tests cover all evidence shapes plus the safe path. LGTM.> 🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 17.8 AIC · ⊞ 5.4K

@pelikhan
pelikhan merged commit 5545339 into main Aug 6, 2026
41 of 42 checks passed
@pelikhan
pelikhan deleted the copilot/prefer-structured-clone-fix branch August 6, 2026 14:39
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.86.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

3 participants