Skip to content

close-issue: intent-path failures silently fall back to an unreviewed legacy close #64443

Description

@alondahari

Summary

close-issue supports an opt-in issue-intent: true mode that routes the close through the platform's native "intent" API instead of a plain state update, so that automation-control/review policies can gate the change. When that intent request fails, closeIssue() in actions/setup/js/close_issue.cjs catches the error, logs a core.warning, and unconditionally falls back to a plain github.rest.issues.update(...) call with the same state/state_reason. That fallback bypasses whatever policy caused the intent request to fail, and the workflow run still finishes green.

Where

  • actions/setup/js/close_issue.cjs, closeIssue() — the try { ... } catch (error) { core.warning(...) } block that falls through to github.rest.issues.update(baseParams) on any error, regardless of the error type.
  • actions/setup/js/issue_intents.cjs, normalizeIssueIntentMetadata() — only extracts rationale, confidence, and suggest from the intent metadata. It never surfaces a resolved canonical-issue identifier for state_reason: duplicate closes, so the intent request for a duplicate close can never include what the API requires to accept it as a duplicate.

Reproduction

  1. Configure a workflow using close-issue with state-reason: duplicate and issue-intent: true.
  2. Have the agent request closing an issue as a duplicate (e.g. via duplicate_of: <n>), with a repository confidence/review policy configured such that the close must be reviewed rather than applied directly.
  3. Run the workflow.

Actual behavior

  • The intent PATCH request is rejected by the API (HTTP 422: a canonical-issue identifier is required when a close is being routed for review as a duplicate) — because normalizeIssueIntentMetadata() never sends one.
  • closeIssue() logs Issue-intent close path unavailable, falling back to legacy close path: ... and immediately calls github.rest.issues.update() with a plain state: "closed", state_reason: "duplicate".
  • The issue closes immediately, with no review, no rationale/confidence metadata, and no recorded relationship to the canonical issue.
  • The workflow step and run both complete successfully (no failure surfaced).

Expected behavior

  1. A validation-level failure (4xx) on the intent path must not silently fall back to an unreviewed, un-gated write. The action should fail the item (or otherwise clearly report incomplete/failed) instead of downgrading to a legacy close, so a configured review requirement cannot be bypassed by a client-side error.
    • Falling back may still be reasonable for errors that indicate the intent feature/endpoint itself is unavailable (e.g. 404/501), but not for 4xx validation rejections, which represent a policy decision that must be respected, not retried through a different path.
  2. (Secondary / follow-up) normalizeIssueIntentMetadata() should resolve duplicate_of to the canonical issue's identifier and include it in the intent metadata when state_reason is duplicate, so a well-formed duplicate-close intent request can succeed in the first place rather than always failing validation.
  3. (Secondary / follow-up) The markAsDuplicate GraphQL mutation called elsewhere in the duplicate-close flow currently fails for every run with Field 'markAsDuplicate' doesn't exist on type 'Mutation'. Once a duplicate-close intent request can carry the canonical-issue identifier (item 2), that call may be redundant and worth removing rather than fixed.

Priority

Item 1 (fail instead of silently falling back) is the priority — it's what allows an unreviewed state change to slip through today. Items 2 and 3 are secondary correctness/cleanup follow-ups.

Version

Observed on gh-aw v0.88.8.

No activity

Activity on this issue will appear here.

Activity

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

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions