Skip to content

fix(#2903): show bootstrap scan finding details#2925

Closed
sjsjsjjs534 wants to merge 1 commit into
fullsend-ai:mainfrom
sjsjsjjs534:me/security-scan-finding-details-2903
Closed

fix(#2903): show bootstrap scan finding details#2925
sjsjsjjs534 wants to merge 1 commit into
fullsend-ai:mainfrom
sjsjsjjs534:me/security-scan-finding-details-2903

Conversation

@sjsjsjjs534

Copy link
Copy Markdown

Summary

  • Print individual security finding details after bootstrap scan warnings for agents, skills, and plugins.
  • Add stderr regression coverage for fail-open bootstrap scans.

Fixes #2903

Tests

  • go test ./internal/cli -run TestScanRuntimeContent -count=1
  • env TMPDIR=/private/var/folders/t6/2b3hch457vld0w_q_m84tp_w0000gn/T/ go test ./internal/cli -count=1
  • go vet ./...
  • pre-commit run

Signed-off-by: zhangsixiao <zhangsixiao@bytedance.com>
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

1 similar comment
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Show bootstrap scan finding details in fail-open warnings

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Print per-finding details to stderr for agent/skill/plugin bootstrap scan warnings.
• Preserve fail-open behavior while making warnings actionable.
• Add regression tests validating stderr output for finding detail lines.
Diagram

graph TD
  A(["CLI bootstrap scan"]) --> B["scanRuntimeContent"] --> C["scanAgentFile"]
  B --> D["scanSkillDir"]
  B --> E["scanPluginDir"]
  C --> F["security.Pipeline scan"] --> G["stderr warnings + finding details"]
  D --> F
  E --> F
Loading
High-Level Assessment

The chosen approach (a shared helper that prints findings whenever warnings are emitted) is the most direct way to make fail-open scans actionable while keeping behavior consistent across agent/skill/plugin scans. Alternatives like introducing a structured logger or returning rich warning objects would add complexity without clear benefit for this CLI-focused output.

Files changed (2) +103 / -0

Bug fix (1) +12 / -0
bootstrap_scan.goPrint per-finding details for bootstrap scan warnings +12/-0

Print per-finding details for bootstrap scan warnings

• Adds a helper to print scan finding severity/name/detail to stderr. Calls the helper from agent, skill, and plugin scan warning paths (including fail-open critical warnings) so users can see which findings triggered the warning.

internal/cli/bootstrap_scan.go

Tests (1) +91 / -0
bootstrap_scan_test.goAdd stderr regression tests for finding detail output +91/-0

Add stderr regression tests for finding detail output

• Introduces tests that capture stderr and assert that warning output includes finding details for agent, skill, and plugin fail-open scans. Adds a small stderr capture helper to make these assertions reliable.

internal/cli/bootstrap_scan_test.go

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 54 rules

Grey Divider


Remediation recommended

1. Global stderr capture race 🐞 Bug ☼ Reliability
Description
captureStderr replaces the process-global os.Stderr without synchronization, which can interleave
with other tests (including t.Parallel tests in this package) and produce flaky captures or data
races. It also doesn’t guarantee the pipe fds are closed if the callback exits early (e.g.,
FailNow/panic), leaking descriptors and leaving stderr redirected.
Code

internal/cli/bootstrap_scan_test.go[R153-172]

+func captureStderr(t *testing.T, fn func()) string {
+	t.Helper()
+
+	oldStderr := os.Stderr
+	r, w, err := os.Pipe()
+	require.NoError(t, err)
+	os.Stderr = w
+	defer func() {
+		os.Stderr = oldStderr
+	}()
+
+	fn()
+
+	require.NoError(t, w.Close())
+	var buf bytes.Buffer
+	_, err = io.Copy(&buf, r)
+	require.NoError(t, err)
+	require.NoError(t, r.Close())
+	return buf.String()
+}
Relevance

⭐⭐ Medium

Team accepts fixes for process-global mutation/concurrency risks, but no direct prior
os.Stderr-capture precedent found (e.g. PRs #279, #2015).

PR-#279
PR-#2015

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The helper swaps a global (os.Stderr) and only restores it via defer, with pipe closure occurring
after fn(); if fn() exits early, those closes won’t run. The package also contains
t.Parallel() tests, meaning concurrent execution is possible and global stderr swapping can
interfere.

internal/cli/bootstrap_scan_test.go[153-172]
internal/cli/mint_test.go[980-1013]
internal/cli/mint_test.go[29-31]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`captureStderr` mutates global `os.Stderr` and relies on non-deferred cleanup after `fn()` returns. This can flake when other tests run concurrently (package contains `t.Parallel()` tests) and can leak/leave redirected stderr if `fn()` exits early.

### Issue Context
This is test-only but can destabilize CI. The repo already has other tests that swap `os.Stderr`, so a shared, hardened helper is preferable.

### Fix Focus Areas
- internal/cli/bootstrap_scan_test.go[153-172]

### Implementation notes
- Add a package-level `var stderrMu sync.Mutex` and lock around the entire capture to serialize global `os.Stderr` swapping.
- Use `defer` to restore `os.Stderr` and close both `w` and `r` even if `fn()` aborts early.
- Restore `os.Stderr` immediately after closing `w` (before reading from `r`) to minimize the window where stderr points at a closed pipe.
- Optionally refactor other tests that swap `os.Stderr` to use the same helper to avoid future reintroductions.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. Misleading injection warning label 🐞 Bug ◔ Observability
Description
Bootstrap scan warnings/counts are phrased as “injection finding(s)”, but security.InputPipeline()
also includes UnicodeNormalizer which emits non-injection findings (e.g., ansi_escape,
null_byte). With printScanFindings(result.Findings) now printing all findings, users can see
non-injection findings under an “injection” warning and the counts become misleading.
Code

internal/cli/bootstrap_scan.go[R60-65]

		fmt.Fprintf(os.Stderr, "WARNING: agent definition %q has critical injection findings (fail_mode: open)\n", agentPath)
+		printScanFindings(result.Findings)
	} else if len(result.Findings) > 0 {
		fmt.Fprintf(os.Stderr, "WARNING: agent definition %q has %d injection finding(s)\n", agentPath, len(result.Findings))
+		printScanFindings(result.Findings)
	}
Relevance

⭐⭐⭐ High

Similar “misleading count/label due to UnicodeNormalizer findings” wording fixes were accepted (PRs
#2444, #1178).

PR-#2444
PR-#1178

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
bootstrap_scan prints “injection finding(s)” based on len(result.Findings) and now prints every
finding via printScanFindings. The pipeline includes UnicodeNormalizer, which adds findings that
are not injection-pattern detections.

internal/cli/bootstrap_scan.go[55-65]
internal/security/scanner.go[82-91]
internal/security/unicode.go[64-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Bootstrap scan warnings say “injection finding(s)” but the pipeline returns findings from both the unicode normalizer and the injection scanner. After this PR, `printScanFindings` prints those mixed findings, making the warning label/count inaccurate.

### Issue Context
`InputPipeline()` runs `NewUnicodeNormalizer()` then `NewContextInjectionScanner()`. Unicode normalizer findings are security-relevant, but they aren’t “injection” findings.

### Fix Focus Areas
- internal/cli/bootstrap_scan.go[55-65]
- internal/cli/bootstrap_scan.go[83-93]
- internal/cli/bootstrap_scan.go[103-113]

### Implementation options
- Easiest: change wording everywhere from “injection finding(s)” to “security finding(s)”.
- Or: filter/count only `f.Scanner == "context_injection"` for “injection” wording, and optionally print grouped sections (e.g., “Unicode findings” vs “Injection findings”).
- Consider including `f.Scanner` in `printScanFindings` output to reduce ambiguity.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +153 to +172
func captureStderr(t *testing.T, fn func()) string {
t.Helper()

oldStderr := os.Stderr
r, w, err := os.Pipe()
require.NoError(t, err)
os.Stderr = w
defer func() {
os.Stderr = oldStderr
}()

fn()

require.NoError(t, w.Close())
var buf bytes.Buffer
_, err = io.Copy(&buf, r)
require.NoError(t, err)
require.NoError(t, r.Close())
return buf.String()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Global stderr capture race 🐞 Bug ☼ Reliability

captureStderr replaces the process-global os.Stderr without synchronization, which can interleave
with other tests (including t.Parallel tests in this package) and produce flaky captures or data
races. It also doesn’t guarantee the pipe fds are closed if the callback exits early (e.g.,
FailNow/panic), leaking descriptors and leaving stderr redirected.
Agent Prompt
### Issue description
`captureStderr` mutates global `os.Stderr` and relies on non-deferred cleanup after `fn()` returns. This can flake when other tests run concurrently (package contains `t.Parallel()` tests) and can leak/leave redirected stderr if `fn()` exits early.

### Issue Context
This is test-only but can destabilize CI. The repo already has other tests that swap `os.Stderr`, so a shared, hardened helper is preferable.

### Fix Focus Areas
- internal/cli/bootstrap_scan_test.go[153-172]

### Implementation notes
- Add a package-level `var stderrMu sync.Mutex` and lock around the entire capture to serialize global `os.Stderr` swapping.
- Use `defer` to restore `os.Stderr` and close both `w` and `r` even if `fn()` aborts early.
- Restore `os.Stderr` immediately after closing `w` (before reading from `r`) to minimize the window where stderr points at a closed pipe.
- Optionally refactor other tests that swap `os.Stderr` to use the same helper to avoid future reintroductions.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 60 to 65
fmt.Fprintf(os.Stderr, "WARNING: agent definition %q has critical injection findings (fail_mode: open)\n", agentPath)
printScanFindings(result.Findings)
} else if len(result.Findings) > 0 {
fmt.Fprintf(os.Stderr, "WARNING: agent definition %q has %d injection finding(s)\n", agentPath, len(result.Findings))
printScanFindings(result.Findings)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Informational

2. Misleading injection warning label 🐞 Bug ◔ Observability

Bootstrap scan warnings/counts are phrased as “injection finding(s)”, but security.InputPipeline()
also includes UnicodeNormalizer which emits non-injection findings (e.g., ansi_escape,
null_byte). With printScanFindings(result.Findings) now printing all findings, users can see
non-injection findings under an “injection” warning and the counts become misleading.
Agent Prompt
### Issue description
Bootstrap scan warnings say “injection finding(s)” but the pipeline returns findings from both the unicode normalizer and the injection scanner. After this PR, `printScanFindings` prints those mixed findings, making the warning label/count inaccurate.

### Issue Context
`InputPipeline()` runs `NewUnicodeNormalizer()` then `NewContextInjectionScanner()`. Unicode normalizer findings are security-relevant, but they aren’t “injection” findings.

### Fix Focus Areas
- internal/cli/bootstrap_scan.go[55-65]
- internal/cli/bootstrap_scan.go[83-93]
- internal/cli/bootstrap_scan.go[103-113]

### Implementation options
- Easiest: change wording everywhere from “injection finding(s)” to “security finding(s)”.
- Or: filter/count only `f.Scanner == "context_injection"` for “injection” wording, and optionally print grouped sections (e.g., “Unicode findings” vs “Injection findings”).
- Consider including `f.Scanner` in `printScanFindings` output to reduce ambiguity.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@rh-hemartin rh-hemartin closed this Jul 3, 2026
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jul 3, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 7:20 AM UTC · Completed 7:24 AM UTC
Commit: af599da · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

PR #2925 was an external contributor PR that received only third-party bot review (qodo-code-review), no fullsend agent participation, no human review feedback, and was closed without merge. The retro dispatch was wasteful — there is no fullsend agent workflow to analyze. Existing issue #2942 already proposes the correct fix (skip retro when no fullsend agents participated). No new proposals are warranted; the single actionable improvement is already tracked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security scanner warnings don't show finding details

2 participants