Skip to content

fix: use distinct XML marker for threat detection engine errors vs real threats - #49527

Merged
pelikhan merged 6 commits into
mainfrom
copilot/deep-report-fix-threat-detection-engine
Aug 1, 2026
Merged

fix: use distinct XML marker for threat detection engine errors vs real threats#49527
pelikhan merged 6 commits into
mainfrom
copilot/deep-report-fix-threat-detection-engine

Conversation

Copilot AI commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Tooling failures (agent_failure, parse_error) emitted the same <!-- gh-aw-threat-detected --> XML marker as actual security findings, making them indistinguishable to automated scanners and causing alert fatigue across dozens of daily reports.

Changes

  • threat_detection_warning.cjs — added getThreatEngineErrorMarker() / getThreatEngineErrorMarkerTemplate() returning <!-- gh-aw-threat-engine-error -->. Modified getThreatDetectedMarker(reason) to delegate to the engine-error marker when isToolingFailureReason(reason) is true.

  • messages_run_status.cjs — the [!WARNING] engine-error banner template now embeds getThreatEngineErrorMarkerTemplate() instead of getThreatDetectedMarkerTemplate().

  • push_to_pull_request_branch.cjs — review PR bodies were unconditionally [!CAUTION] agentic threat detected; now gates on isToolingFailureReason() and uses [!WARNING] threat detection engine error with the correct marker for tooling failures.

  • Tests — updated generate_footer, messages, threat_detection_warning, and update_activation_comment tests to assert <!-- gh-aw-threat-engine-error --> for tooling failures and <!-- gh-aw-threat-detected --> exclusively for real threat verdicts.

Before / after marker mapping:

Reason Banner Marker (before) Marker (after)
threat_detected [!CAUTION] <!-- gh-aw-threat-detected --> <!-- gh-aw-threat-detected -->
agent_failure [!WARNING] <!-- gh-aw-threat-detected --> <!-- gh-aw-threat-engine-error -->
parse_error [!WARNING] <!-- gh-aw-threat-detected --> <!-- gh-aw-threat-engine-error -->

Caution

agentic threat detected
Threat detection flagged this output in warn mode. Manual review is REQUIRED before any follow-up automation.

Details

Potential security threats were detected in the agent output.

Review the workflow run logs for details.

run: https://github.com/github/gh-aw/actions/runs/30692749654

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 19.5 AIC · ⌖ 5.58 AIC · ⊞ 8.1K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 21 AIC · ⌖ 5.28 AIC · ⊞ 5.7K ·
Comment /souschef to run again

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

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix threat detection engine rendering generic banners fix: use distinct XML marker for threat detection engine errors vs real threats Aug 1, 2026
Copilot AI requested a review from pelikhan August 1, 2026 07:52
@pelikhan
pelikhan marked this pull request as ready for review August 1, 2026 07:56
Copilot AI review requested due to automatic review settings August 1, 2026 07:56
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

⚠️ PR Code Quality Reviewer failed during code quality review.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #49527 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Separates threat-engine failures from genuine security findings using a distinct XML marker and warning presentation.

Changes:

  • Adds <!-- gh-aw-threat-engine-error --> marker helpers.
  • Applies engine-error messaging to status output and review PR bodies.
  • Updates marker expectations across related tests.
Show a summary per file
File Description
actions/setup/js/threat_detection_warning.cjs Adds engine-error marker selection.
actions/setup/js/messages_run_status.cjs Uses the new marker in warning messages.
actions/setup/js/push_to_pull_request_branch.cjs Differentiates review PR messaging by reason.
actions/setup/js/threat_detection_warning.test.cjs Tests marker helpers.
actions/setup/js/messages.test.cjs Verifies engine-error message markers.
actions/setup/js/generate_footer.test.cjs Updates footer marker expectations.
actions/setup/js/update_activation_comment.test.cjs Updates the mocked warning output.

Review details

Tip

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

  • Files reviewed: 7/7 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment on lines +1309 to +1313
isEngineError ? "> [!WARNING]" : "> [!CAUTION]",
isEngineError ? "> threat detection engine error" : "> agentic threat detected",
isEngineError
? "> The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding."
: "> Threat detection flagged this output in warn mode. Manual review is REQUIRED before any follow-up automation.",
Comment on lines +87 to +89
const isEngineError = reason === "agent_failure" || reason === "parse_error";
if (isEngineError) {
return `> [!WARNING]\n> threat detection engine error\n> The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.\n> <!-- gh-aw-threat-engine-error -->\n>\n> ${reasonText}`;
const isEngineError = isToolingFailureReason(ctx.reason);
if (isEngineError) {
const defaultTemplate = `> [!WARNING]\n> threat detection engine error\n> The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.\n> ${getThreatDetectedMarkerTemplate()}\n>\n> <details>\n> <summary>Details</summary>\n>\n> {reason_text}\n>\n> Review the [workflow run logs]({run_url}) for details.\n> </details>`;
const defaultTemplate = `> [!WARNING]\n> threat detection engine error\n> The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.\n> ${getThreatEngineErrorMarkerTemplate()}\n>\n> <details>\n> <summary>Details</summary>\n>\n> {reason_text}\n>\n> Review the [workflow run logs]({run_url}) for details.\n> </details>`;

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The implementation correctly separates threat-engine-error markers from real-threat markers across all code paths. Tests cover the full matrix of inputs. No blocking issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 11.7 AIC · ⌖ 10 AIC · ⊞ 5.4K

@github-actions github-actions Bot mentioned this pull request Aug 1, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — the fix is correct and well-tested; two minor maintainability issues noted.

📋 Key Themes & Highlights

Key Themes

  • Duplicated condition in test helperupdate_activation_comment.test.cjs re-implements isToolingFailureReason() inline rather than importing it, which will silently drift if new tooling-failure reasons are added.
  • Dual-path PR body constructionpush_to_pull_request_branch.cjs branches on isEngineError for the banner lines and calls getThreatDetectedMarker(reason) (which branches internally), creating two independent paths that must stay in sync manually.

Positive Highlights

  • ✅ Clean, focused fix — root cause (shared marker constant) addressed at the source in threat_detection_warning.cjs
  • getThreatDetectedMarker(reason) now acts as a single routing point for the marker decision
  • ✅ Tests across four test files assert both the positive case (engine-error marker for tooling failures) and the negative case (.not.toContain for the real-threat marker) — good regression discipline
  • ✅ PR description includes a clear before/after mapping table

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 35.7 AIC · ⌖ 8.04 AIC · ⊞ 7.1K
Comment /matt to run again

parse_error: "The threat detection results could not be parsed.",
};
const reasonText = reasons[reason] || "The threat detection analysis could not be completed.";
const isEngineError = reason === "agent_failure" || reason === "parse_error";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The isEngineError check here duplicates the logic from isToolingFailureReason() instead of importing it — if tooling-failure reasons ever expand, this test helper will silently diverge from production logic.

💡 Suggested fix

Import isToolingFailureReason from threat_detection_warning.cjs and use it in the test fixture instead of the inline literal check:

// replace
const isEngineError = reason === 'agent_failure' || reason === 'parse_error';
// with (at the top of createTestableFunction or its mock)
const { isToolingFailureReason } = require('./threat_detection_warning.cjs');
const isEngineError = isToolingFailureReason(reason);

This keeps the test fixture in sync with production logic automatically.

@copilot please address this.

isEngineError
? "> The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding."
: "> Threat detection flagged this output in warn mode. Manual review is REQUIRED before any follow-up automation.",
`> ${getThreatDetectedMarker(detectionReasonEnv)}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/diagnosing-bugs] The new isEngineError branch selects the correct marker text but still calls getThreatDetectedMarker(detectionReasonEnv) on line 1314 — which already performs the same routing internally. The banner text and the marker are now computed independently, so a future change to one path won't automatically keep the other in sync.

💡 Suggested simplification

Since getThreatDetectedMarker(reason) already returns the right marker for both cases, there is no need to duplicate the isEngineError branching for the body lines above it. Consider extracting the PR body construction into a helper (e.g. in threat_detection_warning.cjs) so the banner, text, and marker are always derived from the same source of truth.

Alternatively, add a unit test for the PR body output in this file to lock in the expected marker for both agent_failure and threat_detected reasons.

@copilot please address this.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel Report test

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 58.1 AIC · ⌖ 7.99 AIC · ⊞ 8.4K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 83/100. 17% implementation tests (threshold: 30%). Tests verify distinct XML markers for threat detection engine errors vs real threats, with edge cases for null/undefined inputs. No violations.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot quick triage for this PR:

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 24.4 AIC · ⌖ 8.51 AIC · ⊞ 8.1K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

@copilot quick triage for this PR:

Addressed in dbb215a.

  • DRYed the warning/marker selection through a shared threat-warning presentation helper
  • removed the duplicated tooling-failure check from the activation-comment test helper
  • added review-PR body coverage for agent_failure and threat_detected
  • added activation-comment coverage for both markers
  • updated the safe-outputs spec for the separate engine-error contract

The failed PR Code Quality Reviewer run was a reviewer-agent exit on the previous head; CI for this new head is still stale and will need a maintainer re-trigger.

Copilot AI requested a review from gh-aw-bot August 1, 2026 08:34
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

Caution

agentic threat detected
Threat detection flagged this output in warn mode. Manual review is REQUIRED before any follow-up automation.

Details

Potential security threats were detected in the agent output.

Review the workflow run logs for details.

@copilot quick triage for this PR:

Generated by 👨🍳 PR Sous Chef
Comment /souschef to run again

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 19.5 AIC · ⌖ 5.58 AIC · ⊞ 8.1K ·
Comment /souschef to run again

Copilot AI commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

[!CAUTION]
agentic threat detected
Threat detection flagged this output in warn mode. Manual review is REQUIRED before any follow-up automation....

Checked the remaining skills-based review items on the current head: the DRY marker-selection concern is already addressed via getThreatWarningPresentation() in /home/runner/work/gh-aw/gh-aw/actions/setup/js/threat_detection_warning.cjs, and the activation-comment helper already reuses production warning logic in /home/runner/work/gh-aw/gh-aw/actions/setup/js/update_activation_comment.test.cjs.

Validation on f596c9a:

  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make test-impacted-js
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make fmt
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make lint
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make test-unit
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make test still hits an unrelated pre-existing wasm golden/version drift failure in pkg/workflow (TestWasmGolden_CompileFixtures / TestWasmGolden_AllEngines expecting GH_AW_INFO_VERSION 1.0.75 vs current 1.0.77).

The earlier PR Code Quality Reviewer failure was on the previous head and its job log did not show a code regression to repair here. Current CI on the latest head still needs a maintainer re-trigger before merge.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

PR Triage

Category: bug · Risk: medium · Priority: medium · Score: 68/100 (impact 30, urgency 22, quality 16)

Recommended action: fast_track

Fixes alert-fatigue bug: tooling failures used the same XML marker as real security threats. Ready for review (9 comments, 5 review comments), copilot CI check passed. High value for signal quality — fast-track.

Generated by 🔧 PR Triage Agent · auto · 49.2 AIC · ⌖ 8.64 AIC · ⊞ 8K ·

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

PR Triage

  • Category: bug
  • Risk: medium
  • Priority: medium
  • Score: 54/100 (Impact25/Urgency15/Quality14)
  • Recommended action: fast_track

Distinct XML marker prevents false-positive threat alerts across daily reports; 2 approvals.

Generated by 🔧 PR Triage Agent · auto · 73.4 AIC · ⌖ 10.1 AIC · ⊞ 8K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot quick triage for this PR:

Generated by 👨🍳 PR Sous Chef
Comment /souschef to run again

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 21 AIC · ⌖ 5.28 AIC · ⊞ 5.7K ·
Comment /souschef to run again

Copilot AI commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

@copilot quick triage for this PR:

  • Review feedback still worth closing out before merge:
    1. github-actions[bot] — add successful-review-path coverage for the new review-PR body branch (`agent_fa...

Checked the remaining github-actions review items on f596c9a: both are already covered on the current head.

  • /home/runner/work/gh-aw/gh-aw/actions/setup/js/push_to_pull_request_branch.test.cjs:1468 exercises the successful review-PR body path for both agent_failure and threat_detected, asserting the admonition and marker.
  • /home/runner/work/gh-aw/gh-aw/actions/setup/js/update_activation_comment.test.cjs:231 exercises emitted activation-comment bodies for both engine-error and real-threat markers.

Validation on the current head:

  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make test-impacted-js
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make fmt
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make lint
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make test-unit
  • BASE_REF=594778a52e97a6cfc6a7648d50bc79b0981cc7ae make test still reproduces the unrelated pre-existing wasm golden/version drift in /home/runner/work/gh-aw/gh-aw/pkg/workflow (TestWasmGolden_CompileFixtures / TestWasmGolden_AllEngines, GH_AW_INFO_VERSION 1.0.75 vs 1.0.77).

No further code changes were needed in this pass. Remaining maintainer action before merge: re-trigger CI on the current head after reviewing the existing unrelated make test failure.

@pelikhan
pelikhan merged commit be1047f into main Aug 1, 2026
12 checks passed
@pelikhan
pelikhan deleted the copilot/deep-report-fix-threat-detection-engine branch August 1, 2026 19:36
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.

[deep-report] Threat detection engine repeatedly fails to produce results, rendered as generic banners indistinguishable from a real hit

4 participants