Repository navigation
/cso import-sarif: results with a uriBaseId are dropped as partial — semgrep and trivy SARIF never reach the audit #3011
Description
Summary
gstack-cso import-sarif drops every SARIF result whose artifactLocation
carries a uriBaseId, unless the run declares that base in
originalUriBaseIds and the base is exactly file://<sourceRoot>/. The
import CLI always normalizes against the fixed root /source
(lib/cso/cli.ts:348, importSarif(..., {sourceRoot: '/source'})), so a base
that points at the real checkout can never match.
semgrep and trivy both emit uriBaseId by default, so all of their results
are dropped: coverage scanner:sarif becomes partial with the gap
A SARIF result could not be safely normalized., and the result yields 0
candidates. A real finding from either scanner is dropped exactly like a
false positive, and never reaches the audit.
Version: gstack 1.91.9.0 (96764e80), semgrep 1.177.0, trivy 0.74.0, Linux,
no Docker (scanners run natively, SARIF imported with import-sarif).
Where it happens
lib/cso/scanners.ts, in the result loop (lines ~360-378 in 1.91.9.0):
if (artifact.uriBaseId !== undefined) {
const baseId = str(artifact.uriBaseId);
const bases = obj(run.originalUriBaseIds); // throws 'Expected object' if absent
const base = str(obj(bases[baseId]).uri);
if (base !== `file://${root}/` && base !== `file://${root}`) throw new Error('Unsafe location');
}
...
} catch (error) { gap(... ? 'UNSAFE_LOCATION' : 'INVALID_OUTPUT', 'A SARIF result could not be safely normalized.'); }- semgrep: results carry
"uriBaseId": "%SRCROOT%"and the run has no
originalUriBaseIds.obj(undefined)throwsExpected object→
INVALID_OUTPUT. - trivy: results carry
"uriBaseId": "ROOTPATH", and the run declares
originalUriBaseIds.ROOTPATH.uri = "file:///path/to/checkout/", which is not
file:///source/→Unsafe location→UNSAFE_LOCATION.
The uri itself is relative and inside the repo in both cases
(lib/x.test.mjs, Dockerfile).
Reproduction
semgrep --config=p/secrets --metrics=off --sarif -o semgrep.sarif . # any repo with one finding
trivy fs --scanners misconfig --format sarif -o trivy.sarif . # a Dockerfile without HEALTHCHECK
gstack-cso-launcher start --repo . --budget 120
gstack-cso-launcher import-sarif <run> semgrep.sarif
gstack-cso-launcher import-sarif <run> trivy.sarif
gstack-cso-launcher inspect <run> # scanner:sarif partial ×2, 0 candidatesCalling importSarif directly on the same files:
| Input | Status | Candidates | Gap |
|---|---|---|---|
| semgrep.sarif as emitted | partial |
0 | INVALID_OUTPUT |
| trivy.sarif as emitted | partial |
0 | UNSAFE_LOCATION |
same files, uriBaseId removed (relative uri kept) |
complete |
2 / 1 | none |
Expected
A relative uri that stays inside the source root should normalize whether or
not a uriBaseId is present. Suggestions, in order of preference:
- When the
uriis relative and safe, ignoreuriBaseIdif its base is
undeclared, and resolve theuriagainst the source root, as other SARIF
consumers do for%SRCROOT%. - Accept a declared base that equals the real checkout path the run was
started on, not only the fixed/source. - At minimum, report a distinct gap (e.g.
UNRESOLVED_URI_BASE) so users can
tell "unsafe path" from "base not understood".
Workaround
Strip uriBaseId from results whose uri is relative before importing
(and keep refusing absolute or .. paths). With that, both files import as
complete.
Activity
v1.91.13.0 fix: severe bug wave (autoplan guard, land-and-deploy CI g…
capy-ai commentedon Oct 2, 2026
Fixed in v1.91.13.0 (#3013, merged as f30b7b7): import-sarif resolves semgrep's %SRCROOT% and trivy's ROOTPATH through explicit mappings captured from real scanner output; rejected results are counted with rule, base and path. Run
/gstack-upgrade, then start a new Claude Code session. Thanks for the report. Reopen if you still see it after upgrading.