Skip to content

remove_labels and assign_to_user safe output handlers do not support target-repo for cross-repository operationsΒ #15216

@benvillalobos

Description

@benvillalobos

πŸ€–: Bug report submitted by AI

Summary

Follow-up to #15027 β€” the same context.repo hardcoding bug that was fixed in add_labels.cjs and close_issue.cjs also exists in remove_labels.cjs and assign_to_user.cjs. Both handlers ignore the target-repo config and always operate against the workflow's own repository.

Affected Files

actions/setup/js/remove_labels.cjs

  • Lines 11-12: Only imports safe_output_validator.cjs and error_helpers.cjs β€” does NOT import repo_helpers.cjs
  • Line 124: Hardcoded ...context.repo in the removeLabel API call:
    await github.rest.issues.removeLabel({
      ...context.repo,
      issue_number: itemNumber,
      name: label,
    });

actions/setup/js/assign_to_user.cjs

  • Lines 8-9: Only imports safe_output_processor.cjs and error_helpers.cjs β€” does NOT import repo_helpers.cjs
  • Lines 104-105: Hardcoded context.repo.owner / context.repo.repo in the addAssignees API call:
    await github.rest.issues.addAssignees({
      owner: context.repo.owner,
      repo: context.repo.repo,
      issue_number: issueNumber,
      assignees: uniqueAssignees,
    });

Root Cause

When #15027 was fixed, add_labels.cjs and close_issue.cjs were updated to use resolveTargetRepoConfig / resolveAndValidateRepo from repo_helpers.cjs. The same fix was not applied to remove_labels.cjs and assign_to_user.cjs.

The Plumbing Already Works

Everything upstream of the handler JS is wired correctly:

  1. Go compiler structs: Both RemoveLabelsConfig and AssignToUserConfig embed SafeOutputTargetConfig (which provides TargetRepoSlug and AllowedRepos)
  2. Config generation (compiler_safe_outputs_config.go): The remove_labels builder calls AddIfNotEmpty("target-repo", c.TargetRepoSlug) and AddStringSlice("allowed_repos", c.AllowedRepos). The assign_to_user builder similarly extracts the config via addRepoParameterIfNeeded in safe_outputs_config_generation.go (line 894-898).
  3. Docs (.github/aw/github-agentic-workflows.md): Both remove-labels and assign-to-user document target-repo as a supported field.
  4. MCP tool schema: The compiler correctly adds the repo parameter to the safe-outputs MCP tool description when allowed-repos is configured.

The config IS passed correctly at runtime β€” it's just never read by the handlers.

Fix

Apply the exact same pattern from add_labels.cjs (the fix from #15027):

For each handler:

  1. Add the import:

    const { resolveTargetRepoConfig, resolveAndValidateRepo } = require("./repo_helpers.cjs");
  2. In the main() factory function, resolve the target repo from config:

    const { defaultTargetRepo, allowedRepos } = resolveTargetRepoConfig(config);
  3. In the message handler function, resolve and validate per-message:

    const repoResult = resolveAndValidateRepo(message, defaultTargetRepo, allowedRepos, "label"); // or "assignee"
    if (!repoResult.success) {
      core.warning(`Skipping: ${repoResult.error}`);
      return { success: false, error: repoResult.error };
    }
    const { repo: itemRepo, repoParts } = repoResult;
  4. Replace context.repo / ...context.repo with repoParts.owner / repoParts.repo in the API call.

Reference implementation: actions/setup/js/add_labels.cjs lines 13, 24, 57, 65, 127-128

Use Case

We're building a stale-issue re-triage workflow in a side repo (gh-aw-test) that will eventually run cross-repo from microsoft/vscode-engineering against microsoft/vscode. The workflow needs to:

Reproduction

  1. Create a workflow with target-repo set to an external repo:
    safe-outputs:
      remove-labels:
        allowed: ["triage-needed"]
        target-repo: "org/other-repo"
      assign-to-user:
        max: 1
        target-repo: "org/other-repo"
  2. Trigger the workflow and have the agent call remove_labels or assign_to_user on an issue in the external repo
  3. Both will 404 because they operate on context.repo instead of the configured target repo

Metadata

Metadata

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