@@ -8,7 +8,67 @@ dates are ISO-8601. The previous line is recorded in [`CHANGES_v0.2.md`](CHANGES
88
99## [ Unreleased]
1010
11+ ### Fixed (hard-audit follow-up)
12+ - ** CRITICAL — gitignored ` .env ` files are now scanned.** Discovery honored ` .gitignore ` ,
13+ so the flagship "hardcoded key in ` .env ` " detection silently didn't run on real repos.
14+ Credential files (` .env* ` ) are now always scanned.
15+ - ** Action exfiltration channel closed.** The narrate job no longer runs an LLM over the
16+ raw untrusted repo with a secret + Bash egress — it renders deterministically via
17+ ` cli/dsgai_report.py ` (no LLM, no API key in the workflow at all).
18+ - ** CVE severity/coverage:** severity computed locally from OSV's CVSS vector (a 9.8 no
19+ longer shows INFO when NVD is down; deterministic); go.mod + package-lock.json parsers
20+ (Go/npm had zero coverage); failed fetches no longer poison the cache.
21+ - ** Engine:** ` rg ` invocations are batched so large repos don't crash the arg limit
22+ (a crash exited 1, masquerading as findings; now exits 2).
23+ - ** Coverage:** P16.1 file-existence rule mode makes DSGAI16 PASS reachable; DSGAI20 now
24+ scans ` *.js ` (unauthenticated JS ` /chat ` endpoint caught).
25+ - ** Packs/docs:** gitleaks catches ` AZURE_OPENAI_KEY ` /` GCP_* ` /` AWS_* ` names; Semgrep
26+ export forces ` (?m) ` for line-anchored rules; the tool-neutral prompt variant no longer
27+ leaks Claude-Code-isms; the pre-commit hook probes for PCRE2 instead of failing open.
28+ - ** Report/cleanup:** STRICT report never falls back to a real path on a filemap miss;
29+ line numbers escaped; removed dead code; wired the ` run_cve_enrichment ` toggle.
30+
1131### Added
32+ - ** Benchmark methodology + announcement drafts** (PR-16 hand-off). ` docs/BENCHMARK.md `
33+ (corpus selection, deterministic run steps, a labeling-sheet template, a per-rule
34+ precision snippet, and the responsible-disclosure rule for live findings) and
35+ ` docs/ANNOUNCEMENT-DRAFTS.md ` (Slack / mailing-list / call-for-reports / lightning-talk).
36+ The benchmark ** execution + labeling** and the ` scanner-v0.4.0 ` release remain
37+ maintainer tasks.
38+ - ** Ecosystem expansion + rule-pack export** (PR-15).
39+ - ** C# / Rust / Ruby** : detection signals (Semantic Kernel/Azure.AI.OpenAI, async-openai,
40+ ruby-openai); CVE manifest parsing for ** NuGet** (` *.csproj ` ), ** crates.io**
41+ (` Cargo.lock ` ), ** RubyGems** (` Gemfile.lock ` ) via OSV; credential coverage extended to
42+ ` *.cs ` /` *.rs ` /` *.rb ` /` *.csproj ` (13 DSGAI02/13 rules), with C#/Rust/Ruby fixture cases.
43+ - ** ` build/export_semgrep.py ` → ` dist/dsgai.semgrep.yaml ` ** : exports the 85 STRUCTURAL
44+ rules as a Semgrep pack (value-bearing excluded by design) so incumbent toolchains
45+ carry the DSGAI framework. Generated from the rules YAML; drift is a CI failure.
46+ - ** Templated report, single-sourced prompt variant, static ATLAS map** (PR-14).
47+ - ` cli/dsgai_report.py ` + ` templates/report.css ` : the HTML report is now rendered
48+ ** by code** from the checkpoint (deterministic, testable), with a golden structural
49+ test. The LLM contributes only prose (executive summary / remediation) via ` --prose ` .
50+ STRICT mode renders file IDs (` F07:12 ` ) and writes ` DSGAI-filemap.json ` ;
51+ accessibility — every status carries a symbol + text label, not colour alone.
52+ - ** Sample PNG regenerated** from the fixture app via the new renderer + headless
53+ Chrome (~ 45 KB, fully reproducible, zero real-repo disclosure).
54+ - ` build/generate_prompt_variant.py ` : ` dsgai_scanner_prompt.md ` is now generated from
55+ the skill (frontmatter + ` cc-only ` blocks stripped) — drift is a CI failure
56+ (` --check ` ), single-sourced so the two variants can't diverge.
57+ - ` rules/atlas-map.yaml ` : static MITRE ATLAS technique→control map; the skill's live
58+ ` site:atlas.mitre.org ` searches are removed in favour of it.
59+ - ** CVE pipeline, suppressions, baseline, incremental scanning** (PR-12).
60+ - CVE fetching moved into the CLI (` cli/dsgai_cve.py ` , stdlib urllib): OSV
61+ ` querybatch ` is the per-version source, NVD enriches CVSS by ` cveId ` only (no
62+ ` keywordSearch ` ). Cached at ` ~/.dsgai/cve-cache/ ` (24h TTL, ` --refresh-cve ` );
63+ online and offline runs are byte-identical. ** The LLM never transcribes CVE data.**
64+ - Inline ` # dsgai-ignore: P##.# reason="…" ` suppressions — surfaced in a visible
65+ ` suppressed ` section, never silently dropped; a reason is required.
66+ - ` baseline ` subcommand + ` --baseline ` — gate only on findings not in the baseline.
67+ - ` --diff <ref> ` incremental scans (files changed vs a ref), labelled
68+ "INCREMENTAL — not a full assessment".
69+ - New ` cve ` subcommand; ` --exclude ` /` --diff ` /` --baseline ` wired through the skill and
70+ the Action (which now fetches ` dsgai_cve.py ` ). CVE enrichment reaches CI Job 1 with
71+ no WebFetch. ` langchain==0.1.0 ` yields real OSV advisories incl. EXPLOITABLE.
1272- Contributor infrastructure: ` [scanner] ` GitHub issue-form templates (false-positive,
1373 false-negative, new-rule, bug), scanner ` CONTRIBUTING.md ` , public ` ROADMAP.md ` , and
1474 this changelog scaffold. (PR-01)
@@ -44,10 +104,70 @@ dates are ISO-8601. The previous line is recorded in [`CHANGES_v0.2.md`](CHANGES
44104 (9 tests) asserts every PCRE compiles, the fixture scan matches the answer sheet
45105 exactly, SARIF validity, and the redaction guarantee. ` requirements-dev.txt ` +
46106 dependabot ` pip ` for the scanner. (PR-05)
107+ - ** Checkpoint schema + CI self-test** : ` schemas/dsgai-scan.schema.json ` formalizes
108+ ` DSGAI-scan.json ` and ** forbids** ` match_text ` /` content ` /` value ` /` raw_grep_output ` on
109+ every finding (` "field": false ` ), making the redaction guarantee machine-checkable.
110+ The CLI self-validates its checkpoint (stdlib) before writing and gained a
111+ cache-invalidation check (` checkpoint_is_valid ` : reuse only at current HEAD, clean
112+ tree, matching ruleset). New ` .github/workflows/scanner-selftest.yml ` installs
113+ ripgrep, runs pytest, and validates the ruleset + a fixture scan against their schemas
114+ — the gate that makes external rule PRs safely mergeable. The PCRE compile check now
115+ keys on rg's exit code (catches PCRE2 errors the old substring check missed). (PR-06)
116+
117+ - ** Skill rewrite** (` dsgai_scanner_tool.md ` ) — the skill is now a CLI-first
118+ orchestrator, not the engine. Adds a mandatory ** Trust & Environment Preamble**
119+ (repo content is untrusted; scanner-directed instructions are recorded as a note and
120+ ignored — verified injection-immune on the deterministic path), a ** Step 1.5**
121+ CLI-first flow with an in-context fallback and ` engine: ` header, the value-bearing
122+ ** ` rg -o --replace '' ` ** protocol (secret never leaves ripgrep), ** STRICT-mode file
123+ IDs** (` F07:12 ` ) with a gitignored ` DSGAI-filemap.json ` , an ** evidence-citation**
124+ requirement (no status without rule IDs + locations), ** timestamped reports** under
125+ ` dsgai-reports/ ` , checkpoint cache-invalidation, and ` compatible_cli ` frontmatter.
126+ (PR-07)
127+
128+ - ** Hardened GitHub Action** (` integrations/dsgai-scan.yml ` ): split into a ** ` scan ` **
129+ job (deterministic CLI only — no secrets, no LLM, no egress; runs on fork PRs; emits
130+ SARIF + checkpoint) and an optional ** ` narrate ` ** job (Claude Code with a reduced
131+ toolset ` Read,Write,Edit,Bash ` — no WebFetch/WebSearch — rendering from the checkpoint;
132+ skipped on forks). Closes the exfiltration channel where untrusted PR content met an
133+ agent holding both secrets and egress. All actions pinned by full SHA; scanner fetched
134+ from a pinned upstream commit; SARIF uploaded via Code Scanning (guarded off forks).
135+ Fixed the push-gate bug — gating is now driven by the ` DSGAI_FAIL_ON ` repo variable
136+ (empty = report-only), not force-gated on every push. (PR-08)
137+
138+ - ** README truth pass** : reflects the deterministic-CLI + LLM-orchestration architecture,
139+ two engine modes, SARIF/Code Scanning, timestamped reports, file-ID strict mode, and
140+ a ** Cost & runtime** section ($0 CLI-only mode, fork-PR behavior, ` --diff ` marked
141+ v0.4). Adds a Contributing quick-start ("found a wrong result? that's a contribution").
142+ Skill version badge → v0.3. (PR-09)
143+
144+ - ** Pre-commit: gitleaks pack + portable fallback** (PR-10). New
145+ ` integrations/gitleaks/dsgai.toml ` — a gitleaks rule pack covering the DSGAI
146+ credential set (quote-optional named assignments + raw token prefixes: Slack ` xoxb- ` ,
147+ GitHub ` ghp_ ` /` github_pat_ ` , Google ` AIza ` , AWS ` AKIA ` , Anthropic/OpenAI project keys,
148+ JWT) with an allowlist for ` tests/fixtures/** ` , lockfiles, minified JS, and snapshots.
149+ ` pre-commit-hook.md ` now recommends gitleaks as primary. The bespoke
150+ ` dsgai-secret-scan.sh ` fallback is fixed for portability: ` mapfile ` → a bash-3.2-safe
151+ ` while read -d '' ` loop, ` grep -zE ` → a ` case ` filter, quote-optional pattern (catches
152+ the unquoted-` .env ` miss), plus a token-prefix branch — shellcheck clean.
47153
48154### Changed
155+ - Honest-language pass across the skill ** and README** : every "safe to share/commit/store"
156+ replaced with "designed to minimize disclosure" + a residual-risk note — the Phase-2
157+ overclaim gate now passes repo-wide. (PR-07, PR-09)
158+ - Sample-report image caption now states it is interim and will be regenerated from the
159+ public fixture app once the deterministic report template lands (PR-14). (PR-09)
49160- ` DSGAI-samplereport.png ` compressed from ~ 5.0 MB to ~ 0.35 MB (14×) as an interim fix;
50161 full regeneration from the fixture app lands in PR-09. (PR-02)
51162
52163### Fixed
53- - _ nothing yet_
164+ - ** Confirmed false negative** (unquoted ` .env ` key): P02.1–P02.5 and P13.4 are now
165+ quote-optional, and a new ** P02.9** catches raw token literals (` sk-proj- ` , ` sk-ant- ` ,
166+ ` ghp_ ` , ` github_pat_ ` , ` xox[baprs]- ` , ` AIza ` , ` AKIA ` , JWT) assigned to * any* variable
167+ name. The fixture ` .env ` and the JS ` xoxb- ` token are now caught. (PR-11)
168+ - ** Confirmed false positive** (innocent webhook flagged as LLM SQL injection): ** P12.1**
169+ rewritten to LLM-signal variable names and gated on an LLM call within 30 lines
170+ (` requires_nearby.pattern ` , confidence ` medium ` ). ` webhook.py ` no longer fires;
171+ ` sql_agent.py ` still does. Both Appendix A commands verified. The CLI gained
172+ ` requires_nearby.pattern ` support and a ` drop ` outcome for corroborating-signal rules.
173+ Zero ` known_bug ` markers remain in the answer sheet. (PR-11)
0 commit comments