Skip to content

[agent-issue]: GitHub issue safe outputs are create-only — port gh-aw's issue mutation family #1871

Description

@JamesBurnside

Submission requirements

  • I generated this issue with an agent that used .github/agents/ado-aw.agent.md.
  • I reviewed the generated issue and confirm it is being filed directly in githubnext/ado-aw.

Problem summary

#1670 added create-github-issue and set-github-issue-type, which closed #1621. Those two are
still the entire GitHub-issue surface: as of 0.49.0 there is no supported way for an ado-aw
workflow to comment on, label, unlabel, close, or update an existing GitHub issue.

This is a parity gap with gh-aw, and an asymmetry inside ado-aw itself.

gh-aw exposes the full lifecycle for GitHub issues — add-comment, hide-comment, add-labels,
remove-labels, close-issue, update-issue, set-issue-field, assign-milestone,
assign-to-user, unassign-from-user, link-sub-issue.

ado-aw already ships those same semantics for Azure DevOps work items: comment-on-work-item
(whose own doc line reads "This is the ADO equivalent of gh-aw's add-comment tool"),
update-work-item (per-field opt-in for state/title/body/tags/assignee) and create-work-item.

So an ado-aw workflow can run a full lifecycle against an ADO work item, but against a GitHub issue
it can only ever create one and then never touch it again.

Impact. This affects teams whose pipelines are in Azure DevOps but whose issue tracking is in GitHub —
the case ado-aw's GitHub-issue outputs exist to serve. Every post-creation write has to leave the
safe-output model: mint a GitHub App installation token in a hand-written pipeline stage and call the
REST API directly. That code then sits outside threat detection's output gating, outside the max
budgets, outside target/allowlist scoping, and outside Stage 3's credential isolation and token
revocation. It also has to re-implement idempotency by hand — we maintain a marker-comment upsert
with Bot-author matching and duplicate reconciliation purely because there is no add-comment with
an equivalent of gh-aw's hide-older-comments.

This is incremental, not new infrastructure. set-github-issue-type already mutates an
existing issue by numeric issue_number in a configured target-repo, so the Stage 3 GitHub
credential path (PAT, shared engine App, or dedicated safe-outputs.github-app), target-repo
resolution, minimum-permission derivation and token revocation all shipped with #1670. The mutation
family would sit on top of that rather than beside it.

Separately, the two tools that did ship are missing gh-aw's per-tool scoping fields
(target, required-labels, required-title-prefix, allowed-repos), which are the mechanism
gh-aw uses to bound which issues a workflow may touch. Those matter more, not less, once
mutation is possible.

Reproduction details

Environment: ado-aw 0.49.0 (windows-x64), Copilot engine, target: stage.

Baseline — the two shipped tools compile:

safe-outputs:
  create-github-issue:
    target-repo: octo-org/octo-repo

Generated stage template: probe.lock.yml

1) No comment tool for GitHub issues. Under both the gh-aw name and the ado-aw naming
convention:

safe-outputs:
  add-comment:
    target: "*"
Error: safe-outputs contains unrecognised tool name(s):
  - add-comment (similar known tools: add-build-tag, add-pr-comment)
safe-outputs:
  comment-on-github-issue:
    target: "*"
Error: safe-outputs contains unrecognised tool name(s):
  - comment-on-github-issue (similar known tools: comment-on-work-item)

That second suggestion is the gap in one line: the compiler points at the work-item tool because the
GitHub equivalent does not exist.

2) No label tools.

safe-outputs:
  add-labels:
    allowed: [bug]
Error: safe-outputs contains unrecognised tool name(s):
  - add-labels (similar known tools: add-build-tag, add-pr-comment)

remove-labels behaves the same. Note update-pr does accept an add-labels operation, but that
is an Azure DevOps pull request, not a GitHub issue.

3) No close or update.

safe-outputs:
  close-github-issue:
    target: "*"
Error: safe-outputs contains unrecognised tool name(s):
  - close-github-issue
safe-outputs:
  update-github-issue:
    target: "*"
Error: safe-outputs contains unrecognised tool name(s):
  - update-github-issue (similar known tools: update-pr, update-wiki-page, update-work-item)

4) The shipped tools accept no issue-scoping fields.

Error: safe-outputs.set-github-issue-type has invalid configuration:
  unknown field `target`, expected one of `target-repo`, `allowed`, `max`

Error: safe-outputs.set-github-issue-type has invalid configuration:
  unknown field `required-labels`, expected one of `target-repo`, `allowed`, `max`

Error: safe-outputs.create-github-issue has invalid configuration:
  unknown field `allowed-repos`, expected one of `target-repo`, `title-prefix`,
  `labels`, `allowed-labels`, `assignees`, `require-temporary-id`, `max`

Observed: the GitHub-issue safe outputs are create-only, and unscoped beyond target-repo.
Expected: parity with gh-aw's GitHub-issue family, matching the lifecycle coverage ado-aw already
provides for ADO work items.

Proposed next step

Port gh-aw's GitHub-issue safe outputs to ado-aw as a family rather than one at a time, so workflows
are not blocked again on the next field. Suggested area: src/safe_outputs/ alongside the existing
create_github_issue.rs / set_github_issue_type.rs, reusing the Stage 3 GitHub auth, target-repo
resolution and minimum-permission derivation that #1670 already established.

Requested coverage, in rough priority order for the ADO-pipelines / GitHub-issues topology:

gh-aw output Purpose Note
add-comment Comment on an existing issue Highest value. ado-aw's comment-on-work-item is the direct precedent; hide-older-comments is what removes hand-rolled marker upserts
add-labels / remove-labels Issue state transitions gh-aw's allowed + blocked glob evaluation order is the injection-resistant design worth carrying over
close-issue Close, with optional comment, state-reason and duplicate_of
update-issue Title / body / status, with append/prepend/replace/replace-island replace-island is the durable-status-block pattern
set-issue-field Set one issue field by name Natural companion to the set-github-issue-type that shipped
hide-comment Retire superseded agent comments
assign-to-user / unassign-from-user / assign-milestone / link-sub-issue Remaining lifecycle Lower priority; listed for completeness so the family is not left half-ported

Also worth adding to the tools that already shipped, since they become load-bearing once mutation
exists: target (triggering / * / number), required-labels, required-title-prefix and
allowed-repos, matching gh-aw's semantics.

Two ado-aw-specific points that would need a decision, raised here rather than assumed:

  1. Naming. gh-aw's add-comment and add-labels are ambiguous in ado-aw, which addresses both
    ADO work items and GitHub issues from one safe-outputs block and already has add-pr-comment
    and comment-on-work-item. A *-github-issue suffix (comment-on-github-issue,
    add-github-issue-labels) would match the create-github-issue / set-github-issue-type
    convention feat(safeoutputs): add GitHub issue outputs #1670 established, at the cost of gh-aw source compatibility. The compiler's own
    "similar known tools" suggestion already assumes the latter shape.
  2. Triggering-issue targeting. gh-aw's target: "triggering" default derives the issue from the
    GitHub event that started the run. ado-aw workflows are commonly started by an ADO webhook
    resource carrying a GitHub payload, so there may be no ambient triggering issue. Defaulting to
    an explicit issue_number — as set-github-issue-type already does — is probably the honest
    behaviour, with triggering supported only where a GitHub-backed build provides it.

Related: #1621 (issue types, closed by #1670).


Posted by Copilot CLI assistant.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions