@kirrosh/zond 0.23.0 → 0.26.0
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 +164 -1
- package/README.md +8 -7
- package/package.json +2 -3
- package/src/CLAUDE.md +112 -0
- package/src/cli/commands/add-api.ts +19 -7
- package/src/cli/commands/api/annotate/index.ts +359 -4
- package/src/cli/commands/api/annotate/lifecycle.ts +1 -1
- package/src/cli/commands/api/annotate/overlay.ts +1 -1
- package/src/cli/commands/api/annotate/pagination.ts +10 -6
- package/src/cli/commands/api/annotate/prompts.ts +39 -2
- package/src/cli/commands/audit.ts +360 -54
- package/src/cli/commands/check.ts +15 -2
- package/src/cli/commands/checks.ts +352 -36
- package/src/cli/commands/cleanup.ts +4 -30
- package/src/cli/commands/coverage.ts +275 -57
- package/src/cli/commands/db.ts +311 -8
- package/src/cli/commands/discover.ts +281 -161
- package/src/cli/commands/doctor.ts +57 -3
- package/src/cli/commands/fixtures.ts +1 -1
- package/src/cli/commands/generate.ts +24 -7
- package/src/cli/commands/init/bootstrap.ts +4 -1
- package/src/cli/commands/init/index.ts +2 -2
- package/src/cli/commands/init/skills.ts +43 -0
- package/src/cli/commands/init/templates/agents.md +12 -3
- package/src/cli/commands/init/templates/skills/warm-up-target.md +122 -0
- package/src/cli/commands/init/templates/skills/zond-checks.md +268 -44
- package/src/cli/commands/init/templates/skills/zond-seed.md +114 -0
- package/src/cli/commands/init/templates/skills/zond-triage.md +88 -26
- package/src/cli/commands/init/templates/skills/zond.md +274 -64
- package/src/cli/commands/init/templates/zond-config.yml +1 -1
- package/src/cli/commands/prepare-fixtures.ts +14 -52
- package/src/cli/commands/probe/_seed-bodies.ts +52 -0
- package/src/cli/commands/probe/mass-assignment.ts +101 -10
- package/src/cli/commands/probe/security.ts +95 -12
- package/src/cli/commands/probe/webhooks.ts +2 -0
- package/src/cli/commands/probe.ts +87 -11
- package/src/cli/commands/refresh-api.ts +59 -1
- package/src/cli/commands/report-bundle.ts +3 -11
- package/src/cli/commands/request.ts +116 -0
- package/src/cli/commands/run.ts +33 -5
- package/src/cli/commands/schema-from-runs.ts +128 -0
- package/src/cli/commands/secrets.ts +133 -0
- package/src/cli/json-envelope.ts +0 -20
- package/src/cli/json-schemas.ts +51 -0
- package/src/cli/output.ts +17 -1
- package/src/cli/program.ts +5 -4
- package/src/cli/safe-live.ts +24 -0
- package/src/cli/status-filter.ts +0 -10
- package/src/core/audit/persist.ts +183 -0
- package/src/core/checks/budget.ts +59 -0
- package/src/core/checks/checks/cross_call_references.ts +17 -4
- package/src/core/checks/checks/cursor_boundary_fuzzing.ts +219 -0
- package/src/core/checks/checks/idempotency_replay.ts +1 -5
- package/src/core/checks/checks/ignored_auth.ts +44 -1
- package/src/core/checks/checks/index.ts +3 -0
- package/src/core/checks/checks/lifecycle_transitions.ts +169 -26
- package/src/core/checks/checks/negative_data_rejection.ts +119 -16
- package/src/core/checks/checks/not_a_server_error.ts +8 -0
- package/src/core/checks/checks/open_cors_on_sensitive.ts +47 -18
- package/src/core/checks/checks/pagination_invariants.ts +298 -117
- package/src/core/checks/checks/positive_data_acceptance.ts +1 -4
- package/src/core/checks/checks/status_code_conformance.ts +78 -7
- package/src/core/checks/mode.ts +3 -0
- package/src/core/checks/recommended-action.ts +5 -1
- package/src/core/checks/runner.ts +614 -27
- package/src/core/checks/spec-findings.ts +308 -0
- package/src/core/checks/types.ts +117 -1
- package/src/core/checks/zond-extensions.ts +73 -0
- package/src/core/classifier/recommended-action.ts +35 -6
- package/src/core/coverage/loader.ts +31 -0
- package/src/core/diagnostics/db-analysis.ts +200 -106
- package/src/core/diagnostics/failure-class.ts +21 -1
- package/src/core/diagnostics/failure-hints.ts +4 -208
- package/src/core/diagnostics/suggested-fixes.ts +2 -3
- package/src/core/generator/chunker.ts +1 -8
- package/src/core/generator/data-factory.ts +199 -61
- package/src/core/generator/fixtures-builder.ts +38 -31
- package/src/core/generator/index.ts +0 -2
- package/src/core/generator/openapi-reader.ts +98 -4
- package/src/core/generator/path-param-disambig.ts +30 -4
- package/src/core/generator/resources-builder.ts +276 -26
- package/src/core/generator/schema-utils.ts +22 -0
- package/src/core/generator/suite-generator.ts +168 -15
- package/src/core/generator/types.ts +6 -0
- package/src/core/identity/identity-file.ts +0 -0
- package/src/core/output/README.md +11 -29
- package/src/core/output/index.ts +1 -1
- package/src/core/output/run.ts +0 -35
- package/src/core/output/types.ts +0 -7
- package/src/core/parser/dynamic-values.ts +160 -0
- package/src/core/parser/variables.ts +0 -0
- package/src/core/probe/dry-run-envelope.ts +4 -0
- package/src/core/probe/mass-assignment/classify.ts +175 -0
- package/src/core/probe/mass-assignment/cleanup.ts +52 -0
- package/src/core/probe/mass-assignment/digest.ts +114 -0
- package/src/core/probe/mass-assignment/orchestrator.ts +459 -0
- package/src/core/probe/mass-assignment/regression.ts +141 -0
- package/src/core/probe/mass-assignment/suspects.ts +92 -0
- package/src/core/probe/mass-assignment/types.ts +135 -0
- package/src/core/probe/mass-assignment-probe.ts +23 -1118
- package/src/core/probe/mass-assignment-template.ts +32 -4
- package/src/core/probe/path-discovery.ts +3 -4
- package/src/core/probe/probe-harness.ts +21 -22
- package/src/core/probe/security/baseline.ts +174 -0
- package/src/core/probe/security/classify.ts +341 -0
- package/src/core/probe/security/cleanup.ts +125 -0
- package/src/core/probe/security/detectors.ts +71 -0
- package/src/core/probe/security/digest.ts +104 -0
- package/src/core/probe/security/orchestrator.ts +398 -0
- package/src/core/probe/security/regression.ts +103 -0
- package/src/core/probe/security/types.ts +151 -0
- package/src/core/probe/security-probe-class.ts +8 -2
- package/src/core/probe/security-probe.ts +28 -1449
- package/src/core/probe/shared.ts +26 -0
- package/src/core/probe/webhooks-probe.ts +5 -7
- package/src/core/runner/assertions.ts +1 -1
- package/src/core/runner/executor.ts +3 -18
- package/src/core/runner/form-encode.ts +8 -18
- package/src/core/runner/http-client.ts +38 -1
- package/src/core/runner/preflight-vars.ts +19 -15
- package/src/core/runner/rate-limiter.ts +11 -29
- package/src/core/runner/run-kind.ts +7 -1
- package/src/core/runner/schema-validator.ts +2 -6
- package/src/core/runner/send-request.ts +11 -6
- package/src/core/runner/types.ts +6 -0
- package/src/core/setup-api.ts +53 -15
- package/src/core/severity/index.ts +0 -63
- package/src/core/spec/infer-schema.ts +102 -0
- package/src/core/spec/merge-specs.ts +156 -0
- package/src/core/spec/schema-from-runs.ts +117 -0
- package/src/core/spec/schema-overlay.ts +130 -0
- package/src/core/util/ajv.ts +13 -0
- package/src/core/util/headers.ts +9 -0
- package/src/core/util/url.ts +24 -0
- package/src/core/workspace/fixture-gap-report.ts +84 -0
- package/src/core/workspace/fixture-gaps.ts +71 -0
- package/src/core/workspace/root.ts +13 -11
- package/src/db/migrate.ts +2 -0
- package/src/db/migrations/0002_run_kind_request.sql +59 -0
- package/src/db/queries/collections.ts +2 -2
- package/src/db/queries/results.ts +88 -0
- package/src/db/queries/runs.ts +56 -2
- package/src/db/queries.ts +3 -0
- package/src/db/schema.ts +7 -7
- package/src/cli/commands/bootstrap.ts +0 -710
- package/src/core/anti-fp/bootstrap.ts +0 -34
- package/src/core/anti-fp/index.ts +0 -33
- package/src/core/anti-fp/registry.ts +0 -44
- package/src/core/anti-fp/rules/baseline-echo.ts +0 -74
- package/src/core/anti-fp/rules/schemathesis/body_negation_becomes_valid.ts +0 -52
- package/src/core/anti-fp/rules/schemathesis/coverage_phase_boundary_positive.ts +0 -38
- package/src/core/anti-fp/rules/schemathesis/has_unverifiable_mutations.ts +0 -35
- package/src/core/anti-fp/rules/schemathesis/index.ts +0 -24
- package/src/core/anti-fp/rules/schemathesis/string_type_mutation_becomes_valid.ts +0 -53
- package/src/core/anti-fp/rules/subscription-gated/index.ts +0 -11
- package/src/core/anti-fp/rules/subscription-gated/paid-plan-403.ts +0 -75
- package/src/core/anti-fp/types.ts +0 -68
- package/src/core/generator/create-body.ts +0 -89
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,170 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## [0.26.0] — 2026-07-09
|
|
8
|
+
|
|
9
|
+
Deterministic gap-fills surfaced by a docgen-core-service audit — all pass the
|
|
10
|
+
litmus test (same input → same output, no severity/FP/blame judgment). Plus an
|
|
11
|
+
m-25 distribution cleanup that collapses the workspace layout to one convention.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **Multi-spec merge (ARV-375):** `zond add api <name> --spec a --spec b …`
|
|
15
|
+
unions N specs into one audit target. Deterministic last-wins on path /
|
|
16
|
+
component collisions, surfaced as warnings (path collisions + same-name /
|
|
17
|
+
different-shape schema collisions). Core in `src/core/spec/merge-specs.ts`.
|
|
18
|
+
- **`zond secrets set <key> <value>` (ARV-377):** writes `apis/<name>/.secrets.yaml`
|
|
19
|
+
with a `.bak` backup, never echoes the value, and auto-strips a pasted
|
|
20
|
+
`Bearer ` prefix (`--literal` keeps it verbatim). Closes the "hand-rolled
|
|
21
|
+
python to rotate an expired token" gap and ARV-367/AC3.
|
|
22
|
+
- **`zond db diagnose --union <spec>` (ARV-380):** aggregate
|
|
23
|
+
`by_recommended_action` (+ summary counts, deduped examples) across a run
|
|
24
|
+
set, reusing coverage's `--union` vocabulary (`session` / `since:<dur>` /
|
|
25
|
+
`tag:<name>` / `runs:<ids>`). `--api` scopes `since:`/`tag:` to a collection.
|
|
26
|
+
- **Coverage deprecated flags (ARV-379):** `coverage --json` now carries a
|
|
27
|
+
per-entry `deprecated` boolean on the `*Endpoints` bucket arrays plus a
|
|
28
|
+
top-level `deprecatedEndpoints` list, so a consumer can split "real gap"
|
|
29
|
+
from "deprecated, skip by design" without re-reading spec.json.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- **`db diagnose --union` version follow-up + candidate-surfacing (ARV-381/382):**
|
|
33
|
+
disambig's parent-walk now skips version segments (`/v30/{code}`), aligning
|
|
34
|
+
with `owningCollectionForPathParam` which already strips them — resolves the
|
|
35
|
+
`_v30_code` miss-no-list class. And when prepare-fixtures can't confidently
|
|
36
|
+
derive an owner list, the item carries `candidates[]` — plausible GET/list
|
|
37
|
+
endpoints ranked by proximity (deprecated ones marked) — instead of
|
|
38
|
+
dead-ending; zond surfaces the evidence, the agent picks the value. On
|
|
39
|
+
docgen-core-merged: `miss-no-list` 40 → 22 total, 9 of those now carry
|
|
40
|
+
candidates, the rest are honest dead-ends (no listable source in the spec).
|
|
41
|
+
- **Resource graph misses `/list`-style owners (ARV-376):** `resolveOwnerListPaths`
|
|
42
|
+
now links `/list` (and `/search`, `/find`) endpoints to their sibling
|
|
43
|
+
`/{code}` and `/byid/{id}` params; the `byid` accessor marker no longer
|
|
44
|
+
collapses every read-by-id param into one global `byid_id`; a malformed spec
|
|
45
|
+
whose path template (`/byid/{id}`) disagrees with the declared param name
|
|
46
|
+
(`byid_id`) is reconciled to the template; secondary lookup keys (`{code}`)
|
|
47
|
+
surface as candidates. On the docgen-core-merged spec this cut
|
|
48
|
+
prepare-fixtures `miss-no-list` from 40 → 30.
|
|
49
|
+
- **`fixtures add` batch (ARV-378):** confirmed `fixtures add <pairs...>`
|
|
50
|
+
already applies N `key=value` pairs in one call (one write + one `.bak`) —
|
|
51
|
+
no shell loop needed.
|
|
52
|
+
|
|
53
|
+
### Removed
|
|
54
|
+
- **Flat `zond.db` workspace layout (m-25):** dropped the legacy root-level
|
|
55
|
+
`zond.db` marker and its implicit default-DB resolution. The DB now lives
|
|
56
|
+
only at `.zond/zond.db`; `zond.config.yml` / `.zond/` / `apis/` remain the
|
|
57
|
+
workspace markers. Migrate an old workspace with `mv zond.db .zond/` (or
|
|
58
|
+
re-`zond init`); an explicit `--db <path>` still opens any file. Removes the
|
|
59
|
+
dual-layout confusion that let a root `zond.db` and `.zond/zond.db` coexist.
|
|
60
|
+
- **Dead `benchmarks/` references (m-25):** pruned the never-committed
|
|
61
|
+
`benchmarks/**` entries from `knip.json` and the dead `bench:api` script from
|
|
62
|
+
`package.json` (`knip` is now clean).
|
|
63
|
+
|
|
64
|
+
## [0.25.0] — 2026-07-07
|
|
65
|
+
|
|
66
|
+
m-24: **rebuild around the agent.** zond becomes a set of deterministic
|
|
67
|
+
dumb tools — it sends requests, validates schemas, stores and diffs runs,
|
|
68
|
+
and reports gaps. The autonomous heuristic layer that produced most of the
|
|
69
|
+
0.24 bug-stream (auto-discovery/seed/cascade, annotate-auto guess-engine,
|
|
70
|
+
severity calibrators, anti-FP suppression) is removed; the agent now owns
|
|
71
|
+
every judgment call (severity, spec-vs-backend blame, "is this a false
|
|
72
|
+
positive?", which value fills a fixture). The deterministic core —
|
|
73
|
+
send → validate → store → diff — survives intact. A litmus test in
|
|
74
|
+
`src/CLAUDE.md` keeps the heuristic layer from creeping back one
|
|
75
|
+
"reasonable" fix at a time: same input → same output, or it's the agent's.
|
|
76
|
+
|
|
77
|
+
### Removed (heuristic layer)
|
|
78
|
+
- **Autonomous fixture seed/cascade engine gone (ARV-336):** `bootstrap.ts`
|
|
79
|
+
+ `create-body.ts` deleted. Live-POST resource creation guessed bodies and
|
|
80
|
+
cascaded parent→child (1% success on Stripe). prepare-fixtures is now
|
|
81
|
+
single-pass verify + gap-report; the agent (or user) creates resources.
|
|
82
|
+
- **Severity calibrators + anti-FP suppression gate removed (ARV-337 Cut A):**
|
|
83
|
+
severity is agent judgment; anti-FP `applyAntiFp` no longer gates emission —
|
|
84
|
+
the rule reasons survive as raw evidence, not as a suppress-or-emit verdict.
|
|
85
|
+
- **annotate-auto guess-engine removed (ARV-337 Cut B):** `inferSeedBody`
|
|
86
|
+
fabricated bodies from format/name fallbacks and self-ranked confidence.
|
|
87
|
+
annotate now dumps the spec slice; the agent authors the YAML, zond
|
|
88
|
+
validates and merges.
|
|
89
|
+
|
|
90
|
+
### Agent-facing artifacts & new mechanics
|
|
91
|
+
- **YAML run summary (ARV-338):** `zond db diagnose` drops prose hints (keeps
|
|
92
|
+
the mechanical counts/grouping spine); `db … --report yaml` emits
|
|
93
|
+
agent-friendly output.
|
|
94
|
+
- **Field-level run diff (ARV-339):** `zond db compare` now diffs response
|
|
95
|
+
body/schema per field, not just status.
|
|
96
|
+
- **prepare-fixtures gap report (ARV-349/350):** undefined vars + unseeded
|
|
97
|
+
capture-chain roots are reported deterministically — no auto-seed.
|
|
98
|
+
- **Agent-orchestrated auto-seed (ARV-355):** `zond request --capture` +
|
|
99
|
+
`zond-seed` skill — the agent reasons about creation order, zond executes.
|
|
100
|
+
- **Ambiguous-id guard (ARV-334):** the hint-less fixture harvest reports
|
|
101
|
+
`miss-ambiguous-id` (naming the candidate string field) instead of silently
|
|
102
|
+
putting a numeric `id` into a string slot like `{owner}` — zond flags the
|
|
103
|
+
ambiguity, the agent/annotation picks the field.
|
|
104
|
+
- **generate preserves hand-edits (ARV-361):** suite files whose auto-gen
|
|
105
|
+
header was removed are treated as agent-owned and preserved on regenerate;
|
|
106
|
+
`--force` overwrites them (was a documented no-op).
|
|
107
|
+
|
|
108
|
+
### Checks, probes & safety
|
|
109
|
+
- **`--safe`/`--live` parity (ARV-299)** across `checks run` and `probe`.
|
|
110
|
+
- **stateful scope (ARV-325):** `--check stateful` expands to the
|
|
111
|
+
state-machine set only.
|
|
112
|
+
- **cascade fast-fail (ARV-326):** prepare-fixtures aborts early on a
|
|
113
|
+
dead/scoped-wrong token instead of grinding through futile attempts.
|
|
114
|
+
- **input-triggered 5xx caught (ARV-340/341):** self-generated body rejects
|
|
115
|
+
route to `fix_spec`, not `report_backend_bug`.
|
|
116
|
+
- **child-exclude wired (ARV-330):** the last-attempt history lookup uses the
|
|
117
|
+
all-run-kinds query + child-exclude pattern so probe sub-resource POSTs
|
|
118
|
+
(`/v1/accounts/{id}/reject`) don't starve the real create-path window.
|
|
119
|
+
- **checks reporting fixes (ARV-322/323/328):** suppressed-count accuracy,
|
|
120
|
+
SIGTERM ndjson counting, throttled stderr progress on long runs.
|
|
121
|
+
|
|
122
|
+
### Sweeps & infrastructure
|
|
123
|
+
- **Bounded/resumable sweeps (ARV-342):** `--skip-ops` / `--max-ops` op-window.
|
|
124
|
+
- **DB retention (ARV-266):** `zond db prune` + `zond db stats`, per-run-kind
|
|
125
|
+
cutoffs, VACUUM after delete.
|
|
126
|
+
- **Schema from observed runs (ARV-175/176):** `schema-from-runs` command +
|
|
127
|
+
`refresh-api --merge-schema` — union/required-intersection from real
|
|
128
|
+
responses, not guessing.
|
|
129
|
+
|
|
130
|
+
### Report, triage & audit-run cleanup
|
|
131
|
+
- Report-noise, severity and UX cleanup (ARV-343/344/345/346/348/351/353);
|
|
132
|
+
compare scope tag, partial summary on SIGTERM, triage depth aggregate
|
|
133
|
+
(ARV-352/354).
|
|
134
|
+
- Empty-dir `zond run --output` writes a `0 tests` envelope instead of no
|
|
135
|
+
file (ARV-357); cross-phase double-emit documented for triage (ARV-358).
|
|
136
|
+
- Workspace-leak fix (env-independent audit paths) + self-compare guard
|
|
137
|
+
(ARV-359/360), from a petstore audit-run.
|
|
138
|
+
|
|
139
|
+
## [0.24.0] — 2026-07-03
|
|
140
|
+
|
|
141
|
+
m-22 validation sprint. No new milestone surface — this release hardens the
|
|
142
|
+
0.23.0 depth-checks/probe/audit stack against real APIs. ~40 fixes (ARV-260..332)
|
|
143
|
+
were found by running `zond audit`/`zond-scan` live against Stripe, GitHub,
|
|
144
|
+
Resend and docgen-core, not by unit tests.
|
|
145
|
+
|
|
146
|
+
### Safety & contracts
|
|
147
|
+
- **Safe-mode leak closed (ARV-332):** `checks run --check stateful --include
|
|
148
|
+
method:GET` no longer fires POST create-chains — CRUD groups are built from
|
|
149
|
+
the filtered op set, so `ensure_resource_availability`/`use_after_free`
|
|
150
|
+
self-skip when no write is in scope. Critical for scanning APIs you don't own.
|
|
151
|
+
- Exit-code contract hardened (ARV-303/307/308/309/310): audit judges stages on
|
|
152
|
+
`envelope.ok`, not raw exit code; budget-exhaust distinguished from network error.
|
|
153
|
+
- `open_cors_on_sensitive` HIGH only on 2xx + ambient (cookie) credential
|
|
154
|
+
(ARV-312/316) — kills a class of false HIGHs.
|
|
155
|
+
|
|
156
|
+
### Severity calibration
|
|
157
|
+
- Probe-side severity calibrator (ARV-283/300): `SecuritySeverity ↔ Severity`
|
|
158
|
+
adapter with sentinel passthrough; wired into security probe. mass-assignment/
|
|
159
|
+
static/webhooks tracked in ARV-311.
|
|
160
|
+
|
|
161
|
+
### Fixture / seed pipeline
|
|
162
|
+
- FK-aware body builder wires reference fields to fixtures (ARV-45).
|
|
163
|
+
- Topological seed order + body-FK deferral (ARV-324/327); gap-report flags
|
|
164
|
+
unfillable complex root resources instead of silently skipping (ARV-329/330).
|
|
165
|
+
|
|
166
|
+
### Ops & workflow
|
|
167
|
+
- `ZOND_WORKSPACE` honored; `zond-audit` workflow added for reproducible runs.
|
|
168
|
+
- ndjson reporter stability (ARV-314/318/320/322); path-casing canonicalized
|
|
169
|
+
before workspace-root walk (ARV-315).
|
|
170
|
+
- Repo-wide ponytail cleanup: dead code removed, probe monoliths deduped.
|
|
8
171
|
|
|
9
172
|
## [0.23.0] — 2026-05-15
|
|
10
173
|
|
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
|
|
24
|
+
zond prepare-fixtures --api my-api # gap report: verify fixtures + which FK vars need a value
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
50
|
-
|
|
51
|
-
|
|
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.
|
|
3
|
+
"version": "0.26.0",
|
|
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
|
-
|
|
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 /
|
|
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
|
-
|
|
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" =
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|