Skip to content

Fix dynamic dispatch_workflow ref forwarding and prevent ref leakage into inputs - #50042

Merged
pelikhan merged 5 commits into
mainfrom
copilot/dispatch-workflow-fix-ref-override
Aug 3, 2026
Merged

Fix dynamic dispatch_workflow ref forwarding and prevent ref leakage into inputs#50042
pelikhan merged 5 commits into
mainfrom
copilot/dispatch-workflow-fix-ref-override

Conversation

Copilot AI commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Per-workflow dispatch_workflow tools currently pass flat args directly as inputs, so per-call ref is sent as an unexpected workflow input instead of the required top-level dispatch field. This causes 422 failures (Unexpected inputs provided: ["ref"]) and can silently dispatch on the wrong ref.

  • Dynamic safe-output handler fix (actions/setup/js/safe_outputs_tools_loader.cjs)

    • For tools with _workflow_name, the handler now:
      • extracts ref from tool args,
      • forwards it as top-level ref in the dispatch_workflow payload,
      • sends only remaining fields under inputs.
    • Preserves prior edge-case behavior when args are undefined (no synthetic inputs object added).
  • Regression coverage (actions/setup/js/safe_outputs_tools_loader.test.cjs)

    • Added targeted tests to verify:
      • ref is forwarded top-level,
      • ref is excluded from inputs,
      • strict-schema dispatch tools preserve the same behavior.
  • Workflow usage enablement (.github/workflows/smoke-copilot.md + recompiled lock)

    • Updated one in-repo agentic workflow prompt to explicitly exercise per-call dispatch_workflow ref usage (top-level field), ensuring this codepath is actively used.
tool.handler = args => {
  const { ref, ...inputs } = args ?? {};
  return handlers.defaultHandler("dispatch_workflow")({
    ...(ref && { ref }),
    ...(args !== undefined && { inputs }),
    workflow_name: workflowName,
  });
};

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 11.5 AIC · ⌖ 11.2 AIC · ⊞ 8.3K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix dispatch-workflow ref override issue causing 422 errors Fix dynamic dispatch_workflow ref forwarding and prevent ref leakage into inputs Aug 3, 2026
Copilot AI requested a review from pelikhan August 3, 2026 17:16
@pelikhan
pelikhan marked this pull request as ready for review August 3, 2026 18:12
Copilot AI review requested due to automatic review settings August 3, 2026 18:12

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.

🟡 Not ready to approve

The loader breaks workflows with a legitimate ref input, and the smoke workflow cannot exercise the new path as configured.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Fixes dynamic workflow dispatch handling so per-call refs are forwarded outside workflow inputs.

Changes:

  • Extracts ref from dynamic tool arguments.
  • Adds regression tests for standard and strict schemas.
  • Updates and recompiles the Copilot smoke workflow.
File summaries
File Description
actions/setup/js/safe_outputs_tools_loader.cjs Separates dispatch refs from workflow inputs.
actions/setup/js/safe_outputs_tools_loader.test.cjs Tests ref forwarding and exclusion.
.github/workflows/smoke-copilot.md Adds ref usage to the smoke prompt.
.github/workflows/smoke-copilot.lock.yml Regenerates the compiled workflow.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

9. Artifact upload (only if build passes): stage `./gh-aw` at `$RUNNER_TEMP/gh-aw/safeoutputs/upload-artifacts/gh-aw` and call `upload_artifact` with `path: "gh-aw"`.
10. Discussion create: call `create_discussion` in `announcements` with label `ai-generated`, title `copilot was here`, temp ID `aw_smoke_discussion`.
11. Workflow dispatch: call `dispatch_workflow` for `haiku-printer` and include `inputs.message` with an original testing/automation haiku (non-empty string).
11. Workflow dispatch: call `dispatch_workflow` for `haiku-printer`, set top-level `ref` to `${{ github.event.repository.default_branch }}`, and include `inputs.message` with an original testing/automation haiku (non-empty string).
const workflowName = tool._workflow_name.trim();
tool.handler = args => {
// Wrap args in inputs property to match dispatch_workflow schema
const { ref, ...inputs } = args ?? {};
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

PR Triage: #50042

  • Category: bug
  • Risk: medium
  • Score: 55/100 (Impact 30 + Urgency 15 + Quality 10)
  • Recommended action: batch_review

Fixes ref leakage into dispatch_workflow inputs. CI shows 1 failure and 1 cancelled check alongside 11 passing — needs a fix-up before merge.

Generated by 🔧 PR Triage Agent · auto · 51.1 AIC · ⌖ 4.08 AIC · ⊞ 8K ·

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

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

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

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

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

@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.

Review Summary

The core fix is correct — extracting ref before wrapping remaining args as inputs properly prevents the 422 Unexpected inputs provided: ["ref"] errors. The test coverage is solid.

Two concerns already flagged in existing comments:

  1. ref reservation is unconditional (line 170, safe_outputs_tools_loader.cjs) — any workflow that legitimately declares a ref workflow input will have it silently promoted to the dispatch-level ref field instead of passed as an input. This is a silent breaking change for such workflows.

  2. Smoke test does not exercise the dynamic handler path (line 208, smoke-copilot.md) — the compiled per-workflow tool uses flat args so the added ref step may not cover the changed code path directly.

Neither blocks merge if the ref-as-reserved-field design is intentional.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 17.5 AIC · ⌖ 7.55 AIC · ⊞ 5.4K

@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.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — requesting changes on two correctness issues before merging.

📋 Key Themes & Highlights

Key Issues

  • Falsy ref guard (ref && { ref }): silently drops an empty-string ref. Use ref !== undefined to preserve intent.
  • inputs: {} edge case: when args is an explicit {}, inputs: {} is now forwarded where the old code passed inputs: {} too — but the args !== undefined guard changes the no-args case. Downstream tolerance of inputs: {} vs absent inputs should be confirmed and tested.
  • Missing edge-case test: no test covers ref: '' or args: {}, leaving the falsy-guard bug undetected by the test suite.

Positive Highlights

  • ✅ Clear, minimal destructuring fix for the primary bug
  • ✅ Good regression test structure with both positive and negative assertions
  • ✅ Strict-schema path covered by a dedicated test
  • ✅ PR description accurately describes the root cause and the fix

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 30.1 AIC · ⌖ 11.1 AIC · ⊞ 7.1K
Comment /matt to run again

// Wrap workflow inputs in inputs and pass dispatch ref as top-level field
return handlers.defaultHandler("dispatch_workflow")({
inputs: args,
...(ref && { ref }),

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] ref && { ref } silently drops a falsy (e.g. empty-string) ref. Use ref !== undefined to be explicit.

@copilot please address this.

defaultHandler: defaultHandler,
};

const result = attachHandlers(tools, handlers);

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 test verifies ref is excluded from inputs via a negative assertion, but it doesn't assert what happens when ref is falsy (empty string, null). This is the exact edge case the truthiness guard mishandles.

💡 Suggested additional test
it('should not forward empty-string ref to top-level for dispatch_workflow handler', () => {
  // With current impl, ref:'' is dropped; document whether that is intentional
  result[0].handler({ ref: '', input1: 'value1' });
  expect(mockHandlerFunction).toHaveBeenCalledWith({
    workflow_name: 'ci',
    // ref should be absent OR present — document the contract
    inputs: { input1: 'value1' },
  });
});

@copilot please address this.

return handlers.defaultHandler("dispatch_workflow")({
inputs: args,
...(ref && { ref }),
...(args !== undefined && { inputs }),

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] When args is undefined, inputs becomes {} (from const { ref, ...inputs } = undefined ?? {}) — so args !== undefined correctly suppresses inputs: {}. But when args is {} (explicit empty object), inputs: {} is forwarded. This is a change in behaviour vs the previous inputs: args path. Confirm whether the downstream dispatch_workflow handler tolerates inputs: {} vs a missing inputs field.

@copilot please address this.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

⚠️ Test Quality Score: 67/100 — Acceptable

Analyzed 7 test(s): 6 design, 1 implementation, 0 violation(s).

📊 Metrics (7 tests)
Metric Value
Analyzed 7 (Go: 0, JS: 7)
✅ Design 6 (86%)
⚠️ Implementation 1 (14%)
Edge/error coverage 3 (43%)
Duplicate clusters 0
Inflation Yes (68 test lines vs 4 production lines, ~17:1)
🚨 Violations 0
Test File Classification Issues
should pass ref as top-level field for dispatch_workflow handler safe_outputs_tools_loader.test.cjs:254 design_test / behavioral_contract / high_value
should handle dispatch_workflow with no inputs (empty object) safe_outputs_tools_loader.test.cjs:285 design_test / behavioral_contract / high_value
should handle dispatch_workflow with undefined args safe_outputs_tools_loader.test.cjs:308 design_test / behavioral_contract / high_value
should drop unknown keys before wrapping dispatch_workflow inputs safe_outputs_tools_loader.test.cjs:399 design_test / behavioral_contract / high_value
should keep strict-schema ref top-level for dispatch_workflow handler safe_outputs_tools_loader.test.cjs:441 design_test / behavioral_contract / high_value
should log stripped key names before wrapping dispatch_workflow inputs safe_outputs_tools_loader.test.cjs:478 implementation_test / implementation_detail / low_value Logging detail only
should sanitize strict-schema args for tools using defaultHandler fallback safe_outputs_tools_loader.test.cjs:509 design_test / behavioral_contract / high_value
⚠️ Flagged Tests (1)

should log stripped key names before wrapping dispatch_workflow inputs — implementation_test. Verifies only debug log message content; no downstream behavioral assertion. Consider merging into the behavioral strip test.

Inflation note: 17:1 ratio is expected — the fix was a 4-line destructuring change requiring multiple scenarios to verify the invariant.

Verdict

passed. 14% implementation tests (threshold: 30%). No guideline violations.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 54.8 AIC · ⌖ 16.7 AIC · ⊞ 8.5K ·
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: 67/100. 14% implementation tests (threshold: 30%). No violations.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot sous-chef triage:

Unresolved review threads remain:

Failed checks:

Please address the unresolved review and CI blockers, refresh the branch if needed, then run the pr-finisher skill and post a concise merge-readiness summary for the current head.

Generated by PR Sous Chef · run: https://github.com/github/gh-aw/actions/runs/30848087243

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 11.5 AIC · ⌖ 11.2 AIC · ⊞ 8.3K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Copilot AI requested a review from gh-aw-bot August 3, 2026 20:12
@pelikhan
pelikhan merged commit da702a8 into main Aug 3, 2026
9 checks passed
@pelikhan
pelikhan deleted the copilot/dispatch-workflow-fix-ref-override branch August 3, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dispatch-workflow: per-call ref override lands in inputs, causing 422 "Unexpected inputs provided" and/or dispatching the wrong ref

4 participants