feat(check): SARIF 2.1.0 output mode for clad check (closes #195)#201
Closed
yuyu04 wants to merge 1 commit into
Closed
feat(check): SARIF 2.1.0 output mode for clad check (closes #195)#201yuyu04 wants to merge 1 commit into
clad check (closes #195)#201yuyu04 wants to merge 1 commit into
Conversation
`clad check --format sarif` serializes the gate result as a SARIF 2.1.0 log so every drift finding surfaces inline on the PR diff, in the GitHub Security tab (github/codeql-action/upload-sarif), and in any SARIF viewer — instead of living only in the terminal/`--json` view. Mapping is 1:1 with the existing finding shape: detector → rule, severity (error/warn/info) → level (error/warning/note), path+line → physicalLocation. Each result carries a deterministic partialFingerprints value so re-runs de-duplicate alerts. A blocking stage that produced no findings (type/test failure) still surfaces as a result, so a RED gate never serializes to a falsely-clean SARIF. Output is deterministic (no clock/PRNG); default text and --json outputs are unchanged. Also fixes a latent truncation: clad check's machine-output modes now set process.exitCode and let stdout drain instead of calling process.exit(), which could terminate before a buffered stdout pipe (>64KB) flushed — SARIF is ~150KB and was truncated when piped (file redirects were already safe). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8322600 to
11ecb8f
Compare
Contributor
Author
yuyu04
added a commit
to yuyu04/cladding
that referenced
this pull request
Jul 2, 2026
…exit() `clad check`'s machine-output mode (--json) can write >64KB to stdout. Calling process.exit(worst) terminates Node before a buffered stdout PIPE flushes, so a consumer that pipes the output (`clad check --json | cat`, vs. redirecting to a file) gets a TRUNCATED document. Setting process.exitCode and letting the event loop drain guarantees the full payload is emitted, then Node exits with the worst stage code. This is the pipe-safety fix extracted from qwerfunch#201 (SARIF) on its own — it has value independent of SARIF: it fixes the existing --json path. The SARIF body stays in qwerfunch#201 for when GitHub code-scanning adoption is decided. - runCheckCommand: process.exit(...).worst → process.exitCode = ...worst - tests/cli/clad.test.ts: the six runCheckCommand tests now assert process.exitCode (process.exit is no longer called for that path); beforeEach resets process.exitCode, afterEach restores 0 so a recorded failure code can't leak into vitest's own exit status. Other commands (sync/status/init/ checkpoint/rollback) still use process.exit and keep their exitCalls asserts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
clad check --format sarif— a SARIF 2.1.0 output mode for the gate, so every drift finding surfaces inline on the PR diff, in the GitHub Security tab (github/codeql-action/upload-sarif), and in any SARIF viewer, instead of living only in the terminal/--jsonview. The mapping is a near 1:1 re-projection of the existingDriftFindingshape — no new analysis.Linked issue
Closes #195
PR contract (GOVERNANCE.md §4.3)
npm run typecheckcleannpm run lintcleannpm test— all tests pass (147 files / 1509 tests)npm run stage:drift— zero error-severity findings (strict pre-push gate GREEN)npm run conformance— fixtures matched (33/33 in the current suite)node bin/clad check— 15-stage gate greenspec/features/sarif-export-acedface.yaml(F-acedface) authored;spec.yaml/spec/index.yamlinventory synced; attestation stampedCHANGELOG.mdentry added under[Unreleased](Added+Fixed)Scope of change
--jsonoutput unchangedOut-of-scope checklist (must all be no)
What's in the box
src/stages/sarif.ts— pure, deterministic serializer.detector → rule,severity (error/warn/info) → level (error/warning/note),path+line → physicalLocation. Each result carries apartialFingerprintsvalue (sha256 over the finding's stable identity) so re-runs de-duplicate code-scanning alerts. A blocking stage with no findings (type/test failure) still emits a result keyed on the stage id — a failing gate is never represented as clean. No clock/PRNG → byte-identical output across runs.src/cli/clad.ts—--format <fmt>wiring (unknown value → clear error, non-zero exit). The tool version is threaded from commander'sprogram.version()rather than a new literal, to avoid adding a 10thversion-bump/HARNESS_INTEGRITYsite.Notes for the reviewer
clad check's machine-output modes previously calledprocess.exit(worst), which can terminate before a buffered stdout pipe (>64 KB) flushes — SARIF is ~150 KB and was being truncated when piped to another process (file redirects were already safe because those writes are synchronous). Changed to setprocess.exitCodeand let the event loop drain. This also touched 6 existingrunCheckCommandtests that spied onprocess.exit; they now assertprocess.exitCode(with a reset inbeforeEach/afterEachso a recorded code can't leak into vitest's own exit status).