@kirrosh/zond 0.23.0 → 0.26.1

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.
Files changed (158) hide show
  1. package/CHANGELOG.md +176 -1
  2. package/README.md +8 -7
  3. package/package.json +2 -3
  4. package/src/CLAUDE.md +112 -0
  5. package/src/cli/commands/add-api.ts +19 -7
  6. package/src/cli/commands/api/annotate/index.ts +359 -4
  7. package/src/cli/commands/api/annotate/lifecycle.ts +1 -1
  8. package/src/cli/commands/api/annotate/overlay.ts +1 -1
  9. package/src/cli/commands/api/annotate/pagination.ts +10 -6
  10. package/src/cli/commands/api/annotate/prompts.ts +39 -2
  11. package/src/cli/commands/audit.ts +360 -54
  12. package/src/cli/commands/check.ts +15 -2
  13. package/src/cli/commands/checks.ts +352 -36
  14. package/src/cli/commands/cleanup.ts +4 -30
  15. package/src/cli/commands/coverage.ts +275 -57
  16. package/src/cli/commands/db.ts +311 -8
  17. package/src/cli/commands/discover.ts +281 -161
  18. package/src/cli/commands/doctor.ts +57 -3
  19. package/src/cli/commands/fixtures.ts +1 -1
  20. package/src/cli/commands/generate.ts +24 -7
  21. package/src/cli/commands/init/bootstrap.ts +4 -1
  22. package/src/cli/commands/init/index.ts +2 -2
  23. package/src/cli/commands/init/skills.ts +43 -0
  24. package/src/cli/commands/init/templates/agents.md +12 -3
  25. package/src/cli/commands/init/templates/skills/warm-up-target.md +122 -0
  26. package/src/cli/commands/init/templates/skills/zond-checks.md +268 -44
  27. package/src/cli/commands/init/templates/skills/zond-seed.md +114 -0
  28. package/src/cli/commands/init/templates/skills/zond-triage.md +88 -26
  29. package/src/cli/commands/init/templates/skills/zond.md +274 -64
  30. package/src/cli/commands/init/templates/zond-config.yml +1 -1
  31. package/src/cli/commands/prepare-fixtures.ts +14 -52
  32. package/src/cli/commands/probe/_seed-bodies.ts +52 -0
  33. package/src/cli/commands/probe/mass-assignment.ts +101 -10
  34. package/src/cli/commands/probe/security.ts +95 -12
  35. package/src/cli/commands/probe/webhooks.ts +2 -0
  36. package/src/cli/commands/probe.ts +87 -11
  37. package/src/cli/commands/refresh-api.ts +59 -1
  38. package/src/cli/commands/report-bundle.ts +3 -11
  39. package/src/cli/commands/request.ts +116 -0
  40. package/src/cli/commands/run.ts +53 -5
  41. package/src/cli/commands/schema-from-runs.ts +128 -0
  42. package/src/cli/commands/secrets.ts +133 -0
  43. package/src/cli/json-envelope.ts +0 -20
  44. package/src/cli/json-schemas.ts +51 -0
  45. package/src/cli/output.ts +17 -1
  46. package/src/cli/program.ts +5 -4
  47. package/src/cli/safe-live.ts +24 -0
  48. package/src/cli/status-filter.ts +0 -10
  49. package/src/core/audit/persist.ts +183 -0
  50. package/src/core/checks/budget.ts +59 -0
  51. package/src/core/checks/checks/cross_call_references.ts +17 -4
  52. package/src/core/checks/checks/cursor_boundary_fuzzing.ts +219 -0
  53. package/src/core/checks/checks/idempotency_replay.ts +1 -5
  54. package/src/core/checks/checks/ignored_auth.ts +44 -1
  55. package/src/core/checks/checks/index.ts +3 -0
  56. package/src/core/checks/checks/lifecycle_transitions.ts +169 -26
  57. package/src/core/checks/checks/negative_data_rejection.ts +119 -16
  58. package/src/core/checks/checks/not_a_server_error.ts +8 -0
  59. package/src/core/checks/checks/open_cors_on_sensitive.ts +47 -18
  60. package/src/core/checks/checks/pagination_invariants.ts +298 -117
  61. package/src/core/checks/checks/positive_data_acceptance.ts +1 -4
  62. package/src/core/checks/checks/status_code_conformance.ts +78 -7
  63. package/src/core/checks/mode.ts +3 -0
  64. package/src/core/checks/recommended-action.ts +5 -1
  65. package/src/core/checks/runner.ts +614 -27
  66. package/src/core/checks/spec-findings.ts +308 -0
  67. package/src/core/checks/types.ts +117 -1
  68. package/src/core/checks/zond-extensions.ts +73 -0
  69. package/src/core/classifier/recommended-action.ts +35 -6
  70. package/src/core/coverage/loader.ts +31 -0
  71. package/src/core/diagnostics/db-analysis.ts +200 -106
  72. package/src/core/diagnostics/failure-class.ts +21 -1
  73. package/src/core/diagnostics/failure-hints.ts +4 -208
  74. package/src/core/diagnostics/suggested-fixes.ts +2 -3
  75. package/src/core/generator/chunker.ts +1 -8
  76. package/src/core/generator/data-factory.ts +199 -61
  77. package/src/core/generator/fixtures-builder.ts +38 -31
  78. package/src/core/generator/index.ts +0 -2
  79. package/src/core/generator/openapi-reader.ts +98 -4
  80. package/src/core/generator/path-param-disambig.ts +30 -4
  81. package/src/core/generator/resources-builder.ts +276 -26
  82. package/src/core/generator/schema-utils.ts +22 -0
  83. package/src/core/generator/suite-generator.ts +168 -15
  84. package/src/core/generator/types.ts +6 -0
  85. package/src/core/identity/identity-file.ts +0 -0
  86. package/src/core/output/README.md +11 -29
  87. package/src/core/output/index.ts +1 -1
  88. package/src/core/output/run.ts +0 -35
  89. package/src/core/output/types.ts +0 -7
  90. package/src/core/parser/dynamic-values.ts +160 -0
  91. package/src/core/parser/variables.ts +0 -0
  92. package/src/core/probe/dry-run-envelope.ts +4 -0
  93. package/src/core/probe/mass-assignment/classify.ts +175 -0
  94. package/src/core/probe/mass-assignment/cleanup.ts +52 -0
  95. package/src/core/probe/mass-assignment/digest.ts +114 -0
  96. package/src/core/probe/mass-assignment/orchestrator.ts +459 -0
  97. package/src/core/probe/mass-assignment/regression.ts +141 -0
  98. package/src/core/probe/mass-assignment/suspects.ts +92 -0
  99. package/src/core/probe/mass-assignment/types.ts +135 -0
  100. package/src/core/probe/mass-assignment-probe.ts +23 -1118
  101. package/src/core/probe/mass-assignment-template.ts +32 -4
  102. package/src/core/probe/path-discovery.ts +3 -4
  103. package/src/core/probe/probe-harness.ts +21 -22
  104. package/src/core/probe/security/baseline.ts +174 -0
  105. package/src/core/probe/security/classify.ts +341 -0
  106. package/src/core/probe/security/cleanup.ts +125 -0
  107. package/src/core/probe/security/detectors.ts +71 -0
  108. package/src/core/probe/security/digest.ts +104 -0
  109. package/src/core/probe/security/orchestrator.ts +398 -0
  110. package/src/core/probe/security/regression.ts +103 -0
  111. package/src/core/probe/security/types.ts +151 -0
  112. package/src/core/probe/security-probe-class.ts +8 -2
  113. package/src/core/probe/security-probe.ts +28 -1449
  114. package/src/core/probe/shared.ts +26 -0
  115. package/src/core/probe/webhooks-probe.ts +5 -7
  116. package/src/core/runner/assertions.ts +1 -1
  117. package/src/core/runner/executor.ts +3 -18
  118. package/src/core/runner/form-encode.ts +8 -18
  119. package/src/core/runner/http-client.ts +38 -1
  120. package/src/core/runner/preflight-vars.ts +19 -15
  121. package/src/core/runner/rate-limiter.ts +11 -29
  122. package/src/core/runner/run-kind.ts +7 -1
  123. package/src/core/runner/schema-validator.ts +2 -6
  124. package/src/core/runner/send-request.ts +11 -6
  125. package/src/core/runner/types.ts +6 -0
  126. package/src/core/setup-api.ts +53 -15
  127. package/src/core/severity/index.ts +0 -63
  128. package/src/core/spec/infer-schema.ts +102 -0
  129. package/src/core/spec/merge-specs.ts +156 -0
  130. package/src/core/spec/schema-from-runs.ts +117 -0
  131. package/src/core/spec/schema-overlay.ts +130 -0
  132. package/src/core/util/ajv.ts +13 -0
  133. package/src/core/util/headers.ts +9 -0
  134. package/src/core/util/url.ts +24 -0
  135. package/src/core/workspace/fixture-gap-report.ts +84 -0
  136. package/src/core/workspace/fixture-gaps.ts +71 -0
  137. package/src/core/workspace/root.ts +13 -11
  138. package/src/db/migrate.ts +2 -0
  139. package/src/db/migrations/0002_run_kind_request.sql +59 -0
  140. package/src/db/queries/collections.ts +2 -2
  141. package/src/db/queries/results.ts +88 -0
  142. package/src/db/queries/runs.ts +56 -2
  143. package/src/db/queries.ts +3 -0
  144. package/src/db/schema.ts +7 -7
  145. package/src/cli/commands/bootstrap.ts +0 -710
  146. package/src/core/anti-fp/bootstrap.ts +0 -34
  147. package/src/core/anti-fp/index.ts +0 -33
  148. package/src/core/anti-fp/registry.ts +0 -44
  149. package/src/core/anti-fp/rules/baseline-echo.ts +0 -74
  150. package/src/core/anti-fp/rules/schemathesis/body_negation_becomes_valid.ts +0 -52
  151. package/src/core/anti-fp/rules/schemathesis/coverage_phase_boundary_positive.ts +0 -38
  152. package/src/core/anti-fp/rules/schemathesis/has_unverifiable_mutations.ts +0 -35
  153. package/src/core/anti-fp/rules/schemathesis/index.ts +0 -24
  154. package/src/core/anti-fp/rules/schemathesis/string_type_mutation_becomes_valid.ts +0 -53
  155. package/src/core/anti-fp/rules/subscription-gated/index.ts +0 -11
  156. package/src/core/anti-fp/rules/subscription-gated/paid-plan-403.ts +0 -75
  157. package/src/core/anti-fp/types.ts +0 -68
  158. package/src/core/generator/create-body.ts +0 -89
package/CHANGELOG.md CHANGED
@@ -4,7 +4,182 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
- (Emptynext development cycle.)
7
+ ## [0.26.1] 2026-07-09
8
+
9
+ Follow-up from the v0.26.0 petstore verify audit (report-zond findings).
10
+
11
+ ### Fixed
12
+ - **`zond run` on a non-existent path is now a hard error (ARV-383):** a path
13
+ absent on disk exits 2 with `No such file or directory: <path> — nothing to
14
+ run`, instead of falling through to the ARV-357 empty-report path and
15
+ reporting a green 0-test "pass". Real trigger: a probe that matched 0 fields
16
+ never created its output dir, then `zond run <that-dir>` went silently green.
17
+ An existing-but-empty dir keeps its ARV-357 advisory exit-0 behavior.
18
+
19
+ ## [0.26.0] — 2026-07-09
20
+
21
+ Deterministic gap-fills surfaced by a docgen-core-service audit — all pass the
22
+ litmus test (same input → same output, no severity/FP/blame judgment). Plus an
23
+ m-25 distribution cleanup that collapses the workspace layout to one convention.
24
+
25
+ ### Added
26
+ - **Multi-spec merge (ARV-375):** `zond add api <name> --spec a --spec b …`
27
+ unions N specs into one audit target. Deterministic last-wins on path /
28
+ component collisions, surfaced as warnings (path collisions + same-name /
29
+ different-shape schema collisions). Core in `src/core/spec/merge-specs.ts`.
30
+ - **`zond secrets set <key> <value>` (ARV-377):** writes `apis/<name>/.secrets.yaml`
31
+ with a `.bak` backup, never echoes the value, and auto-strips a pasted
32
+ `Bearer ` prefix (`--literal` keeps it verbatim). Closes the "hand-rolled
33
+ python to rotate an expired token" gap and ARV-367/AC3.
34
+ - **`zond db diagnose --union <spec>` (ARV-380):** aggregate
35
+ `by_recommended_action` (+ summary counts, deduped examples) across a run
36
+ set, reusing coverage's `--union` vocabulary (`session` / `since:<dur>` /
37
+ `tag:<name>` / `runs:<ids>`). `--api` scopes `since:`/`tag:` to a collection.
38
+ - **Coverage deprecated flags (ARV-379):** `coverage --json` now carries a
39
+ per-entry `deprecated` boolean on the `*Endpoints` bucket arrays plus a
40
+ top-level `deprecatedEndpoints` list, so a consumer can split "real gap"
41
+ from "deprecated, skip by design" without re-reading spec.json.
42
+
43
+ ### Fixed
44
+ - **`db diagnose --union` version follow-up + candidate-surfacing (ARV-381/382):**
45
+ disambig's parent-walk now skips version segments (`/v30/{code}`), aligning
46
+ with `owningCollectionForPathParam` which already strips them — resolves the
47
+ `_v30_code` miss-no-list class. And when prepare-fixtures can't confidently
48
+ derive an owner list, the item carries `candidates[]` — plausible GET/list
49
+ endpoints ranked by proximity (deprecated ones marked) — instead of
50
+ dead-ending; zond surfaces the evidence, the agent picks the value. On
51
+ docgen-core-merged: `miss-no-list` 40 → 22 total, 9 of those now carry
52
+ candidates, the rest are honest dead-ends (no listable source in the spec).
53
+ - **Resource graph misses `/list`-style owners (ARV-376):** `resolveOwnerListPaths`
54
+ now links `/list` (and `/search`, `/find`) endpoints to their sibling
55
+ `/{code}` and `/byid/{id}` params; the `byid` accessor marker no longer
56
+ collapses every read-by-id param into one global `byid_id`; a malformed spec
57
+ whose path template (`/byid/{id}`) disagrees with the declared param name
58
+ (`byid_id`) is reconciled to the template; secondary lookup keys (`{code}`)
59
+ surface as candidates. On the docgen-core-merged spec this cut
60
+ prepare-fixtures `miss-no-list` from 40 → 30.
61
+ - **`fixtures add` batch (ARV-378):** confirmed `fixtures add <pairs...>`
62
+ already applies N `key=value` pairs in one call (one write + one `.bak`) —
63
+ no shell loop needed.
64
+
65
+ ### Removed
66
+ - **Flat `zond.db` workspace layout (m-25):** dropped the legacy root-level
67
+ `zond.db` marker and its implicit default-DB resolution. The DB now lives
68
+ only at `.zond/zond.db`; `zond.config.yml` / `.zond/` / `apis/` remain the
69
+ workspace markers. Migrate an old workspace with `mv zond.db .zond/` (or
70
+ re-`zond init`); an explicit `--db <path>` still opens any file. Removes the
71
+ dual-layout confusion that let a root `zond.db` and `.zond/zond.db` coexist.
72
+ - **Dead `benchmarks/` references (m-25):** pruned the never-committed
73
+ `benchmarks/**` entries from `knip.json` and the dead `bench:api` script from
74
+ `package.json` (`knip` is now clean).
75
+
76
+ ## [0.25.0] — 2026-07-07
77
+
78
+ m-24: **rebuild around the agent.** zond becomes a set of deterministic
79
+ dumb tools — it sends requests, validates schemas, stores and diffs runs,
80
+ and reports gaps. The autonomous heuristic layer that produced most of the
81
+ 0.24 bug-stream (auto-discovery/seed/cascade, annotate-auto guess-engine,
82
+ severity calibrators, anti-FP suppression) is removed; the agent now owns
83
+ every judgment call (severity, spec-vs-backend blame, "is this a false
84
+ positive?", which value fills a fixture). The deterministic core —
85
+ send → validate → store → diff — survives intact. A litmus test in
86
+ `src/CLAUDE.md` keeps the heuristic layer from creeping back one
87
+ "reasonable" fix at a time: same input → same output, or it's the agent's.
88
+
89
+ ### Removed (heuristic layer)
90
+ - **Autonomous fixture seed/cascade engine gone (ARV-336):** `bootstrap.ts`
91
+ + `create-body.ts` deleted. Live-POST resource creation guessed bodies and
92
+ cascaded parent→child (1% success on Stripe). prepare-fixtures is now
93
+ single-pass verify + gap-report; the agent (or user) creates resources.
94
+ - **Severity calibrators + anti-FP suppression gate removed (ARV-337 Cut A):**
95
+ severity is agent judgment; anti-FP `applyAntiFp` no longer gates emission —
96
+ the rule reasons survive as raw evidence, not as a suppress-or-emit verdict.
97
+ - **annotate-auto guess-engine removed (ARV-337 Cut B):** `inferSeedBody`
98
+ fabricated bodies from format/name fallbacks and self-ranked confidence.
99
+ annotate now dumps the spec slice; the agent authors the YAML, zond
100
+ validates and merges.
101
+
102
+ ### Agent-facing artifacts & new mechanics
103
+ - **YAML run summary (ARV-338):** `zond db diagnose` drops prose hints (keeps
104
+ the mechanical counts/grouping spine); `db … --report yaml` emits
105
+ agent-friendly output.
106
+ - **Field-level run diff (ARV-339):** `zond db compare` now diffs response
107
+ body/schema per field, not just status.
108
+ - **prepare-fixtures gap report (ARV-349/350):** undefined vars + unseeded
109
+ capture-chain roots are reported deterministically — no auto-seed.
110
+ - **Agent-orchestrated auto-seed (ARV-355):** `zond request --capture` +
111
+ `zond-seed` skill — the agent reasons about creation order, zond executes.
112
+ - **Ambiguous-id guard (ARV-334):** the hint-less fixture harvest reports
113
+ `miss-ambiguous-id` (naming the candidate string field) instead of silently
114
+ putting a numeric `id` into a string slot like `{owner}` — zond flags the
115
+ ambiguity, the agent/annotation picks the field.
116
+ - **generate preserves hand-edits (ARV-361):** suite files whose auto-gen
117
+ header was removed are treated as agent-owned and preserved on regenerate;
118
+ `--force` overwrites them (was a documented no-op).
119
+
120
+ ### Checks, probes & safety
121
+ - **`--safe`/`--live` parity (ARV-299)** across `checks run` and `probe`.
122
+ - **stateful scope (ARV-325):** `--check stateful` expands to the
123
+ state-machine set only.
124
+ - **cascade fast-fail (ARV-326):** prepare-fixtures aborts early on a
125
+ dead/scoped-wrong token instead of grinding through futile attempts.
126
+ - **input-triggered 5xx caught (ARV-340/341):** self-generated body rejects
127
+ route to `fix_spec`, not `report_backend_bug`.
128
+ - **child-exclude wired (ARV-330):** the last-attempt history lookup uses the
129
+ all-run-kinds query + child-exclude pattern so probe sub-resource POSTs
130
+ (`/v1/accounts/{id}/reject`) don't starve the real create-path window.
131
+ - **checks reporting fixes (ARV-322/323/328):** suppressed-count accuracy,
132
+ SIGTERM ndjson counting, throttled stderr progress on long runs.
133
+
134
+ ### Sweeps & infrastructure
135
+ - **Bounded/resumable sweeps (ARV-342):** `--skip-ops` / `--max-ops` op-window.
136
+ - **DB retention (ARV-266):** `zond db prune` + `zond db stats`, per-run-kind
137
+ cutoffs, VACUUM after delete.
138
+ - **Schema from observed runs (ARV-175/176):** `schema-from-runs` command +
139
+ `refresh-api --merge-schema` — union/required-intersection from real
140
+ responses, not guessing.
141
+
142
+ ### Report, triage & audit-run cleanup
143
+ - Report-noise, severity and UX cleanup (ARV-343/344/345/346/348/351/353);
144
+ compare scope tag, partial summary on SIGTERM, triage depth aggregate
145
+ (ARV-352/354).
146
+ - Empty-dir `zond run --output` writes a `0 tests` envelope instead of no
147
+ file (ARV-357); cross-phase double-emit documented for triage (ARV-358).
148
+ - Workspace-leak fix (env-independent audit paths) + self-compare guard
149
+ (ARV-359/360), from a petstore audit-run.
150
+
151
+ ## [0.24.0] — 2026-07-03
152
+
153
+ m-22 validation sprint. No new milestone surface — this release hardens the
154
+ 0.23.0 depth-checks/probe/audit stack against real APIs. ~40 fixes (ARV-260..332)
155
+ were found by running `zond audit`/`zond-scan` live against Stripe, GitHub,
156
+ Resend and docgen-core, not by unit tests.
157
+
158
+ ### Safety & contracts
159
+ - **Safe-mode leak closed (ARV-332):** `checks run --check stateful --include
160
+ method:GET` no longer fires POST create-chains — CRUD groups are built from
161
+ the filtered op set, so `ensure_resource_availability`/`use_after_free`
162
+ self-skip when no write is in scope. Critical for scanning APIs you don't own.
163
+ - Exit-code contract hardened (ARV-303/307/308/309/310): audit judges stages on
164
+ `envelope.ok`, not raw exit code; budget-exhaust distinguished from network error.
165
+ - `open_cors_on_sensitive` HIGH only on 2xx + ambient (cookie) credential
166
+ (ARV-312/316) — kills a class of false HIGHs.
167
+
168
+ ### Severity calibration
169
+ - Probe-side severity calibrator (ARV-283/300): `SecuritySeverity ↔ Severity`
170
+ adapter with sentinel passthrough; wired into security probe. mass-assignment/
171
+ static/webhooks tracked in ARV-311.
172
+
173
+ ### Fixture / seed pipeline
174
+ - FK-aware body builder wires reference fields to fixtures (ARV-45).
175
+ - Topological seed order + body-FK deferral (ARV-324/327); gap-report flags
176
+ unfillable complex root resources instead of silently skipping (ARV-329/330).
177
+
178
+ ### Ops & workflow
179
+ - `ZOND_WORKSPACE` honored; `zond-audit` workflow added for reproducible runs.
180
+ - ndjson reporter stability (ARV-314/318/320/322); path-casing canonicalized
181
+ before workspace-root walk (ARV-315).
182
+ - Repo-wide ponytail cleanup: dead code removed, probe monoliths deduped.
8
183
 
9
184
  ## [0.23.0] — 2026-05-15
10
185
 
package/README.md CHANGED
@@ -21,12 +21,12 @@ Bootstrap a workspace, register your first API, then fill its fixtures:
21
21
  zond init # bootstrap workspace (no fixture changes)
22
22
  zond add api my-api --spec ./openapi.json # register: copies spec.json + emits manifest
23
23
  zond doctor --api my-api --missing-only # gap report: which vars are UNSET
24
- zond prepare-fixtures --api my-api --apply [--seed] # fill apis/my-api/.env.yaml from live API
24
+ zond prepare-fixtures --api my-api # gap report: verify fixtures + which FK vars need a value
25
25
  ```
26
26
 
27
- For path-FK ids that auto-discover/--seed can't reach (vendor-dashboard
28
- ids like `cus_*`, GitHub PR numbers, Sentry issue ids), use the manual
29
- helpers (ARV-195):
27
+ `prepare-fixtures` **reports** gaps it never harvests a value (which
28
+ record/field fills a path slot is your call). Fill each gap with the
29
+ manual helpers (ARV-195):
30
30
 
31
31
  ```bash
32
32
  zond fixtures add --api my-api customer_id=cus_123 --validate --apply
@@ -46,9 +46,10 @@ Each registered API gets four files in `apis/<name>/`:
46
46
  - `.api-resources.yaml` — CRUD chains, FK dependencies, ETag/soft-delete flags.
47
47
  - `.api-fixtures.yaml` — **manifest** of required `{{vars}}` (read-only, auto-generated).
48
48
 
49
- Plus a sibling `.env.yaml` that you (or `zond prepare-fixtures`) fill with
50
- the **values** for those vars. The manifest/values split is strict — see
51
- the [workspace contract](AGENTS.md#workspace-contract) for details.
49
+ Plus a sibling `.env.yaml` that **you** fill with the **values** for those
50
+ vars (`zond prepare-fixtures` only reports which are missing). The
51
+ manifest/values split is strict — see the
52
+ [workspace contract](AGENTS.md#workspace-contract) for details.
52
53
 
53
54
  Run `zond refresh-api <name> [--spec <new-source>]` to re-snapshot when the
54
55
  upstream spec changes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kirrosh/zond",
3
- "version": "0.23.0",
3
+ "version": "0.26.1",
4
4
  "description": "API testing platform — define tests in YAML, run from CLI, generate from OpenAPI specs",
5
5
  "license": "MIT",
6
6
  "module": "index.ts",
@@ -34,8 +34,7 @@
34
34
  "schemas": "bun run scripts/emit-json-schemas.ts",
35
35
  "schemas:check": "bun run scripts/emit-json-schemas.ts --check",
36
36
  "lint:dead": "knip --reporter compact",
37
- "build": "bun build --compile src/cli/index.ts --outfile dist/zond && bun run scripts/codesign-darwin.ts ./dist/zond",
38
- "bench:api": "bun benchmarks/api/server.ts"
37
+ "build": "bun build --compile src/cli/index.ts --outfile dist/zond && bun run scripts/codesign-darwin.ts ./dist/zond"
39
38
  },
40
39
  "devDependencies": {
41
40
  "@types/bun": "latest",
package/src/CLAUDE.md ADDED
@@ -0,0 +1,112 @@
1
+ # src/ — architecture map
2
+
3
+ Этот файл — точка входа в **код** zond. Workspace-контракт (`.api-fixtures.yaml` vs `.env.yaml`) — в [`../AGENTS.md`](../AGENTS.md), пользовательский CLI-референс — в [`../ZOND.md`](../ZOND.md).
4
+
5
+ zond — API hygiene scanner. **Dumb-tool**: умеет дёргать API, собирать evidence, проверять конформность спеки. Не зовёт LLM, не делает решения — это работа агента, который скармливает zond'у YAML и читает обратно отчёты.
6
+
7
+ ### Litmus-тест: что кладём в zond, а что оставляем агенту
8
+
9
+ m-24 срезал эвристический слой (discovery/seed/cascade, severity-калибраторы, anti-FP-гейты, annotate-auto). Чтобы он не наползал обратно по одному «разумному» фиксу за раз — **каждое изменение zond проходит один тест: детерминировано ли оно?** Один и тот же вход → один и тот же выход, без догадок про намерение / вину / серьёзность / «баг ли это на самом деле».
10
+
11
+ - ✅ **В zond** (детерминированное, быстрое, скучное): слать запросы, валидировать схемы, считать диффы, эмитить evidence + closed-enum хинты, **корректно ограничивать scope чека** (какие case-kinds / методы он оценивает), плюс plumbing/скорость/артефакты. zond — удобный работающий быстрый инструмент.
12
+ - ❌ **Агенту** (суждение): severity, приоритет, атрибуция вины (spec vs backend), «это false-positive?», «это эксплуатируемо?», выдумывание фикстур, многопроходный discovery. Сложное решает умный агент, читая сырой evidence.
13
+
14
+ Практическое следствие для «zond что-то пропустил/зашумил» из аудита: **чини scope чека детерминированно** (напр. ARV-340 — чек смотрел не те case-kinds) — но **не добавляй suppression/down-rank «это FP»** (это ровно тот anti-FP-гейт, что убрал ARV-337; FP отсекает агент в триаже). `recommended_action` — самая размытая из выживших поверхностей: это тонкий routing-хинт, держи его тупым, не выращивай в мини-классификатор.
15
+
16
+ **Evidence-over-inference (ARV-376):** статические инференсеры по форме URL (какой `/list` владеет `{id}`, какой ресурс за `{code}`) имеют бесконечный хвост идиосинкразий спеков. **Не** закрывай хвост растущими хардкод-списками маркеров/глаголов (`LIST_VERB_SUFFIXES`, `ACCESSOR_MARKER_SEGS`, версии) — это ровно тот creep «по одному разумному за раз». Правило: **новый маркер/глагол добавляется только под реальный спек, который его упражняет**, никогда «на всякий случай» (так был убран спекулятивный `bycode`). А когда вывод неуверенный — не тупик (`miss-no-list`), а **`item.candidates`**: правдоподобные эндпоинты, ранжированные по структурной близости, БЕЗ выбора значения. Граф — детерминизм zond'а; выбор — суждение агента. Выравнивание двух слоёв, где один уже что-то делает (напр. version-strip, ARV-381), — это консистентность, не новое знание, и ок.
17
+
18
+ ## Top-level layout
19
+
20
+ | Каталог | Назначение |
21
+ |---|---|
22
+ | `cli/` | CLI surface: парсинг argv, регистрация команд, форматирование вывода. |
23
+ | `core/` | Бизнес-логика: probes, checks, generators, runner, reporters. **Никакой зависимости от commander/process.argv** — это переиспользуемое ядро. |
24
+ | `db/` | SQLite-слой: schema, migrations, queries для истории runs/results. |
25
+
26
+ **Правило**: `cli/commands/<cmd>.ts` парсит флаги и зовёт функции из `core/`. Бизнес-логика в `cli/` — code-smell (см. ARV-257 про `bootstrap.ts`/`discover.ts`, которые лежат в `cli/commands/` но не регистрируют команды).
27
+
28
+ ## cli/
29
+
30
+ | Файл | Что |
31
+ |---|---|
32
+ | `index.ts` | Entry point бинаря. |
33
+ | `program.ts` | Commander root: регистрирует все top-level команды. |
34
+ | `argv.ts`, `resolve.ts` | Аргумент-парсинг и `--api` chain resolution (per-command > global > `ZOND_API` > `.zond/current-api`). |
35
+ | `runtime.ts` | Глобальный runtime context (`api`, workspace paths, http auditor). |
36
+ | `output.ts`, `json-envelope.ts`, `json-schemas.ts` | Forматирование результатов: текстовый/JSON envelope + Ajv-валидация envelope-схем. |
37
+ | `status-filter.ts` | Общий парсер `--status` фильтров. |
38
+ | `commands/` | Один файл на команду; `commands/init/`, `commands/api/`, `commands/probe/` — кластеры с subcommands. |
39
+
40
+ Контракт команды: парсит флаги, валидирует через зависимости из `core/`, эмиттит результат через `output.ts` (envelope) или streaming-репортер.
41
+
42
+ ## core/ — подсистемы
43
+
44
+ | Подкаталог | Роль |
45
+ |---|---|
46
+ | `parser/`, `spec/` | Парсинг OpenAPI, dereferenced spec.json, extraction схем. |
47
+ | `generator/` | Синтез тестовых YAML-сьютов из spec: `suite-generator.ts`, `data-factory.ts`, `resources-builder.ts`. |
48
+ | `runner/` | HTTP-исполнение: `executor.ts`, retry, assertions, schema validation. |
49
+ | `checks/` | Schemathesis-style depth checks (status_code_conformance, response_schema_conformance, idempotency, …). Орк — `checks/runner.ts`. Один файл = один check class. |
50
+ | `probe/` | Активные security/mass-assignment probes. Сейчас два монолита (`security-probe.ts`, `mass-assignment-probe.ts`) — кандидаты на split (ARV-295, ARV-296). |
51
+ | `lint/` | Static spec-lint (`check spec`). Не путать с `checks/` — это разные команды и разные envelope'ы. |
52
+ | `diagnostics/` | Triage финдингов: классификация ошибок, hints, `recommended_action` mapping. |
53
+ | `severity/` | Per-finding severity calibration (ARV-283–288 актуализирует). |
54
+ | `anti-fp/` | Anti-false-positive guard'ы; registry-pattern частично (см. ARV-259). |
55
+ | `coverage/` | Покрытие endpoint'ов: test-runs + audit-runs, dual-metric. |
56
+ | `reporter/` | Форматирование `Run`/`Check`/`Probe` результатов в текст/JSON/NDJSON/SARIF/JUnit/HTML. |
57
+ | `exporter/` | HTML-отчёты, case studies. |
58
+ | `audit/` | Высокоуровневая `audit` команда — wraps checks + probe + report для CI-smoke. |
59
+ | `workspace/` | Layout API-папки: `apis/<name>/{spec,catalog,resources,fixtures,env,secrets}`. |
60
+ | `context/`, `identity/`, `secrets/` | Загрузка контекста запуска, identity tokens, секреты. |
61
+ | `util/`, `utils.ts` | Общие хелперы. URL/headers/schema-валидация частично дублируются с `probe/shared.ts` — кандидат на консолидацию (ARV-297). |
62
+ | `selectors/`, `meta/`, `classifier/` | Endpoint-classification и meta-аттрибуты для дискавери и группировки. |
63
+ | `setup-api.ts` | Регистрация нового API в workspace (used by `add api`/`refresh-api`). |
64
+
65
+ ## db/
66
+
67
+ SQLite на bun. `migrations/` — versioned migrations, `schema.ts` — текущий schema, `queries/` — типизированные SQL. Используется reporter'ами и `coverage` для исторических runs. Retention (ARV-266): `zond db stats` — счётчики строк per `run_kind`; `zond db prune` — opt-in удаление (per-kind defaults: check/probe/request/fixture старше 7d, `regular` — forever; `--older-than 30d` для uniform-cutoff), VACUUM после delete.
68
+
69
+ ## Data-flow по фазам
70
+
71
+ zond работает по 5 фазам — это ментальная модель CLI и skills:
72
+
73
+ ```
74
+ Setup ──► Generate ──► Run ──► Analyze ──► Report
75
+ ```
76
+
77
+ | Фаза | Команды | Что происходит | Артефакты |
78
+ |---|---|---|---|
79
+ | **Setup** | `init`, `add api`, `refresh-api`, `use`, `doctor`, `prepare-fixtures` | Регистрируем API, тянем spec, заполняем `.env.yaml`. | `apis/<name>/{spec.json, .api-catalog.yaml, .api-resources.yaml, .api-fixtures.yaml, .env.yaml}` |
80
+ | **Generate** | `generate`, `api annotate`, `prepare-fixtures` | Синтез тестовых YAML из spec + аннотации (seed-bodies, idempotency, pagination, lifecycle). | `apis/<name>/tests/*.yaml`, annotations |
81
+ | **Run** | `run`, `session`, `request`, `audit`, `checks run`, `probe <class>` | Дергаем API: тесты, depth-checks, probes. Пишем runs/results в SQLite. | `runs/` (DB), HTTP-аудит |
82
+ | **Analyze** | `coverage`, `db {runs,run,collections,diagnose,compare}`, `check spec`, `describe`, `catalog` | Триаж результатов, coverage-гэпы, lint спеки. Финдинги через `recommended_action`. | Envelope JSON, finding-streams |
83
+ | **Report** | `report`, `report-bundle`, `--report {json,ndjson,sarif,junit,html,markdown}` | Конвертация runs/findings в shareable форматы. | NDJSON-stream, SARIF, HTML, JUnit |
84
+
85
+ Полная картина с iron-rules и pre-flight checklist'ами — в skill-документах (`src/cli/commands/init/templates/skills/*.md`), которые ставятся через `zond init`.
86
+
87
+ ## Extension points
88
+
89
+ Когда добавляешь новую функциональность — это **типичные точки расширения**:
90
+
91
+ | Хочу добавить | Куда |
92
+ |---|---|
93
+ | Новый depth-check (schemathesis-style) | `core/checks/checks/<name>.ts` + регистрация в `core/checks/runner.ts`. |
94
+ | Новый probe-class (security/mass-assignment-like) | `core/probe/<class>/` подмодуль; subcommand в `cli/commands/probe/`. Не клади всё в один монолит — см. ARV-295/ARV-296. |
95
+ | Новый reporter format | `core/reporter/<format>.ts`; зарегистрировать в `cli/output.ts` или per-command `--report`. |
96
+ | Новый CLI флаг с envelope-выводом | `cli/commands/<cmd>.ts` + Ajv-схема в `cli/json-schemas.ts`. Envelope shape — единый, не плоди вариации. |
97
+ | Анти-FP guard для check/probe | `core/anti-fp/rules/<rule>.ts` (registry-pattern в развитии — ARV-259). |
98
+ | Новая diagnostic-hint | `core/diagnostics/` — closed-enum `recommended_action`, не магические строки. |
99
+ | Новая DB-сущность | `src/db/migrations/<NNNN>-<name>.sql` + tiped query в `db/queries/`. |
100
+
101
+ ## Workspace contract (ссылка)
102
+
103
+ Артефакты в `apis/<name>/` (`spec.json` / `.api-catalog.yaml` / `.api-resources.yaml` / **`.api-fixtures.yaml` manifest** / **`.env.yaml` values**) — описаны в [`../AGENTS.md`](../AGENTS.md). Главное правило: **manifest — source of truth о списке переменных, env — только values**.
104
+
105
+ ## Conventions
106
+
107
+ - TypeScript strict mode, `bun run check` = `tsc --noEmit` без warnings (`noUnusedLocals`/`noUnusedParameters` включены).
108
+ - Тесты — `bun test` (unit + integration), `bun run test:mocked` (HTTP-mocked).
109
+ - Сборка — `bun run build` → single-file `dist/zond` бинарь.
110
+ - Никаких `console.log` в `core/` — выводи через `cli/output.ts` или reporter slot.
111
+ - Никаких SDK Anthropic/Ollama/прочих LLM-провайдеров внутри zond — это dumb-tool (см. `feedback_zond_no_llm_calls`).
112
+ - Финдинги — через closed-enum `recommended_action`, агент триажит по enum, не по тексту message.
@@ -19,11 +19,13 @@ import { printError, printSuccess } from "../output.ts";
19
19
 
20
20
  export interface AddApiOptions {
21
21
  name: string;
22
- spec?: string;
22
+ /** One or more specs. Multiple → deterministic union (ARV-375). */
23
+ specs?: string[];
23
24
  baseUrl?: string;
24
25
  dir?: string;
25
26
  force?: boolean;
26
27
  insecure?: boolean;
28
+ caPath?: string;
27
29
  dbPath?: string;
28
30
  json?: boolean;
29
31
  }
@@ -31,7 +33,7 @@ export interface AddApiOptions {
31
33
  export async function addApiCommand(opts: AddApiOptions): Promise<number> {
32
34
  const ws = findWorkspaceRoot();
33
35
  if (ws.fromFallback) {
34
- const m = `No workspace detected (no zond.config.yml / .zond / zond.db / apis marker). Run \`zond init\` first to bootstrap a workspace.`;
36
+ const m = `No workspace detected (no zond.config.yml / .zond / apis marker). Run \`zond init\` first to bootstrap a workspace.`;
35
37
  if (opts.json) printJson(jsonError("add-api", [m])); else printError(m);
36
38
  return 2;
37
39
  }
@@ -39,16 +41,18 @@ export async function addApiCommand(opts: AddApiOptions): Promise<number> {
39
41
  const envVars: Record<string, string> = {};
40
42
  if (opts.baseUrl) envVars.base_url = opts.baseUrl;
41
43
 
44
+ const hasSpec = (opts.specs?.length ?? 0) > 0;
42
45
  let result: SetupApiResult;
43
46
  try {
44
47
  result = await setupApi({
45
48
  name: opts.name,
46
- spec: opts.spec,
49
+ specs: opts.specs,
47
50
  dir: opts.dir,
48
51
  envVars: Object.keys(envVars).length > 0 ? envVars : undefined,
49
52
  dbPath: opts.dbPath,
50
53
  force: opts.force,
51
54
  insecure: opts.insecure,
55
+ caPath: opts.caPath,
52
56
  });
53
57
  } catch (err) {
54
58
  const m = (err as Error).message;
@@ -63,7 +67,7 @@ export async function addApiCommand(opts: AddApiOptions): Promise<number> {
63
67
  return 2;
64
68
  }
65
69
 
66
- const mode: "spec" | "run-only" = opts.spec ? "spec" : "run-only";
70
+ const mode: "spec" | "run-only" = hasSpec ? "spec" : "run-only";
67
71
  const artifacts = mode === "spec"
68
72
  ? ["spec.json", ".api-catalog.yaml", ".api-resources.yaml", ".api-fixtures.yaml", ".env.yaml"]
69
73
  : [".env.yaml"];
@@ -106,15 +110,22 @@ export function registerAdd(program: Command): void {
106
110
  add
107
111
  .command("api <name>")
108
112
  .description("Register an API: from an OpenAPI spec (full toolkit) or just --base-url (run-only mode)")
109
- .option("--spec <path>", "Path or URL to OpenAPI spec — enables generate/probe/validate-schema")
113
+ .option(
114
+ "--spec <path>",
115
+ "Path or URL to OpenAPI spec — enables generate/probe/validate-schema. Repeat --spec to union multiple specs (e.g. v1 + v2) into one merged audit target (ARV-375).",
116
+ (val: string, acc: string[]) => acc.concat(val),
117
+ [] as string[],
118
+ )
110
119
  .option("--base-url <url>", "Base URL recorded in .env.yaml (required if --spec is omitted)")
111
120
  .option("--dir <path>", "Target directory (defaults to apis/<name>/)")
112
121
  .option("--force", "Overwrite an existing API with the same name")
113
122
  .option("--insecure", "Skip TLS verification when fetching the spec from https")
123
+ .option("--ca <path>", "PEM CA bundle to trust for the spec fetch (adds to public roots; also reads NODE_EXTRA_CA_CERTS) — use instead of --insecure for internal/corp CAs")
114
124
  .option("--db <path>", "Path to SQLite database file")
115
125
  .action(async (name: string, opts, cmd: Command) => {
116
126
  const json = globalJson(cmd);
117
- if (!opts.spec && !opts.baseUrl) {
127
+ const specs: string[] = Array.isArray(opts.spec) ? opts.spec : (opts.spec ? [opts.spec] : []);
128
+ if (specs.length === 0 && !opts.baseUrl) {
118
129
  const m = "Provide --spec <path|url> for a full registration, or --base-url <url> for run-only mode.";
119
130
  if (json) printJson(jsonError("add-api", [m])); else printError(m);
120
131
  process.exitCode = 2;
@@ -122,11 +133,12 @@ export function registerAdd(program: Command): void {
122
133
  }
123
134
  process.exitCode = await addApiCommand({
124
135
  name,
125
- spec: opts.spec,
136
+ specs,
126
137
  baseUrl: opts.baseUrl,
127
138
  dir: opts.dir,
128
139
  force: opts.force === true,
129
140
  insecure: opts.insecure === true,
141
+ caPath: typeof opts.ca === "string" ? opts.ca : undefined,
130
142
  dbPath: typeof opts.db === "string" ? opts.db : undefined,
131
143
  json,
132
144
  });