Skip to content

fix: pass mentions config to add_comment handler so allowed mentions aren't escaped#32805

Merged
pelikhan merged 4 commits into
mainfrom
copilot/fix-escaping-allowed-mentions
May 17, 2026
Merged

fix: pass mentions config to add_comment handler so allowed mentions aren't escaped#32805
pelikhan merged 4 commits into
mainfrom
copilot/fix-escaping-allowed-mentions

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 17, 2026

mentions.allowed entries (e.g. @copilot in pr-sous-chef) were being escaped in add_comment output because the Go compiler never included the global mentions key in GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG. The handler manager already had forwarding logic for this — it was just a dead path.

Changes

  • compiler_safe_outputs_config.goaddHandlerManagerConfigEnvVar now emits "mentions" at the top level of GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG, activating the existing forwarding in safe_output_handler_manager.cjs:

    if (type === "add_comment" && handlerConfig.mentions == null && config.mentions != null) {
      handlerConfig.mentions = config.mentions; // was always skipped; now works
    }

    Config map type widened from map[string]map[string]anymap[string]any to accommodate non-handler top-level keys.

  • add_comment_target_repo_test.goTestAddCommentMentionsInHandlerConfig verifies the mentions config is present in the handler config JSON and correctly structured.

  • pr-sous-chef.lock.yml — Regenerated; GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG now contains "mentions":{"allowed":["copilot"]}.

Copilot AI and others added 2 commits May 17, 2026 12:40
…add_comment respects allowed mentions

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…g map

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title fix: include mentions config in GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG so add_comment respects allowed mentions fix: pass mentions config to add_comment handler so allowed mentions aren't escaped May 17, 2026
Copilot AI requested a review from pelikhan May 17, 2026 12:45
@pelikhan pelikhan marked this pull request as ready for review May 17, 2026 12:48
Copilot AI review requested due to automatic review settings May 17, 2026 12:48
Copy link
Copy Markdown
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

Fixes safe-output handler configuration so global mention allowlists can be forwarded to the add_comment handler.

Changes:

  • Adds top-level mentions to GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG.
  • Adds Go test coverage for mention propagation into handler config.
  • Updates the pr-sous-chef compiled workflow lock.
Show a summary per file
File Description
pkg/workflow/compiler_safe_outputs_config.go Emits global mentions config for handler manager consumption.
pkg/workflow/add_comment_target_repo_test.go Verifies mentions are present or omitted in handler config as expected.
.github/workflows/pr-sous-chef.lock.yml Regenerated handler config includes the mentions allowlist.

Copilot's findings

Tip

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

  • Files reviewed: 3/3 changed files
  • Comments generated: 3

GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":20,\"target\":\"*\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"default_operation\":\"append\",\"max\":10,\"target\":\"*\",\"update_branch\":true}}"
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":20,\"target\":\"*\"},\"create_report_incomplete_issue\":{},\"mentions\":{\"allowed\":[\"copilot\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"default_operation\":\"append\",\"max\":10,\"target\":\"*\",\"update_branch\":true}}"
Comment on lines +124 to +140
func buildMentionsHandlerConfig(m *MentionsConfig) map[string]any {
cfg := make(map[string]any)
if m.Enabled != nil {
cfg["enabled"] = *m.Enabled
}
if m.AllowTeamMembers != nil {
cfg["allowTeamMembers"] = *m.AllowTeamMembers
}
if m.AllowContext != nil {
cfg["allowContext"] = *m.AllowContext
}
if len(m.Allowed) > 0 {
cfg["allowed"] = m.Allowed
}
if m.Max != nil {
cfg["max"] = *m.Max
}
Comment on lines +95 to +100
// Include top-level mentions configuration so the handler manager can pass it to
// the add_comment handler (which calls sanitizeContent with the allowed aliases).
if safeOutputs.Mentions != nil {
mentionsCfg := buildMentionsHandlerConfig(safeOutputs.Mentions)
if len(mentionsCfg) > 0 {
config["mentions"] = mentionsCfg
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments, avoid duplicate code

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 80/100

Excellent test quality

Metric Value
New/modified tests analyzed 1 (table-driven, 3 sub-cases)
✅ Design tests (behavioral contracts) 1 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 1 (100%)
Duplicate test clusters 0
Test inflation detected ⚠️ Yes (99 test lines / 38 production lines = 2.6:1)
🚨 Coding-guideline violations None

Test Classification Details

Test File Classification Issues Detected
TestAddCommentMentionsInHandlerConfig pkg/workflow/add_comment_target_repo_test.go:264 ✅ Design None — 3 table rows covering positive and negative paths

Test Analysis

TestAddCommentMentionsInHandlerConfig is a table-driven test with 3 rows:

  1. mentions.allowed propagates to handler config — verifies that mentions.allowed: ["copilot"] appears in the compiled GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG JSON. This directly tests the behavioral fix: the bug was that mentions config was not being passed to the handler, causing usernames to be escaped.
  2. mentions.enabled=false propagates to handler config — verifies that disabling mentions also flows through correctly.
  3. no mentions config omits mentions from handler config — a negative/edge-case row verifying that the mentions key is absent when no mentions config is set, preventing false positives.

All three rows test observable output (the compiled step JSON) rather than internal implementation details — a strong behavioral contract test.

Build tag: ✅ //go:build !integration present on line 1.
Mock usage: None — real compiler instance used (NewCompiler()).


Test Inflation Note

The test file gained 99 lines vs. 38 lines added to the production file (compiler_safe_outputs_config.go), a 2.6:1 ratio exceeding the 2:1 threshold. This is explainable: the test includes thorough setup, JSON round-trip parsing via extractHandlerConfig, and 3 well-structured table rows to fully cover the behavioral contract of a focused fix. The inflation is justified by test quality.


Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 1 test function (3 table-driven sub-cases) — unit (//go:build !integration)
  • 🟨 JavaScript: No test files changed

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). The new test directly enforces the behavioral contract fixed by this PR: that mentions configuration is included in the handler config so allowed mentions are not escaped.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct

Goal: Shift toward tests that describe the system's behavioral contract.

References: §25991308933

🧪 Test quality analysis by Test Quality Sentinel · ● 8.2M ·

Copy link
Copy Markdown
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.

✅ Test Quality Sentinel: 80/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). The new table-driven test TestAddCommentMentionsInHandlerConfig directly enforces the behavioral contract fixed by this PR.

…puts handler config

Generated by the Design Decision Gate workflow. Documents the decision
to allow non-handler top-level keys (e.g. `mentions`) in
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG, widening the Go config map type
to `map[string]any` and activating existing runtime forwarding logic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: bcb3bc6

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 5.1M

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic in pkg/workflow/ (137 new lines in business directories, threshold = 100) but does not have a linked Architecture Decision Record (ADR).

AI has analyzed the PR diff and generated a draft ADR to help you get started:

📄 Draft ADR: docs/adr/32805-non-handler-top-level-keys-in-safe-outputs-handler-config.md

The draft captures the structural decision implied by this PR: widening the Go config map from map[string]map[string]anymap[string]any so that GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG can hold both per-handler entries and non-handler top-level keys (here, mentions) that the runtime forwards into specific handlers.

What to do next

  1. Review the draft ADR committed to your branch — it was generated from the PR diff and PR description.
  2. Complete the missing sections — refine the alternatives if you actually considered others, and confirm the consequences match your intent.
  3. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-32805: Non-Handler Top-Level Keys in Safe-Outputs Handler Config

  4. If you believe this PR is a pure bug fix and the type widening is incidental rather than a design choice worth recording, leave a comment explaining that and the gate can be revisited.

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

Why this PR tripped the gate

The gate is volume-based when no implementation label is present: any PR exceeding 100 added lines in business-logic directories (default set includes pkg/) is treated as significant enough to warrant explicit decision capture. The 99-line test file inflated this PR over the threshold even though the production change is ~38 lines.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 32805-*.md for PR #32805).

🔒 This PR cannot merge until an ADR is linked in the PR body (or the gate is satisfied through reviewer override).

References:

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 5.1M ·

… regenerate locks

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 17, 2026

@copilot review all comments, avoid duplicate code

Done in 94610ff:

  1. No duplicate codegenerateSafeOutputsConfig now calls buildMentionsHandlerConfig instead of duplicating the conversion inline.
  2. Gated on add_commentmentions is only emitted in GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG when add_comment is enabled, preventing unnecessary churn in workflows that have mentions but no add_comment.
  3. All affected locks regeneratedpr-sous-chef and daily-experiment-report (the two workflows with both mentions and add-comment) were recompiled. The eight workflows with mentions but no add-comment are unchanged.

Copilot AI requested a review from pelikhan May 17, 2026 13:03
@pelikhan pelikhan merged commit 160fcc5 into main May 17, 2026
@pelikhan pelikhan deleted the copilot/fix-escaping-allowed-mentions branch May 17, 2026 13:05
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.

3 participants