@clear-capabilities/agentic-security-scanner 0.195.26 → 0.195.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,19 @@
9
9
  > make the history less accurate, not more.
10
10
 
11
11
 
12
+ ## 0.195.27 - GA programme, release G: provenance adverse histories with a frozen contract and an absolute latency budget, promoted-rule regressions that run in CI
13
+
14
+ **Measured, 0.195.26:** `TIMINGS preflight=3s push=7s pr=4s checks=393s merge=6s verify=5s tag=2s release=161s npm=636s total=1217s release-clock=174s`, shipped from the merge to the published release in 174 s; the npm listing lagged the publish and `ship --resume` confirmed it.
15
+
16
+ Two items of the GA plan that are code and tests: GA-05 (adverse Git histories in the origin corpus, the provenance contract frozen, the old ratio target replaced by an absolute budget) and GA-07 §2 and §3 (promoted-rule regressions that run from every CI template on a machine that never promoted the rule, a shared negative corpus, the reviewed scope and evidence recorded). Nothing moved a maturity.
17
+
18
+ - **Ten adverse histories in the origin corpus, 23 of 23 resolved** (`bench/provenance-accuracy`, `npm run bench:provenance-accuracy:check`, in the pre-push gate). A revert of a fix (bounded at the first introduction, the origin is the revert and `findingOrigin.revertOf` names what it reverted), a cherry-pick with `-x` (`cherryPickOf` names the source), a squash merge, an amended introducing commit, a `git mv` after the introduction, a dirty file whose vulnerable line is committed (origin resolved, `analysisBasis.dirty` set), a merge whose first parent carries the flaw, a conflict resolution that writes the flaw, a transitive lockfile bump (`express` to `qs`, the chain re-derived at the origin commit) and a configured forge provider that cannot be reached. A fixture may now declare `mode: 'deep'` and hand the scan an environment (a `--provenance-since` boundary at one of its own commits) and a `verify` of the record beyond the origin commit, and the corpus runs the deep-mode code it never ran before.
19
+ - **Two provenance fixes the corpus found.** Deep mode's revert and cherry-pick annotation ran only in the retry after a standard-walk miss, so a resolved origin (the common case) never carried `revertOf` or `cherryPickOf`; it is applied to every origin deep mode resolves. A revert of a revert is titled `Reapply "..."` by git since 2.43 and was not recognised as a revert; the diff inversion still decides. And a provider that erred or did not answer returned the same `null` as "no pull request names this commit"; it now returns `{unavailable, reason}` and the coordinator records a limitation naming the provider and the reason, with the origin, status and confidence untouched.
20
+ - **The provenance contract is frozen** (`docs/reference/finding-provenance-contract.md`, `scanner/test/contracts/finding-provenance.contract.test.js`, in `test:posture` and run by `check-ga-contracts` on every release). The record and its parts field by field, the six terminal states, the fifteen confidence reason codes (derived from the sources by the test, so a new code must be documented), the eleven eligibility categories behind the coverage figure, the identity rules (email withheld, stable pseudonyms), the default behaviour per command, the shared timeout (60 s, 300 s deterministic, a 2 s per-finding floor, 20 provider calls at 8 s each) and the latency budget; exercised for real on git fixtures: a shallow clone is `partial`, a root commit is `complete` capped at `medium`, an uncommitted line is `uncommitted`, an expired budget is `budget_exhausted` and not cached, `scan` leaves provenance off until a flag asks. The `finding-provenance` registry row now carries the contract, the contract test, `gate: provenance-gate`, the limits section and `since`; its remaining GA-bar gap is a hosted platform job.
21
+ - **An absolute latency budget replaces the 1.3x ratio target** (`bench/provenance`, schema `provenance/v4`). The bench records the wall time provenance ADDS to the same iteration's provenance-disabled scan and holds its p95 to a budget frozen in the runner with its derivation (cold 2000 ms, warm 250 ms on the 15-finding, 45-commit fixture), beside the ratio gates; a re-baseline cannot loosen it. Recorded on the maintainer host (60 iterations): cold added p50 1196 ms, p95 1215 ms; warm added p50 39 ms, p95 49 ms; the base scan is 189 ms (it was 44 ms when the baseline was recorded in August, a four-fold change in the engine's own cost on this fixture since, recorded here and not explained by this release). The guide now carries the per-finding figure (about 80 ms cold) as the number to budget with.
22
+ - **Promoted-rule regressions run in CI, on any machine** (`rules regress`). Every CI template (GitLab, CircleCI, Buildkite, Jenkins, which also moves to Node 24) and the GitHub Actions workflow `/setup --ci` generates run it, before the scan gate so a failing gate cannot hide a rule regression; the template test asserts the order and the key variable. `rules promote --sign-key` now also signs the lifecycle ledger with the operator's Ed25519 key (`ledger.json.author.sig`, renewed by a later command run with the same key) and prints the public key; on a machine whose per-install HMAC key differs, every `rules` command accepts the ledger when its chain verifies and the author signature verifies against `AGENTIC_SECURITY_RULES_PUBLIC_KEY` (a CI variable, never a file in the checkout) or the rule-pack trust store, and refuses it otherwise, including with the last entry dropped. `rules regress --json` reports `ledgerVerifiedBy`.
23
+ - **A shared negative corpus, and the reviewed scope and evidence.** The scanner ships 27 safe snippets across nine languages (`rule-compiler/negative-corpus.js`, the same everywhere); they sit in front of the shared false-positive corpus with the other promoted rules' safe code, the project's `fp-corpus/` and directories a fleet shares through `AGENTIC_SECURITY_RULES_FP_CORPUS`, and evaluation, promotion and regression refuse a rule that fires on any of them. `--scope` is required at promotion, and the promotion event and ledger entry record the evidence the reviewer looked at (digests of the evaluation, the provenance and both corpus halves); `regress` re-derives the corpus digests and reports a rule whose corpus changed after the review. An "independent" example that is the original snippet, its patch or a generated mutation (whitespace aside) is refused as not independent. `rules deprecate` retires a promoted rule (the ledger's terminal edge, which no command reached), a rolled-back rule re-enters as a candidate with its history kept (the edge existed and `synthesize` could not take it), and `rule test` exits 1 on a missed vulnerable fixture or a hit on a clean one (it exited 0 whatever the fixtures said). The `rule-compiler` registry row gains `gate`, `limits` and `since`.
24
+
12
25
  ## 0.195.26 - GA programme, release F: composed router mounts, stale citations refused, frozen graph artifact contracts with a revision check
13
26
 
14
27
  **Measured, 0.195.25:** `TIMINGS preflight=3s push=7s pr=5s checks=433s merge=6s verify=6s tag=2s release=223s npm=237s total=922s release-clock=237s`, shipped from the merge to the published release in 237 s; the npm listing lagged the publish and `ship --resume` confirmed it.
@@ -1790,7 +1790,7 @@ async function cmdRules(args) {
1790
1790
  // Self-learning finding-to-rule compiler (PRD 3): synthesize/evaluate/promote/status/rollback a DETECTION rule
1791
1791
  // from one confirmed finding — distinct from validate/lock below (rules.yml override linting and pack locking).
1792
1792
  // Dispatches to its own module rather than inlining here, same convention as `triage exploit`/`proof`.
1793
- if (sub === 'synthesize' || sub === 'evaluate' || sub === 'promote' || sub === 'status' || sub === 'rollback' || sub === 'cost' || sub === 'regress') {
1793
+ if (sub === 'synthesize' || sub === 'evaluate' || sub === 'promote' || sub === 'status' || sub === 'rollback' || sub === 'deprecate' || sub === 'cost' || sub === 'regress') {
1794
1794
  return (await import('../src/posture/rule-compiler/cli.js')).cmdRules(args, path.resolve(args.flags.root || '.'));
1795
1795
  }
1796
1796
  const target = path.resolve(args._[2] || '.');
@@ -1807,7 +1807,7 @@ async function cmdRules(args) {
1807
1807
  console.log(` scanner: ${lock.scannerVersion} rulePackHash: ${lock.rulePackHash}`);
1808
1808
  return 0;
1809
1809
  }
1810
- console.error('rules validate | rules lock | rules synthesize <finding-id> --spec <file.json> [--auto] | rules evaluate|promote|status|rollback|cost <rule-id>'); return 4;
1810
+ console.error('rules validate | rules lock | rules synthesize <finding-id> --spec <file.json> [--auto] | rules evaluate|promote|status|rollback|deprecate|cost <rule-id> | rules regress [rule-id]'); return 4;
1811
1811
  }
1812
1812
 
1813
1813
  // `agentic-security secure [--launch]` — smart router. One command picks the
@@ -1970,7 +1970,8 @@ async function cmdRule(args) {
1970
1970
  if (!glob) { console.error('Usage: agentic-security rule test <fixture-glob>'); return 4; }
1971
1971
  const target = path.resolve(args.flags.root || '.');
1972
1972
  const r = await runRuleTests(target, glob);
1973
- return r.ok ? 0 : 4;
1973
+ // GA-07 §3 (0.195.27): a missed vulnerable fixture or a false positive on a clean one is a failed test (exit 1); it used to exit 0 always.
1974
+ return r.ok ? 0 : 1;
1974
1975
  }
1975
1976
  if (sub === 'list') {
1976
1977
  const target = path.resolve(args.flags.root || '.');