Improvments#27
Merged
Merged
Conversation
Squashed from the improvments branch (15 commits, full history local): - AST-based Go security checks (insecure-tls, shell-execution) + Go masking - finding confidence levels + fixture-path secret demotion - detection precision corpus harness (tests/corpus, 24 rules, known-gap ledger) - intra-section file parallelism + caller ctx into git subprocesses - line-shift-resilient context fingerprints + SARIF partialFingerprints - fix templates for all 141 rules, deterministic/guided classification - new context.* agent-legibility family + repo_legibility artifact - OWASP A09 rules (log-secret-exposure, unsanitized-error-response) - rule_stats suppression telemetry + doctor rule-health - tree-sitter adoption spike: docs/treesitter-spike.md + isolated prototype Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r flag Ships the pure-Go tree-sitter runtime (gotreesitter pinned v0.20.8, MIT) as the first root dependency, behind parsers.treesitter: off|auto (default off, byte-for-byte legacy behavior). ParseScriptFile seam + corpus tree cache; four TS rules (explicit-any, non-null-assertion, double-assertion, unsafe-html-sink + JS mirror) gain query-based detection with per-file regex fallback (256KiB cap, ERROR-ratio guard). Differential corpora: regex 63.6% precision / 53.8% recall vs tree 100%/100%. Release builds use grammar-subset tags: binary 13.6MB -> 18.9MB. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ase tags Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <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.
Execute the checks-improvement plan: precision, engine, agent-readiness, and the tree-sitter TypeScript engine
272 files changed, +10,264 / −295 · tests 505 → 632 (46 packages) · golangci-lint 0 issues ·
-raceclean · self-scan exit 0Why
This PR executes a first-principles improvement plan for the check engine. The premise: a check's value is
(real bugs caught × cost avoided) − (false positives × attention burned), and the primary consumer of findings is shifting from humans to AI agents. That drove six workstreams: measure and fix precision, stabilize finding identity, make every finding machine-actionable, check codebase legibility itself, close OWASP gaps, and instrument rule health.1. Detection precision (Tier 1)
AST-based Go security checks.
security.insecure-tlsandsecurity.shell-executionwere literal substring matches on raw source —os/execin a comment fired,InsecureSkipVerify:true(no space) didn't. Both now walk the cachedgo/ast(import-alias aware, call-site precise); unparseable files fall back to a masked-line regex scan. A new Go source masker also hardens the remaining line-scan rules against comments/strings.Ground-truth precision corpus (
tests/corpus/). 96+ fixtures across 24 security rules — mutation variants (whitespace, renamed vars) and adversarial cleans (comments, docstrings, placeholders, import-only files) — scored per-rule againstexpectations.yaml. Known gaps are tracked assertions: the harness fails when a documented gap is unexpectedly fixed so it gets promoted, and fails on regression. The corpus mechanically confirmed the AST rework: precision 0.878 → 0.926, recall 0.956 → 0.969, withinsecure-tls/shell-executionat 1.000/1.000. Six remaining gaps are documented in the manifest as the next targets.Finding confidence. Every finding carries
confidence: high|medium|low(AST/manifest-backed = high; name-based and entropy heuristics = low), surfaced in JSON, SARIF property bags, and text. Secret findings in fixture paths (testdata/,*_test.*,*.spec.ts, …) demote fail→warn with low confidence behindchecks.security_rules.demote_fixture_findings(default on) — the top secret-rule FP source, still reported, never silent.2. Engine performance & stability (Tier 2)
ScanTargetFilesfans out to a bounded worker pool (min(4, NumCPU)) with deterministic output order and panic propagation; NL custom rules and the Python design graph stay sequential by design. ~3× faster on a 64-file section benchmark. Also fixes a latent warm-cache bug that left the Python import graph empty on cache-hit scans.sha256(rule|path|normalized ±2-line snippet)); baselines match on either the legacy or context fingerprint, so unrelated edits that shift line numbers no longer break suppression. Old baseline files keep working. SARIF results emitpartialFingerprints— what GitHub code scanning uses for cross-commit alert dedup.3. Agent-actionable output (Tier 3)
Every one of the 141 catalog rules now ships a
FixTemplate(119 backfilled), typed withkind: deterministic|guided(19 deterministic). Exposed throughexplain -format agent(newfix_template_kind) and the MCP explain tool. A catalog test enforces the invariant for all future rules.4. New
context.*family — agent-legibility checks (Tier 4)A new check section, "Agent Context", scoring how workable a repo is for AI agents:
context.agent-docs-missing— no CLAUDE.md / AGENTS.md / .cursorrules / copilot-instructionscontext.agent-docs-drift/context.readme-drift— docs referencing paths, make targets, or npm scripts that provably don't exist (conservative resolver; skips URLs, globs, placeholders; zero FPs on this repo's own README)context.oversized-context-unit— files over an agent-context budget (default 1500 lines; skips generated/vendored)context.ambiguous-symbol— duplicated basenames (utils.ts×9) that defeat grep navigationrepo_legibilityartifact — explainable 0–100 score with per-component breakdown, slop-score styleEnabled in full scans, skipped in diff scans by default (mirrors
contracts) so repo-level findings don't nag every PR. All warn-level; the section honestly flags this repo's own gaps without failing CI.5. OWASP A09 + coverage hygiene (Tier 5)
security.log-secret-exposure— secret-bearing identifiers/keys/concatenations inside logging call argument lists (Go/Python/TS/JS, masked-source, format-verb aware:"token count: %d"never fires)security.unsanitized-error-response— raw errors written into HTTP responses (http.Error(w, err.Error(), …),res.send(err),return str(e)in except blocks)codeguard owaspcoverage: 8/10 → 9/10 categories (A04 Insecure Design remains, inherently non-static)go-native; nowlanguage-agnostic6. Rule-health telemetry (Tier 6)
Scans record per-rule emitted vs baseline/waiver/inline-suppressed counts into a
rule_statsartifact plus a capped history file.doctornow flags dead waivers (matching no rule), expired waivers, and rules suppressed >50% of the time ("consider tuning or disabling") — a suppressed-to-death rule is a broken rule, and now it's visible.7. Tree-sitter TypeScript engine (spike → shipped behind a flag)
docs/treesitter-spike.mddocuments the full evaluation (options matrix incl. CGo/WASM routes, benchmarks, supply-chain assessment, phased plan). Outcome: conditional GO on a pure-Go runtime — every CGo option breaks theCGO_ENABLED=0goreleaser matrix andgo installdistribution of the Action.Shipped in this PR, default off:
github.com/odvcencio/gotreesitterpinned exactly at v0.20.8 (MIT). This is the deliberate, documented end of the zero-dep stance; mitigations per spike §8 — exact pin, go.sum enforcement, differential CI vs the reference C runtime, grammar-subset embedding. Vendor-vs-fork is the flagged follow-up before default-on.parsers.treesitter: off|auto(default off — byte-for-byte legacy behavior, verified by a toggle test).ParseScriptFileseam (SyntaxTree/CompiledQuery/QueryHitinchecks/support), cached per scan in the corpus like Go ASTs. Per-file regex fallback on parse failure, >25% error-node bytes, or files >256KiB (bounds parse heap).quality.typescript.explicit-any,non-null-assertion(incl. definite-assignment!),double-assertion,security.typescript.unsafe-html-sink+ its JS mirror. Same IDs/levels/messages; tree findings carryconfidence: high.satisfies, formatter-split expressions, JSX): regex baseline 63.6% precision / 53.8% recall → tree 100%/100%, with pure-Go vs CGo node-level parity.Compatibility
parsers.treesitter: off, fixture demotion on, context family off in diff mode).RuleMetadata.FixTemplatechanged fromstringto a typed struct in the SDK surface;explainoutput keepsfix_templateas a string and addsfix_template_kind.partialFingerprints,properties.confidence) — additive, spec-compliant.Testing
505 → 632 tests. New: precision corpus with per-rule TP/FN/FP scoring, tree-sitter differential corpora (auto == ground truth AND off == pinned regex), off-vs-auto byte-equality, fallback paths (oversize/garbage/error-heavy), concurrency determinism +
-race, baseline line-shift resilience, doctor rule-health, context-family fixtures, A09 adversarial negatives. The repo self-scan stays clean, and the corpus harness now gates every future detector change.Follow-ups (tracked in docs/treesitter-spike.md §9)
gotreesitterbefore default-on; large-corpus burn-in (parity ≥99.99% of nodes).parsers.treesitterdefault oncerule_statstelemetry shows strictly fewer suppressions in the field.Header.Setbearer tokens,dbPass :=naming miss, comment FPs in raw-line rules).🤖 Generated with Claude Code