Skip to content

fix: record findings held back by the reportable severity gate - #155

Open
mldangelo wants to merge 1 commit into
openai:mainfrom
mldangelo:fix/report-informational-note
Open

fix: record findings held back by the reportable severity gate#155
mldangelo wants to merge 1 commit into
openai:mainfrom
mldangelo:fix/report-informational-note

Conversation

@mldangelo

Copy link
Copy Markdown
Contributor

Fixes #48.

Summary

report.md filters findings to REPORTABLE_SEVERITIES, which excludes informational. A scan whose findings are all informational seals them into findings.json, exports them to SARIF as note and to CSV, and then renders a report stating:

No findings

No reportable findings survived the canonical discovery, validation, and reportability gates.

The three artifacts of a single scan contradict each other, and the one a human reads is the one missing data.

Which of the issue's two directions I took, and why

The issue offers both: state the exclusion, or add informational to REPORTABLE_SEVERITIES and give it a section.

I concluded the exclusion is deliberate and took the first. The evidence is that "reportable" is a load-bearing concept across the codebase, not a one-off in the projection: src/cli.ts defines the same four levels as REPORTABLE_SEVERITIES to gate --fail-on-severity (you cannot fail a build on informational) and then defines a separate DISPLAY_SEVERITIES that adds informational back for display. The report body follows the reportable set; that split is intentional and I did not want to silently reverse it.

So the report keeps its reportable-only body and instead records what was held back:

1 finding is outside the reportable severity set (informational: 1) and not detailed here. It remains recorded in findings.json and in the SARIF and CSV exports.

The line appears in both branches — under ### No findings, and beneath the findings table when reportable findings also exist, since the summary counts are computed from the filtered list and would otherwise under-report there too.

The count is derived from not in REPORTABLE_SEVERITIES rather than hardcoding informational, and the mix is rendered through the existing _severity_mix, so a future non-reportable level is described accurately instead of silently vanishing again.

references/final-report.md described the ordering as criticallow without ever saying informational is dropped — the documentation gap the issue calls out. It now states it.

Testing / QA instructions

Baseline before this branch: 470 pass / 6 skip / 0 fail. After: 475 pass / 6 skip / 0 fail (five added tests, new file tests-ts/report-projection.test.ts).

cd sdk/typescript          # run pnpm from here, not the repo root
CI=true pnpm install --frozen-lockfile
CI=true pnpm run types
CI=true pnpm run test
CI=true pnpm run format
CI=true pnpm run build

Confirm the tests reproduce the issue

Revert only the plugin files, keeping the tests:

cd sdk/typescript
cp _bundled_plugin/scripts/report_projection.py /tmp/rp.py
cp _bundled_plugin/references/final-report.md /tmp/fr.md
git checkout main -- _bundled_plugin/scripts/report_projection.py _bundled_plugin/references/final-report.md
CI=true bun test --timeout 30000 ./tests-ts/report-projection.test.ts   # expect 2 pass / 3 fail
cp /tmp/rp.py _bundled_plugin/scripts/report_projection.py
cp /tmp/fr.md _bundled_plugin/references/final-report.md
CI=true bun test --timeout 30000 ./tests-ts/report-projection.test.ts   # expect 5 pass / 0 fail

Reproduce by hand, as the issue does

cd sdk/typescript/_bundled_plugin && python3 -I -B -c '
import copy, json, sys; sys.path.insert(0, "scripts")
import report_projection as R
load = lambda n: json.load(open("examples/completed-scan/" + n, encoding="utf-8"))
m, c, f = load("scan-manifest.json"), load("coverage.json"), load("findings.json")
for level in ("high", "informational"):
    d = copy.deepcopy(f); d["findings"][0]["severity"]["level"] = level
    t = R.build_report_markdown(m, d, c)
    print(level, "| no-findings:", "### No findings" in t, "| records held back:",
          "outside the reportable severity set" in t)'

Use -B (as the workbench itself does via runWorkbench) — without it Python leaves __pycache__ inside _bundled_plugin/scripts/, which is not gitignored and makes pnpm run check:package fail with "npm tarball contains an unexpected file". The added tests spawn Python with -I -B for the same reason.

New coverage — tests-ts/report-projection.test.ts

The repo has no Python test suite, so these drive the real projection through spawnSync, guarded by test.skipIf on interpreter availability (matching the existing skipIf convention). They render the bundled examples/completed-scan bundle with severities forced, exactly as the issue reproduces it.

  1. records findings held back by the reportable severity gate — all informational: report still says ### No findings, and now also states 1 finding is outside the reportable severity set (informational: 1) and names findings.json.
  2. records held-back findings alongside reportable ones — 1 high + 2 informational: no ### No findings, the high finding renders, and 2 findings are outside…(informational: 2) appears.
  3. stays silent when every finding is reportable — high + low: the note must be absent, so clean reports are unchanged.
  4. keeps the rendered report valid for the format validator — pipes both renders through validate_report_format.py and asserts exit 0, since report.md is contract-validated and the new lines sit inside the ## Findings section.
  5. documents the exclusion in the final-report reference — pins the documentation fix.

Packaging check

Because this touches _bundled_plugin, verify the plugin payload is unchanged in shape:

cd sdk/typescript
CI=true pnpm pack --pack-destination /tmp/pkg
CI=true pnpm run check:package /tmp/pkg/openai-codex-security-0.1.4.tgz
# expect: 95 bundled plugin files, 179 entries

No files were added or removed from the plugin, so plugin-files.json needs no update (it carries paths, not hashes).

report.md filters findings to REPORTABLE_SEVERITIES, which excludes
informational. A scan whose findings are all informational therefore
sealed them into findings.json and exported them to SARIF and CSV while
the human-facing report stated that no findings survived the discovery,
validation and reportability gates. The three artifacts of one scan
contradicted each other, and the one a person reads was the one missing
data.

The exclusion itself is deliberate -- src/cli.ts draws the same line for
--fail-on-severity and keeps a separate DISPLAY_SEVERITIES that adds
informational -- so the report keeps its reportable-only body. It now
records how many findings were held back, with their severity mix, and
points at the artifacts that retain them.

references/final-report.md described the ordering as critical through
low without stating that informational is dropped, so it now says so.

Fixes openai#48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48ef1cd443

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"-B",
join(pluginRoot, "scripts", "validate_report_format.py"),
"--report-md",
"/dev/stdin",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace the POSIX-only stdin path in the Windows test

The test workflow runs the full TypeScript suite on windows-latest (.github/workflows/node-ci.yml, lines 23 and 70–76), where the hosted Python interpreter is discoverable but /dev/stdin does not exist. Consequently, validate_report_format.py fails while opening that path and this new test receives a nonzero status, breaking the Windows CI job. Write the rendered report to a temporary file and pass that native path to --report-md instead.

Useful? React with 👍 / 👎.

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.

informational findings are exported to SARIF and CSV but dropped from report.md, which then reports no findings

1 participant