Skip to content

Add blocked deny list for assign-to-user and unassign-from-user safe outputs#16628

Merged
pelikhan merged 6 commits intomainfrom
copilot/add-blocked-deny-list-feature
Feb 18, 2026
Merged

Add blocked deny list for assign-to-user and unassign-from-user safe outputs#16628
pelikhan merged 6 commits intomainfrom
copilot/add-blocked-deny-list-feature

Conversation

Copy link
Contributor

Copilot AI commented Feb 18, 2026

Implementation Complete: blocked deny list for assign-to-user safe output

  • Add Blocked field to AssignToUserConfig struct in pkg/workflow/assign_to_user.go
  • Add Blocked field to UnassignFromUserConfig struct in pkg/workflow/unassign_from_user.go
  • Create generateMaxWithAllowedAndBlockedConfig helper in pkg/workflow/safe_outputs_config_generation_helpers.go
  • Update safe output config generation for assign-to-user and unassign-from-user in pkg/workflow/safe_outputs_config_generation.go
  • Implement generic glob pattern matching in actions/setup/js/glob_pattern_helpers.cjs
  • Update processItems function in actions/setup/js/safe_output_processor.cjs to filter blocked items
  • Update JavaScript handler actions/setup/js/assign_to_user.cjs to use blocked configuration
  • Update JavaScript handler actions/setup/js/unassign_from_user.cjs to use blocked configuration
  • Add tests for pattern matching in actions/setup/js/glob_pattern_helpers.test.cjs
  • Add tests for blocked patterns in actions/setup/js/assign_to_user.test.cjs
  • Update documentation in docs/src/content/docs/reference/safe-outputs.md
  • Update JSON schema to include blocked field in pkg/parser/schemas/main_workflow_schema.json
  • Test compilation with blocked patterns
  • Run validation: make fmt and make lint
  • Verify workflow recompilation
  • Refactor to use generic glob pattern helpers (addressing PR feedback)
  • Deduplicate pattern matching logic (final refactoring)

Latest Changes

Deduplicated glob pattern matching implementation to eliminate code duplication:

Refactored glob_pattern_helpers.cjs:

  • Added escapeRegexChars() internal helper for consistent special character escaping
  • Enhanced globPatternToRegex() with optional options parameter:
    • pathMode (default: true): Controls how * is interpreted
    • caseSensitive (default: true): Controls case sensitivity
  • Simplified simpleGlobToRegex() to call globPatternToRegex() with pathMode: false
  • Fixed TypeScript type annotations for optional parameters

Updated callers:

  • parseGlobPatterns() - Uses arrow function to pass pattern correctly
  • push_repo_memory.cjs - Updated map call to use arrow function
  • Test files - Updated to use arrow functions with map

Benefits:

  • Single source of truth for regex escaping logic
  • Reduced code duplication by ~15 lines
  • More maintainable and consistent behavior
  • TypeScript type safety maintained
Original prompt

This section details on the original issue you should resolve

<issue_title>Feature request: blocked deny list for assign-to-user safe output</issue_title>
<issue_description>🤖 Filed with agentic-workflows agent mid-design conversation

Problem

The assign-to-user safe output currently supports assignees: [list] (allowlist) and max: N (count cap), but has no way to deny specific users or patterns from being assigned.

In workflows that process untrusted public input (e.g., issue triage on microsoft/vscode), a prompt injection attack could attempt to trick the agent into assigning copilot or other bot accounts to issues — which would trigger Copilot coding agent sessions or other unintended automated actions. Currently this can only be prevented via prompt-level instructions ("never assign copilot"), which is not a reliable defense against adversarial input.

Maintaining an exhaustive allowlist is also impractical when the set of valid assignees changes as team members rotate.

Proposed Solution

Add a blocked: field to assign-to-user (and potentially unassign-from-user) safe outputs:

safe-outputs:
  assign-to-user:
    blocked: ["copilot", "*[bot]"]   # deny specific users or patterns
    max: 1

This should support:

  • Exact user matches (e.g., copilot)
  • Pattern matching for bot accounts (e.g., *[bot] to deny all bot suffixed accounts)

Why This Matters

For workflows processing untrusted content, the safe-outputs config is the hard security boundary. A compromised agent that assigns copilot to an issue could trigger an autonomous coding agent session on attacker-controlled issue content — escalating a prompt injection from "triage manipulation" to "code execution." Being able to deny dangerous assignees at the infrastructure layer would close this escalation path.

Related

This is the assign-to-user counterpart to #16625 (blocked patterns for add-labels).

Current Workaround

Prompt-level instructions telling the agent not to assign bot accounts. Works under normal conditions but is not a reliable defense against adversarial input.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.



✨ PR Review Safe Output Test - Run 22157554498

💥 [THE END] — Illustrated by Smoke Claude


Changeset

  • Type: patch
  • Description: Added blocked deny-list support for the assign-to-user and unassign-from-user safe outputs so workflows can refuse risky assignees via glob patterns.

Generated by Changeset Generator

Copilot AI and others added 2 commits February 18, 2026 19:44
…outputs

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…assign-from-user

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add blocked deny list for assign-to-user output Add blocked deny list for assign-to-user and unassign-from-user safe outputs Feb 18, 2026

// Simple glob pattern matching
// Convert glob pattern to regex: "*[bot]" -> "^.*\[bot\]$"
const regexPattern = pattern
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot review for security

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored in commit 7102cba. The regex pattern escaping now uses the generic simpleGlobToRegex() function from glob_pattern_helpers.cjs, which properly escapes all special regex characters except *.

.replace(/[.+?^${}()|[\]\\]/g, "\\$&") // Escape special regex chars except *
.replace(/\*/g, ".*"); // Convert * to .*

const regex = new RegExp(`^${regexPattern}$`, "i"); // Case-insensitive
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot review for security

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored in commit 7102cba. The regex construction is now delegated to matchesSimpleGlob() in glob_pattern_helpers.cjs, which handles case-insensitive matching by default.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
return patterns.some(pattern => pattern.test(filePath));
}

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot deduplicate with globPatternToRegex

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deduplicated in commit 0626e1a. The simpleGlobToRegex() function now reuses globPatternToRegex() with pathMode: false option, sharing the same escaping logic through a new escapeRegexChars() helper.

…e globPatternToRegex

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan marked this pull request as ready for review February 18, 2026 20:41
Copilot AI review requested due to automatic review settings February 18, 2026 20:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a blocked deny list feature to assign-to-user and unassign-from-user safe outputs to provide defense-in-depth against prompt injection attacks. The feature allows workflow authors to block specific users or patterns (e.g., copilot, *[bot]) from being assigned to issues, preventing attackers from escalating prompt injection attacks into triggering automated agent sessions.

Changes:

  • Added blocked field to AssignToUserConfig and UnassignFromUserConfig structs with pattern matching support
  • Implemented generic glob pattern matching helpers with deduplication of regex escaping logic
  • Updated safe output processing pipeline to filter blocked items after allowed filtering
  • Added comprehensive test coverage for pattern matching and the assign-to-user handler
  • Updated JSON schema and documentation with clear examples and security context

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/workflow/assign_to_user.go Added Blocked field to config struct with YAML tag and documentation
pkg/workflow/unassign_from_user.go Added Blocked field to config struct with YAML tag and documentation
pkg/workflow/safe_outputs_config_generation_helpers.go Created generateMaxWithAllowedAndBlockedConfig helper function
pkg/workflow/safe_outputs_config_generation.go Updated config generation to use new helper with blocked parameter
pkg/parser/schemas/main_workflow_schema.json Added blocked field schema with clear descriptions for both handlers
docs/src/content/docs/reference/safe-outputs.md Updated documentation with examples and security explanation
actions/setup/js/glob_pattern_helpers.cjs Refactored with escapeRegexChars() helper and enhanced globPatternToRegex() with options
actions/setup/js/safe_output_processor.cjs Added filterByBlocked() function and integrated into processItems pipeline
actions/setup/js/safe_output_helpers.cjs Added matchesBlockedPattern() and isUsernameBlocked() helper functions
actions/setup/js/assign_to_user.cjs Updated to extract and use blocked configuration
actions/setup/js/unassign_from_user.cjs Updated to extract and use blocked configuration
actions/setup/js/glob_pattern_helpers.test.cjs Added comprehensive tests for simple glob matching
actions/setup/js/safe_output_helpers.test.cjs Added tests for blocked pattern matching functions
actions/setup/js/assign_to_user.test.cjs Added comprehensive tests for blocked pattern filtering
actions/setup/js/push_repo_memory.cjs Updated to use arrow function syntax for pattern mapping
actions/setup/js/push_repo_memory.test.cjs Updated test to use arrow function syntax

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

async function main(config = {}) {
// Extract configuration
const allowedAssignees = config.allowed || [];
const blockedAssignees = config.blocked || [];
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unassign_from_user.test.cjs file is missing test coverage for the new blocked patterns feature. While assign_to_user.test.cjs has comprehensive tests for blocked patterns (lines 487-587), the unassign_from_user handler should have similar test coverage to ensure the blocked filtering works correctly for unassignments as well.

Consider adding tests for:

  • Filtering out blocked users by exact match
  • Filtering out blocked users by pattern (e.g., *[bot])
  • Combining allowed and blocked filters
  • Handling empty results when all users are blocked

Copilot uses AI. Check for mistakes.
* @param {string[]|undefined} blockedPatterns - Blocked patterns list (undefined means no blocking)
* @returns {string[]} Filtered items with blocked items removed
*/
function filterByBlocked(items, blockedPatterns) {
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The safe_output_processor.test.cjs file is missing test coverage for the new filterByBlocked function. The function is exported from the module and used in the processItems pipeline, but there are no direct tests to verify its behavior.

Consider adding tests for:

  • Filtering items with exact pattern matches
  • Filtering items with glob patterns
  • Handling empty or undefined blocked patterns
  • Integration with the processItems pipeline

Copilot uses AI. Check for mistakes.
@pelikhan pelikhan added the smoke label Feb 18, 2026
@github-actions
Copy link
Contributor

🧪 Smoke Project is now testing project operations...

@github-actions
Copy link
Contributor

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 18, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

🧪 Smoke Temporary ID is now testing temporary ID functionality...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 18, 2026

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

@github-actions
Copy link
Contributor

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.52.0
jq 1.7
yq 4.52.2
curl 8.5.0
gh 2.86.0
node 20.20.0
python3 3.12.3
go 1.24.13
java 21.0.10
dotnet 10.0.102

Result: 12/12 tools available ✅

Overall Status: PASS

🔧 Tool validation by Agent Container Smoke Test for issue #16628

@github-actions
Copy link
Contributor

Smoke Temporary ID completed successfully. Temporary ID validation passed.

@github-actions
Copy link
Contributor

Smoke Project completed successfully. All project operations validated.

@github-actions
Copy link
Contributor

Smoke test results
PR titles: Update test expectations for roles-to-on-roles codemod; Fix missing global.context setup in submit_pr_review.test.cjs
GitHub MCP ✅
Serena MCP ✅
Playwright ✅
File write ✅
Bash cat ✅
Build ✅
Overall: PASS

🔮 The oracle has spoken through Smoke Codex for issue #16628

@github-actions
Copy link
Contributor

Smoke Test: Copilot - 22157553390 ⚠️ PARTIAL PASS (10/11)

Test Status
GitHub MCP
Safe Inputs GH CLI
Serena MCP
Playwright
File Writing + Bash
Discussion Interaction
Build gh-aw
Discussion Creation
Workflow Dispatch
PR Review

Failure: Serena MCP — uvx not installed.

@pelikhan — PR reviewed, smoke-copilot label added.

📰 BREAKING: Report filed by Smoke Copilot for issue #16628

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds blocked assignee support to assign_to_user.cjs. The implementation is clean and the test coverage is solid. Two minor suggestions added as inline comments. Overall looks good!

📰 BREAKING: Report filed by Smoke Copilot for issue #16628

async function main(config = {}) {
// Extract configuration
const allowedAssignees = config.allowed || [];
const blockedAssignees = config.blocked || [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition of blockedAssignees support. Consider adding a comment here explaining that blocked takes precedence over allowed to clarify the filtering priority for future readers.

describe("blocked patterns", () => {
it("should filter out blocked users by exact match", async () => {
const { main } = require("./assign_to_user.cjs");
const handler = await main({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good test coverage for blocked patterns. It would also be worth adding a test case that verifies an empty blocked array (the default) doesn't filter any valid assignees.

@github-actions
Copy link
Contributor

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions
Copy link
Contributor

Smoke Test Results — Run §22157554498

Core Tests #1-10: ✅✅✅✅✅✅✅✅✅✅ All pass
PR Review Tests #11-17: ✅✅✅⚠️⚠️⚠️ (10 pass, 3 skipped)

Overall: PARTIAL (all non-skipped tests passed)

💥 [THE END] — Illustrated by Smoke Claude for issue #16628

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💥 Automated smoke test review - all systems nominal!

💥 [THE END] — Illustrated by Smoke Claude for issue #16628

@pelikhan pelikhan merged commit bdbe553 into main Feb 18, 2026
@pelikhan pelikhan deleted the copilot/add-blocked-deny-list-feature branch February 18, 2026 21:35
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.

Feature request: blocked deny list for assign-to-user safe output

2 participants

Comments