Skip to content

Support temporary IDs for dispatched workflow runs - #53572

Closed
pelikhan with Copilot wants to merge 3 commits into
mainfrom
copilot/support-temporary-ids-workflow
Closed

Support temporary IDs for dispatched workflow runs#53572
pelikhan with Copilot wants to merge 3 commits into
mainfrom
copilot/support-temporary-ids-workflow

Conversation

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Agents can now assign a temporary ID when dispatching a workflow and reuse it to approve the returned workflow run.

  • Dispatch workflow

    • Adds optional temporary_id to generated dispatch tools and output schemas.
    • Registers the API-returned workflow_run_id in the safe-output temporary-ID map.
  • Approve workflow run

    • Accepts a dispatched-run temporary ID as run_id.
    • Resolves IDs only for runs in the current repository.
{ "temporary_id": "aw_deploy1" }
{ "run_id": "aw_deploy1" }

Run: https://github.com/github/gh-aw/actions/runs/32103414328> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14 AIC · ⌖ 7.84 AIC · ⊞ 8.8K ·

Comment /souschef to run again

Copilot AI and others added 2 commits August 18, 2026 03:04
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI requested a review from pelikhan August 18, 2026 03:20
@pelikhan
pelikhan marked this pull request as ready for review August 18, 2026 04:02
Copilot AI balanced review requested due to automatic review settings August 18, 2026 04:02
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

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

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

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Ponytail review complete. Reviewed the PR diff (approve_workflow_run.cjs, dispatch_workflow.cjs, safe_outputs_dispatch.go, safe_outputs_validation_config.go, plus generated tool-schema/test files). The change reuses existing temporary_id.cjs helpers (resolveIssueNumber, loadTemporaryIdMapFromResolved) and existing FieldValidation config patterns rather than introducing new abstractions. It is a small, consistent wiring change with no speculative flexibility, dead code, or hand-rolled logic duplicating existing utilities. Lean already. Ship.

Generated by Ponytail Reviewer for #53572

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-18T00:00:00Z
review_event: REQUEST_CHANGES
top_themes:
  - temporary-id-to-run-id resolution accepts non-integer values from resolved maps
  - non-strict workflow recompiles now fail under strict policy by design
files_reviewed:
  - .github/workflows/daily-team-evolution-insights.lock.yml
  - .github/workflows/mcp-inspector.lock.yml
  - actions/setup/js/approve_workflow_run.cjs
  - actions/setup/js/dispatch_workflow.cjs
  - actions/setup/js/safe_outputs_tools_loader.cjs
  - pkg/workflow/safe_outputs_dispatch.go
  - pkg/workflow/safe_outputs_validation_config.go
  - schemas/agent-output.json
comment_count: 2

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 18.8 AIC · ⌖ 6.97 AIC · ⊞ 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.

Requesting changes

This patch introduces one real correctness hole in the new temporary-ID approval path, and it also recompiles existing lockfiles from strict to non-strict so policy-enabled installs would start failing those workflows at runtime.

Blocking themes
  • approve_workflow_run no longer consistently validates resolved temporary IDs as positive integer run IDs before calling the Actions API.
  • Two regenerated workflow lockfiles silently downgrade from strict compilation to non-strict, which is a behavior regression for environments enforcing GH_AW_POLICY_STRICT=true.

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 18.8 AIC · ⌖ 6.97 AIC · ⊞ 7K
Comment /review to run again

const runId = parsePositiveInt(message.run_id);
return async function handleApproveWorkflowRun(message, resolvedTemporaryIds = {}) {
const resolvedRunId = resolveIssueNumber(message.run_id, loadTemporaryIdMapFromResolved(resolvedTemporaryIds));
const runId = resolvedRunId.wasTemporaryId ? (resolvedRunId.resolved?.number ?? undefined) : parsePositiveInt(message.run_id);

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.

The new approve_workflow_run path trusts resolvedTemporaryIds[...].number without re-validating it as a positive integer, so a malformed or fractional mapping can now flow straight into getWorkflowRun/approval instead of being rejected like direct run_id input is.

💡 Why this needs fixing

resolveIssueNumber() converts number with Number(...), but this call site never re-applies parsePositiveInt() when the source was a temporary ID:

const runId = resolvedRunId.wasTemporaryId
  ? (resolvedRunId.resolved?.number ?? undefined)
  : parsePositiveInt(message.run_id);

That means values like 1.5, 0, -1, or NaN coming from the resolved map can bypass the existing integer validation path and get sent to the Actions API. At best this becomes a flaky runtime failure; at worst it weakens the contract that approve_workflow_run only accepts positive integer run IDs.

Please normalize the resolved temporary-ID value through the same positive-integer validator before using it, and add a test that rejects a temporary ID mapped to a non-integer/non-positive number.

@@ -153,7 +153,7 @@ jobs:
GH_AW_INFO_FIREWALL_TYPE: "squid"

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.

These regenerated lockfiles now advertise GH_AW_COMPILED_STRICT: "false", so turning on GH_AW_POLICY_STRICT will hard-fail these workflows at runtime instead of preserving the previous strict behavior.

💡 Why this is a regression

This PR changes both metadata and runtime env from strict to non-strict and relies on the new enforcement step to catch it later:

GH_AW_COMPILED_STRICT: "false"
- name: Enforce strict mode policy

That is not a neutral refactor. Any repository/org that enables GH_AW_POLICY_STRICT=true will now see these workflows fail before doing useful work, even though the same lockfiles previously compiled as strict and ran successfully.

If the downgrade is intentional, the source workflow/frontmatter needs to be updated and justified. Otherwise this is a bad recompile and the lockfiles should stay strict so policy-enabled installations do not break.

@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: Support temporary IDs for dispatched workflow runs

The implementation is well-structured and consistent across all layers (Go validation config, JSON schemas, CJS handlers, and tests).

Security: The cross-repo guard in approve_workflow_run.cjs correctly rejects temporary IDs whose repo doesn't match the current context.repo.owner/context.repo.repo, preventing a run from one repository being approved from another.

Correctness: The wasTemporaryId flag cleanly separates the two resolution paths — numeric IDs fall through to the existing parsePositiveInt path; temporary IDs are resolved via loadTemporaryIdMapFromResolved. The early !runId guard ensures the cross-repo check only fires when the ID was actually found in the resolved map.

Completeness: All schema files (schemas/agent-output.json, both copies of safe_outputs_tools.json), validation config (safe_outputs_validation_config.go), and the tool generator (safe_outputs_dispatch.go) are updated consistently. Tests cover the happy path, the cross-repo rejection, and the missing-run-ID warning.

No blocking issues found. ✅

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 35.9 AIC · ⌖ 8.83 AIC · ⊞ 5.7K

@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 /tdd and /grill-with-docs — requesting changes on three correctness/coverage gaps and one schema consistency issue.

📋 Key Themes & Highlights

Key Themes

  • Undefined-repo guard (approve_workflow_run.cjs): if a stored temporary-ID entry has number but no repo, the cross-repo comparison silently passes and the error message says "belongs to undefined". The guard needs to handle a missing repo field explicitly, with a matching regression test.
  • Missing test for the no-run-id warning path (dispatch_workflow.cjs): the branch that fires core.warning when the API returns no workflow_run_id has no automated test — the temporaryId field absence is untested.
  • Schema gap (schemas/agent-output.json): run_id in approve_workflow_run accepts any string; the temporary-ID pattern constraint from dispatch_workflow's temporary_id should be applied to the string branch here too.
  • Inputs-leak assertion missing (safe_outputs_tools_loader.test.cjs): the new test confirms temporary_id is passed to the handler, but doesn't assert it was removed from inputs.

Positive Highlights

  • ✅ Cross-repo guard is a solid security boundary — good defensive design.
  • ✅ Test coverage is thorough for the happy path and the cross-repo rejection case.
  • ✅ Pattern validation is consistent across Go and JS validation layers.
  • ✅ Clean separation: temporary_id destructuring in safe_outputs_tools_loader.cjs keeps the concern out of individual handlers.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 63.3 AIC · ⌖ 10.4 AIC · ⊞ 7.8K
Comment /matt to run again

core.warning(error);
return { success: false, error };
}
const resolvedRepo = resolvedRunId.resolved?.repo;

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] resolvedRepo can be undefined when a stored temporary ID entry has number but no repo field — the cross-repo guard would produce a misleading error like "belongs to undefined".

💡 Suggested fix + regression test

Guard before comparing:

const resolvedRepo = resolvedRunId.resolved?.repo;
if (resolvedRunId.wasTemporaryId) {
  if (!resolvedRepo) {
    const error = `Temporary workflow run ID '${message.run_id}' does not contain a repository reference`;
    core.warning(error);
    return { success: false, error };
  }
  if (resolvedRepo !== `${context.repo.owner}/${context.repo.repo}`) {
    const error = `Temporary workflow run ID '${message.run_id}' belongs to ${resolvedRepo}, not ${context.repo.owner}/${context.repo.repo}`;
    core.warning(error);
    return { success: false, error };
  }
}

And add a test:

it("rejects a temporary ID with missing repo field", async () => {
  const handler = await main(externalTokenConfig);
  const result = await handler({ run_id: "aw_run123" }, { aw_run123: { number: 123 } });
  expect(result.success).toBe(false);
  expect(result.error).toContain("does not contain a repository reference");
});

@copilot please address this.

core.info(`✓ Successfully dispatched workflow: ${workflowFile} (run ID: ${runId})`);
} else {
core.info(`✓ Successfully dispatched workflow: ${workflowFile}`);
if (typeof message.temporary_id === "string") {

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] Missing test for dispatch_workflow when temporary_id is provided but the API returns no workflow_run_id — the warning branch fires but there's no assertion that temporaryId is absent from the response.

💡 Suggested test
it("should not include temporaryId when API returns no workflow_run_id", async () => {
  github.rest.actions.createWorkflowDispatch.mockResolvedValueOnce({ data: {} }); // no workflow_run_id
  const handler = await main({ workflows: ["test-workflow"], workflow_files: { "test-workflow": ".lock.yml" } });
  const result = await handler({ type: "dispatch_workflow", workflow_name: "test-workflow", temporary_id: "aw_run123", inputs: {} }, {});
  expect(result.success).toBe(true);
  expect(result.temporaryId).toBeUndefined();
  expect(core.warning).toHaveBeenCalledWith(expect.stringContaining("aw_run123"));
});

Without this test the warning path is exercised only manually.

@copilot please address this.

Comment thread schemas/agent-output.json
"run_id": {
"oneOf": [{ "type": "number" }, { "type": "string" }],
"description": "Positive integer workflow run ID to approve"
"description": "Positive integer workflow run ID to approve, or a temporary ID returned by dispatch_workflow"

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.

[/grill-with-docs] The agent-output.json schema still uses "oneOf": [{ "type": "number" }, { "type": "string" }] for run_id in approve_workflow_run without adding a pattern constraint for the temporary ID string form — any arbitrary string passes JSON Schema validation.

💡 Suggested schema tightening
"run_id": {
  "oneOf": [
    { "type": "number" },
    { "type": "string", "pattern": "^#?aw_[A-Za-z0-9_]{3,12}$" }
  ],
  "description": "Positive integer workflow run ID to approve, or a temporary ID returned by dispatch_workflow"
}

This keeps the schema consistent with the dispatch_workflow temporary_id pattern already defined in the same file.

@copilot please address this.

const handlers = { defaultHandler: vi.fn(() => mockHandlerFunction) };

const result = attachHandlers(tools, handlers);
result[0].handler({ environment: "staging", temporary_id: "aw_run123" });

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 safe_outputs_tools_loader.cjs test added for temporary_id passes the value through attachHandlers, but there is no test verifying that temporary_id is absent from the inputs object forwarded to the handler — confirming the destructuring split is correct.

💡 Suggested assertion to add
expect(mockHandlerFunction).toHaveBeenCalledWith(
  expect.objectContaining({
    temporary_id: "aw_run123",
    inputs: expect.not.objectContaining({ temporary_id: expect.anything() }),
  })
);

Without this, a regression where temporary_id leaks into inputs would go undetected.

@copilot please address this.

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 temporary-ID plumbing between workflow dispatch and run approval safe outputs.

Changes:

  • Adds temporary_id to dispatch schemas and generated tools.
  • Registers returned workflow run IDs and resolves them during approval.
  • Updates tests and regenerated workflow artifacts.
Show a summary per file
File Description
schemas/agent-output.json Extends dispatch and approval schemas.
pkg/workflow/safe_outputs_validation_config.go Allows temporary IDs for approvals.
pkg/workflow/safe_outputs_tools_generation_test.go Tests generated dispatch schemas.
pkg/workflow/safe_outputs_dispatch.go Adds temporary IDs to dispatch tools.
pkg/workflow/safe_output_validation_config_test.go Updates approval validation tests.
pkg/workflow/js/safe_outputs_tools.json Updates embedded approval documentation.
actions/setup/js/safe_outputs_tools.json Updates runtime tool documentation.
actions/setup/js/safe_outputs_tools_loader.test.cjs Tests dispatch argument separation.
actions/setup/js/safe_outputs_tools_loader.cjs Separates temporary IDs from workflow inputs.
actions/setup/js/dispatch_workflow.test.cjs Tests returned run-ID mappings.
actions/setup/js/dispatch_workflow.cjs Registers dispatched run mappings.
actions/setup/js/approve_workflow_run.test.cjs Tests temporary-ID resolution and repository checks.
actions/setup/js/approve_workflow_run.cjs Resolves temporary IDs before approval.
.github/workflows/mcp-inspector.lock.yml Regenerates non-strict workflow metadata.
.github/workflows/daily-team-evolution-insights.lock.yml Regenerates non-strict workflow metadata.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

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

Comment on lines +134 to +135
const resolvedRunId = resolveIssueNumber(message.run_id, loadTemporaryIdMapFromResolved(resolvedTemporaryIds));
const runId = resolvedRunId.wasTemporaryId ? (resolvedRunId.resolved?.number ?? undefined) : parsePositiveInt(message.run_id);
DefaultMax: 1,
Fields: map[string]FieldValidation{
"run_id": {Required: true, PositiveInteger: true},
"run_id": {Required: true, IssueNumberOrTemporaryID: true},
Comment on lines +134 to +138
properties["temporary_id"] = map[string]any{
"type": "string",
"description": "Optional temporary ID to associate with the dispatched workflow run. Use this ID as the run_id in a later approve_workflow_run call.",
"pattern": "^#?aw_[A-Za-z0-9_]{3,12}$",
}
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Please address the blocking review feedback below, refresh the branch if needed, then run the pr-finisher skill and report back with validation results and any remaining blockers.

Run: https://github.com/github/gh-aw/actions/runs/32100908477

Generated by 👨🍳 PR Sous Chef · gpt54

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 32.3 AIC · ⌖ 10 AIC · ⊞ 8.8K ·
Comment /souschef to run again

@github-actions

Copy link
Copy Markdown
Contributor

👏 Great work! This PR looks ready for review. The temporary ID feature is well-implemented with:

  • Clear focus — all changes are scoped to adding temporary ID support for workflow dispatch and approval
  • Comprehensive tests — added 4 new test cases covering temporary ID resolution, rejection of cross-repo IDs, and parameter passing
  • Good documentation — PR body explains the feature with clear examples
  • Consistent schema updates — JSON schemas, Go validation config, and TypeScript handlers all updated in sync

The implementation correctly validates that temporary IDs are only resolved for runs in the current repository, which is a good security boundary.

This follows the project agentic development process and maintains the quality standards of the gh-aw codebase.

Generated by ✅ Contribution Check · auto · 47 AIC · ⌖ 8.51 AIC · ⊞ 9.2K ·

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot return workflow url if from another repo

@pelikhan pelikhan closed this Aug 18, 2026
Copilot stopped work on behalf of gh-aw-bot due to an error August 18, 2026 05:39
Copilot AI requested a review from gh-aw-bot August 18, 2026 05:39
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot
Please follow up on these unresolved review threads:

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14 AIC · ⌖ 7.84 AIC · ⊞ 8.8K ·
Comment /souschef to run again

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants