Skip to content

fix(output): disclose compact-mode finding and command-group truncation - #1231

Merged
sonukapoor merged 3 commits into
OWASP:mainfrom
prx-my:feature/issue-1151-compact-truncation-disclosure
Sep 26, 2026
Merged

sonukapoor merged 3 commits into
OWASP:mainfrom
prx-my:feature/issue-1151-compact-truncation-disclosure

Conversation

@prx-my

@prx-my prx-my commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

What changed and why

Compact mode caps finding blocks and suggested-fix command groups at three and previously announced neither cut. A run could print a footer reporting dozens of urgent issues while showing three blocks, and a six-section plan looked complete after three.

Both cuts now print a derived disclosure, and nothing is withheld silently. The caps themselves are unchanged and remain at three; selection, ordering, and severity semantics are untouched. Whether three is still the right cap is a separate design decision.

After the last shown finding block, when findings were withheld:

Showing 3 of 54 findings. Run --verbose --all to see them all.

After the last shown command-group section, when plan.sections.length > 3:

3 more command groups (medium, low). Run --verbose to see them.

Counts and severities are derived from what was actually hidden - the shown count is the number of printed blocks, the total is the finding count, and the hidden severities are the unique severities of the omitted sections in first-seen order. Both notices only appear when truncation occurs.

Tests

  • tests/output/compact-truncation.test.ts covers the formatters and the compact printer: findings above/below the cap, displayed/total count derivation, command groups above/below the cap, hidden count/severity derivation (including duplicate and unknown severities), and no disclosure when nothing is truncated.

Verification

Ran the CONTRIBUTING sequence:

npm ci
npm run lint:tests
npm run build
node dist/index.js advisories sync
npm test
  • lint:tests passed
  • build passed
  • advisories sync: 228631 records
  • npm test: 152 suites, 2051 tests passed

Closes #1151

Compact mode caps finding blocks and suggested-fix command groups at three
and previously announced neither cut. Print a derived disclosure after the
last shown finding block when findings were withheld, and after the last
shown section when fix-plan sections were omitted.

Counts and severities are derived from what was actually hidden, and the
disclosure only appears when truncation occurs. Selection and ordering are
unchanged.

Closes OWASP#1151
@prx-my
prx-my requested a review from sonukapoor as a code owner September 23, 2026 22:59
Copilot AI lite review requested due to automatic review settings September 23, 2026 22:59

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@sonukapoor sonukapoor left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good work, and the discipline is the part I want to note first: #1151 said the cap value itself was a separate decision and you left it alone and said so in the body. That is the right instinct.

I checked the counts rather than trusting them. Showing 3 of 53 on juice-shop against 53 rows from --all, 68 on nest, 109 on analog, all exact. The command-group arithmetic is right too: juice-shop has 7 groups and shows 3, and "4 more command groups (medium, low)" names exactly the hidden severities. I also confirmed the remedies you point people at are real, since --verbose --all passes a null threshold and genuinely is unfiltered.

I also checked your tests discriminate instead of just passing. Breaking the emission, the slice derivation, the severity dedupe and the off-by-one guard each failed the test that should catch it and nothing else. That is real coverage.

One thing to fix before this lands.

The findings notice is not gated on --all, so it contradicts itself. cve-lite examples/juice-shop --all prints:

Showing 3 of 53 findings. Run --verbose --all to see them all.

and then prints all 53 rows about twenty lines below it, from the findings table. I reproduced this: notice present once, table rows 53. The user already has everything and is being told to go and fetch it.

The file already solves this exact problem for the neighbouring hint:

if (!options?.all) {
  console.log(chalk.gray(`Run with ${chalk.whiteBright("--verbose")} for fix plan, paths, and full table.`));
}

The new notice wants the same guard, plus a test for the --all combination, which is the gap that let it through. It matters more here than it normally would, because the entire point of this PR is that compact output should stop saying things that are not true about what it showed.

The command-group notice does not have this problem and should stay as it is: --all reveals the table, not the command groups, so "Run --verbose to see them" is still accurate there.

While you are in there, please drop this:

it("keeps the finding block cap at the configured limit", () => {
  expect(COMPACT_FINDING_BLOCK_LIMIT).toBe(3);
});

It asserts a constant equals its own literal, so it cannot catch a regression, and it will fail the day anyone revisits the cap question the issue deliberately left open.

Three smaller things, none blocking, mentioned so they are on the record rather than because I want another round over them. The cap is now declared twice, as COMPACT_FINDING_BLOCK_LIMIT and as the ?? 3 default in finding-display.ts, and those can drift; src/constants.ts already holds this kind of value. The doc comment calls it a finding-block cap but the selector appends unknown-severity direct findings on top of the slice, so the block count can exceed three even though your disclosure correctly reports what was printed. And the notice says "findings" while the summary below says "packages" for the same 53 things, which is inherited from the issue text rather than something you invented.

Nice catch on the empty-section case, incidentally. On a project with findings but none critical or high, main prints a bare heading with nothing under it, and yours says Showing 0 of 3. That was not asked for and it is the worst silent case in the whole thing.

@prx-my
prx-my requested a review from sonukapoor September 25, 2026 12:33

@sonukapoor sonukapoor left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Both items done, seven minutes after the review, and I checked the behaviour rather than the commit title.

The guard is in, and I verified all three things it needs to be true at once on examples/juice-shop: the default compact run still says Showing 3 of 53 findings, --all no longer says it, and --all still prints all 53 rows. The command-group notice correctly stays under --all, which is the right call since --all reveals the table and not the groups.

Your new test is better than what I asked for. I would have settled for asserting the notice is absent; you also assert the table and a row are present, so it pins that the data is actually there rather than just that the message went away. Removing the guard fails exactly that test and nothing else.

Tautological cap test dropped, thank you. 2079 tests green, build clean.

@sonukapoor
sonukapoor merged commit 971d198 into OWASP:main Sep 26, 2026
6 checks passed
@sonukapoor

Copy link
Copy Markdown
Collaborator

Merged, thank you @prx-my! Fast turnaround, and the test you wrote for the --all case is the better version of what I asked for.

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.

fix(output): compact mode truncates findings and fix groups without saying so

3 participants