@kirrosh/zond 0.22.0 → 0.23.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 +648 -0
- package/README.md +58 -6
- package/package.json +9 -6
- package/src/cli/argv.ts +122 -0
- package/src/cli/commands/add-api.ts +134 -0
- package/src/cli/commands/api/annotate/idempotency.ts +59 -0
- package/src/cli/commands/api/annotate/index.ts +525 -0
- package/src/cli/commands/api/annotate/lifecycle.ts +74 -0
- package/src/cli/commands/api/annotate/overlay.ts +206 -0
- package/src/cli/commands/api/annotate/pagination.ts +60 -0
- package/src/cli/commands/api/annotate/prompts.ts +183 -0
- package/src/cli/commands/api/annotate/readback.ts +58 -0
- package/src/cli/commands/api/annotate/resources.ts +91 -0
- package/src/cli/commands/api/annotate/seed-bodies.ts +61 -0
- package/src/cli/commands/audit.ts +480 -0
- package/src/cli/commands/bootstrap.ts +710 -0
- package/src/cli/commands/catalog.ts +35 -0
- package/src/cli/commands/check.ts +348 -0
- package/src/cli/commands/checks.ts +756 -0
- package/src/cli/commands/ci-init.ts +43 -0
- package/src/cli/commands/clean.ts +212 -0
- package/src/cli/commands/cleanup.ts +262 -0
- package/src/cli/commands/completions.ts +16 -0
- package/src/cli/commands/coverage.ts +605 -132
- package/src/cli/commands/db.ts +178 -7
- package/src/cli/commands/describe.ts +37 -2
- package/src/cli/commands/discover.ts +1236 -0
- package/src/cli/commands/doctor.ts +607 -0
- package/src/cli/commands/fixtures.ts +402 -0
- package/src/cli/commands/generate.ts +420 -46
- package/src/cli/commands/init/bootstrap.ts +30 -1
- package/src/cli/commands/{init.ts → init/index.ts} +99 -5
- package/src/cli/commands/init/skills.ts +56 -3
- package/src/cli/commands/init/templates/agents.md +65 -61
- package/src/cli/commands/init/templates/skills/zond-checks.md +397 -0
- package/src/cli/commands/init/templates/skills/zond-triage.md +210 -0
- package/src/cli/commands/init/templates/skills/zond.md +592 -125
- package/src/cli/commands/init/templates/zond-config.yml +8 -9
- package/src/cli/commands/prepare-fixtures.ts +135 -0
- package/src/cli/commands/probe/mass-assignment.ts +503 -0
- package/src/cli/commands/probe/security.ts +454 -0
- package/src/cli/commands/probe/static.ts +255 -0
- package/src/cli/commands/probe/webhooks.ts +161 -0
- package/src/cli/commands/probe.ts +459 -0
- package/src/cli/commands/reference.ts +87 -0
- package/src/cli/commands/refresh-api.ts +169 -0
- package/src/cli/commands/remove-api.ts +150 -0
- package/src/cli/commands/report-bundle.ts +318 -0
- package/src/cli/commands/report.ts +241 -0
- package/src/cli/commands/request.ts +379 -4
- package/src/cli/commands/run.ts +842 -53
- package/src/cli/commands/session.ts +244 -0
- package/src/cli/commands/use.ts +18 -1
- package/src/cli/index.ts +20 -3
- package/src/cli/json-envelope.ts +112 -3
- package/src/cli/json-schemas.ts +263 -0
- package/src/cli/program.ts +198 -635
- package/src/cli/resolve.ts +105 -0
- package/src/cli/status-filter.ts +124 -0
- package/src/cli/util/api-context.ts +85 -0
- package/src/cli/version.ts +5 -0
- package/src/core/anti-fp/bootstrap.ts +34 -0
- package/src/core/anti-fp/index.ts +33 -0
- package/src/core/anti-fp/registry.ts +44 -0
- package/src/core/anti-fp/rules/baseline-echo.ts +74 -0
- package/src/core/anti-fp/rules/schemathesis/body_negation_becomes_valid.ts +52 -0
- package/src/core/anti-fp/rules/schemathesis/coverage_phase_boundary_positive.ts +38 -0
- package/src/core/anti-fp/rules/schemathesis/has_unverifiable_mutations.ts +35 -0
- package/src/core/anti-fp/rules/schemathesis/index.ts +24 -0
- package/src/core/anti-fp/rules/schemathesis/string_type_mutation_becomes_valid.ts +53 -0
- package/src/core/anti-fp/rules/subscription-gated/index.ts +11 -0
- package/src/core/anti-fp/rules/subscription-gated/paid-plan-403.ts +75 -0
- package/src/core/anti-fp/types.ts +68 -0
- package/src/core/checks/checks/_crud-helpers.ts +133 -0
- package/src/core/checks/checks/_negative_mutator.ts +133 -0
- package/src/core/checks/checks/_readback-helpers.ts +133 -0
- package/src/core/checks/checks/content_type_conformance.ts +39 -0
- package/src/core/checks/checks/cross_call_references.ts +134 -0
- package/src/core/checks/checks/ensure_resource_availability.ts +62 -0
- package/src/core/checks/checks/idempotency_replay.ts +246 -0
- package/src/core/checks/checks/ignored_auth.ts +211 -0
- package/src/core/checks/checks/index.ts +65 -0
- package/src/core/checks/checks/lifecycle_transitions.ts +273 -0
- package/src/core/checks/checks/missing_required_header.ts +40 -0
- package/src/core/checks/checks/negative_data_rejection.ts +45 -0
- package/src/core/checks/checks/not_a_server_error.ts +27 -0
- package/src/core/checks/checks/open_cors_on_sensitive.ts +131 -0
- package/src/core/checks/checks/pagination_invariants.ts +238 -0
- package/src/core/checks/checks/positive_data_acceptance.ts +36 -0
- package/src/core/checks/checks/rate_limit_headers_absent.ts +77 -0
- package/src/core/checks/checks/response_headers_conformance.ts +74 -0
- package/src/core/checks/checks/response_schema_conformance.ts +30 -0
- package/src/core/checks/checks/status_code_conformance.ts +61 -0
- package/src/core/checks/checks/unsupported_method.ts +63 -0
- package/src/core/checks/checks/use_after_free.ts +78 -0
- package/src/core/checks/index.ts +30 -0
- package/src/core/checks/mode.ts +79 -0
- package/src/core/checks/recommended-action.ts +64 -0
- package/src/core/checks/registry.ts +78 -0
- package/src/core/checks/runner.ts +874 -0
- package/src/core/checks/sarif.ts +230 -0
- package/src/core/checks/stateful.ts +121 -0
- package/src/core/checks/types.ts +189 -0
- package/src/core/classifier/recommended-action.ts +222 -0
- package/src/core/context/current.ts +22 -6
- package/src/core/context/session.ts +78 -0
- package/src/core/coverage/loader.ts +185 -0
- package/src/core/coverage/reasons.ts +300 -0
- package/src/core/diagnostics/db-analysis.ts +151 -11
- package/src/core/diagnostics/failure-class.ts +120 -0
- package/src/core/diagnostics/failure-hints.ts +212 -9
- package/src/core/diagnostics/spec-pointer.ts +99 -0
- package/src/core/diagnostics/suggested-fixes.ts +156 -0
- package/src/core/exporter/case-study/index.ts +270 -0
- package/src/core/exporter/curl.ts +40 -0
- package/src/core/exporter/exporter.ts +48 -0
- package/src/core/exporter/html-report/escape.ts +24 -0
- package/src/core/exporter/html-report/index.ts +479 -0
- package/src/core/exporter/html-report/script.ts +100 -0
- package/src/core/exporter/html-report/styles.ts +408 -0
- package/src/core/generator/chunker.ts +42 -16
- package/src/core/generator/coverage-phase.ts +0 -0
- package/src/core/generator/create-body.ts +89 -0
- package/src/core/generator/data-factory.ts +445 -19
- package/src/core/generator/describe.ts +1 -1
- package/src/core/generator/fixtures-builder.ts +325 -0
- package/src/core/generator/index.ts +7 -5
- package/src/core/generator/openapi-reader.ts +37 -3
- package/src/core/generator/path-param-disambig.ts +114 -0
- package/src/core/generator/resources-builder.ts +648 -0
- package/src/core/generator/schema-utils.ts +11 -3
- package/src/core/generator/serializer.ts +103 -13
- package/src/core/generator/suite-generator.ts +419 -111
- package/src/core/generator/types.ts +8 -0
- package/src/core/identity/identity-file.ts +129 -0
- package/src/core/lint/affects.ts +28 -0
- package/src/core/lint/config.ts +96 -0
- package/src/core/lint/format.ts +42 -0
- package/src/core/lint/index.ts +94 -0
- package/src/core/lint/reporter.ts +128 -0
- package/src/core/lint/rules/consistency.ts +158 -0
- package/src/core/lint/rules/heuristics.ts +97 -0
- package/src/core/lint/rules/strictness.ts +109 -0
- package/src/core/lint/types.ts +96 -0
- package/src/core/lint/walker.ts +248 -0
- package/src/core/meta/meta-store.ts +6 -73
- package/src/core/output/README.md +91 -0
- package/src/core/output/index.ts +13 -0
- package/src/core/output/run.ts +126 -0
- package/src/core/output/types.ts +129 -0
- package/src/core/parser/env-interpolation.ts +104 -0
- package/src/core/parser/filter.ts +57 -0
- package/src/core/parser/schema.ts +129 -4
- package/src/core/parser/types.ts +19 -1
- package/src/core/parser/variables.ts +0 -0
- package/src/core/parser/yaml-parser.ts +58 -12
- package/src/core/probe/bootstrap.ts +34 -0
- package/src/core/probe/dry-run-envelope.ts +57 -0
- package/src/core/probe/mass-assignment-probe-class.ts +198 -0
- package/src/core/probe/mass-assignment-probe.ts +1122 -0
- package/src/core/probe/mass-assignment-template.ts +212 -0
- package/src/core/probe/method-probe.ts +43 -76
- package/src/core/probe/method-shared.ts +69 -0
- package/src/core/probe/negative-probe.ts +183 -149
- package/src/core/probe/orphan-tracker.ts +188 -0
- package/src/core/probe/path-discovery.ts +440 -0
- package/src/core/probe/probe-harness.ts +120 -0
- package/src/core/probe/registry.ts +89 -0
- package/src/core/probe/runner.ts +136 -0
- package/src/core/probe/security-probe-class.ts +201 -0
- package/src/core/probe/security-probe.ts +1453 -0
- package/src/core/probe/shared.ts +505 -0
- package/src/core/probe/static-probe-class.ts +125 -0
- package/src/core/probe/types.ts +165 -0
- package/src/core/probe/verdict-aggregator.ts +33 -0
- package/src/core/probe/webhooks-probe.ts +284 -0
- package/src/core/reporter/console.ts +41 -2
- package/src/core/reporter/index.ts +2 -3
- package/src/core/reporter/json.ts +11 -1
- package/src/core/reporter/junit.ts +27 -12
- package/src/core/reporter/ndjson.ts +37 -0
- package/src/core/reporter/types.ts +3 -0
- package/src/core/runner/assertions.ts +58 -1
- package/src/core/runner/async-pool.ts +108 -0
- package/src/core/runner/auth-path.ts +8 -0
- package/src/core/runner/ci-context.ts +72 -0
- package/src/core/runner/executor.ts +264 -20
- package/src/core/runner/form-encode.ts +51 -0
- package/src/core/runner/http-client.ts +75 -2
- package/src/core/runner/learn-drift.ts +293 -0
- package/src/core/runner/preflight-vars.ts +149 -0
- package/src/core/runner/progress-tracker.ts +73 -0
- package/src/core/runner/rate-limiter.ts +89 -17
- package/src/core/runner/run-kind.ts +39 -0
- package/src/core/runner/schema-validator.ts +312 -0
- package/src/core/runner/send-request.ts +153 -20
- package/src/core/runner/types.ts +38 -0
- package/src/core/secrets/registry.ts +164 -0
- package/src/core/secrets/secrets-file.ts +115 -0
- package/src/core/selectors/operation-filter.ts +144 -0
- package/src/core/setup-api.ts +415 -16
- package/src/core/severity/category.ts +94 -0
- package/src/core/severity/index.ts +121 -0
- package/src/core/spec/layers.ts +154 -0
- package/src/core/util/format-eta.ts +21 -0
- package/src/core/utils.ts +5 -1
- package/src/core/workspace/config.ts +129 -0
- package/src/core/workspace/manifest.ts +283 -0
- package/src/core/workspace/output-rotation.ts +62 -0
- package/src/core/workspace/triage-path.ts +87 -0
- package/src/db/lint-runs.ts +47 -0
- package/src/db/migrate.ts +126 -0
- package/src/db/migrations/0001_run_kind.sql +25 -0
- package/src/db/migrations/sql.d.ts +4 -0
- package/src/db/queries/collections.ts +133 -0
- package/src/db/queries/coverage.ts +9 -0
- package/src/db/queries/dashboard.ts +59 -0
- package/src/db/queries/results.ts +128 -0
- package/src/db/queries/runs.ts +235 -0
- package/src/db/queries/sessions.ts +42 -0
- package/src/db/queries/settings.ts +28 -0
- package/src/db/queries/types.ts +172 -0
- package/src/db/queries.ts +72 -802
- package/src/db/schema.ts +178 -50
- package/src/cli/commands/export.ts +0 -144
- package/src/cli/commands/guide.ts +0 -127
- package/src/cli/commands/init/templates/skills/scenarios.md +0 -97
- package/src/cli/commands/probe-methods.ts +0 -108
- package/src/cli/commands/probe-validation.ts +0 -124
- package/src/cli/commands/serve.ts +0 -114
- package/src/cli/commands/sync.ts +0 -268
- package/src/cli/commands/update.ts +0 -189
- package/src/cli/commands/validate.ts +0 -34
- package/src/core/diagnostics/render-md.ts +0 -112
- package/src/core/exporter/postman.ts +0 -963
- package/src/core/generator/guide-builder.ts +0 -253
- package/src/core/meta/types.ts +0 -19
- package/src/core/parser/index.ts +0 -21
- package/src/core/runner/execute-run.ts +0 -132
- package/src/core/runner/index.ts +0 -12
- package/src/core/sync/spec-differ.ts +0 -38
- package/src/web/data/collection-state.ts +0 -362
- package/src/web/routes/api.ts +0 -314
- package/src/web/routes/dashboard.ts +0 -350
- package/src/web/routes/runs.ts +0 -64
- package/src/web/schemas.ts +0 -121
- package/src/web/server.ts +0 -134
- package/src/web/static/htmx.min.cjs +0 -1
- package/src/web/static/style.css +0 -1148
- package/src/web/views/endpoints-tab.ts +0 -174
- package/src/web/views/explorer-tab.ts +0 -402
- package/src/web/views/health-strip.ts +0 -92
- package/src/web/views/layout.ts +0 -48
- package/src/web/views/results.ts +0 -210
- package/src/web/views/runs-tab.ts +0 -126
- package/src/web/views/suites-tab.ts +0 -181
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,654 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
(Empty — next development cycle.)
|
|
8
|
+
|
|
9
|
+
## [0.23.0] — 2026-05-15
|
|
10
|
+
|
|
11
|
+
Big release covering m-15 → m-21 (155 ARV tickets across depth-checks,
|
|
12
|
+
schemathesis-comparison, m-20 stateful probes, agent-augmented annotation,
|
|
13
|
+
deep-testing-and-tuning). The detailed per-task list survives below
|
|
14
|
+
under the legacy TASK-* headings (m-13 carry-over); this section is the
|
|
15
|
+
release-summary for the m-15..m-21 epic series.
|
|
16
|
+
|
|
17
|
+
### Highlights — m-15 to m-21
|
|
18
|
+
|
|
19
|
+
#### `zond checks` — schemathesis-style depth checks (m-15, ARV-1..12)
|
|
20
|
+
|
|
21
|
+
- **17 registered checks** across two registries: per-response
|
|
22
|
+
(`status_code_conformance`, `content_type_conformance`,
|
|
23
|
+
`response_headers_conformance`, `response_schema_conformance`,
|
|
24
|
+
`missing_required_header`, `unsupported_method`, `negative_data_rejection`,
|
|
25
|
+
`positive_data_acceptance`, `not_a_server_error`,
|
|
26
|
+
`rate_limit_headers_absent`) and stateful (`ignored_auth`,
|
|
27
|
+
`use_after_free`, `ensure_resource_availability`, `cross_call_references`,
|
|
28
|
+
`idempotency_replay`, `pagination_invariants`, `lifecycle_transitions`,
|
|
29
|
+
`open_cors_on_sensitive`).
|
|
30
|
+
- **Anti-FP infrastructure** (`core/anti-fp/`) with per-rule registry,
|
|
31
|
+
6 documented schemathesis-FP fixture-pack regressions
|
|
32
|
+
(`tests/regression/schemathesis-fps/`), and per-finding `recommended_action`
|
|
33
|
+
enum (`fix_test_data` / `fix_test_logic` / `report_to_api_owner` / …).
|
|
34
|
+
- **Coverage phase** (`--phase coverage`) for deterministic boundary-value
|
|
35
|
+
enumeration over body + param schemas; complements `--phase examples`.
|
|
36
|
+
- **SARIF v2.1.0 reporter** with stable `partialFingerprints` for GitHub
|
|
37
|
+
Code Scanning integration.
|
|
38
|
+
- **NDJSON streaming reporter** (`--report ndjson`) with published
|
|
39
|
+
JSON Schema (`docs/json-schema/ndjsonEvent.schema.json`).
|
|
40
|
+
- **`--workers` async-pool** for op-level concurrency, gated by an
|
|
41
|
+
optional `--rate-limit auto` adaptive limiter (RFC 9568 RateLimit-* headers).
|
|
42
|
+
- **`--include` / `--exclude` selectors** unified across `generate`, `run`,
|
|
43
|
+
`checks` (path/method/tag/operation-id grammar).
|
|
44
|
+
|
|
45
|
+
#### m-18 — schemathesis parity baselines (ARV-174..186)
|
|
46
|
+
|
|
47
|
+
- Stripe / Resend / Sentry parity baselines (3 baseline-fixed bugs:
|
|
48
|
+
ARV-179 unsupported_method exhaustive enumeration, ARV-180
|
|
49
|
+
status_code_conformance param-axis coverage, ARV-181 ignored_auth
|
|
50
|
+
pathVars + strict-401, ARV-183 phantom-findings fix, ARV-184
|
|
51
|
+
missing_required_header exhaustive). Documented schemathesis-V4
|
|
52
|
+
comparison matrix.
|
|
53
|
+
|
|
54
|
+
#### m-20 — stateful probes (ARV-169..173, 187, 191)
|
|
55
|
+
|
|
56
|
+
- **`cross_call_references`** (ARV-169) — POST→GET shape-diff probe.
|
|
57
|
+
Surfaces `state_not_persisted` (HIGH) when the server echoes a field on
|
|
58
|
+
create but drops it on read.
|
|
59
|
+
- **`idempotency_replay`** (ARV-170) — `Idempotency-Key` honor probe.
|
|
60
|
+
Two POSTs with the same key must return the same id and bit-identical
|
|
61
|
+
response (`duplicate_resource` / `non_bit_identical`).
|
|
62
|
+
- **`pagination_invariants`** (ARV-171) — cursor-style page consistency.
|
|
63
|
+
Detects off-by-one duplicates across pages, partial-page-with-has_more,
|
|
64
|
+
and inconsistent has_more.
|
|
65
|
+
- **`lifecycle_transitions`** (ARV-172) — declared state machine
|
|
66
|
+
verification with action-replay idempotency probe.
|
|
67
|
+
- **`probe webhooks`** (ARV-173) — webhook shape-conformance against
|
|
68
|
+
`spec.webhooks` event log; recipe in `docs/recipes/webhook-receiver.md`.
|
|
69
|
+
- **`zond api annotate`** (ARV-187) — agent-augmented annotation flow:
|
|
70
|
+
`dump` slices spec for the agent, `apply` merges its YAML answers into
|
|
71
|
+
`.api-resources.local.yaml` (no LLM inside zond — see
|
|
72
|
+
`feedback_zond_no_llm_calls` memory).
|
|
73
|
+
- **Form-encoded stateful checks** (ARV-191) — stateful probes honor
|
|
74
|
+
`requestBodyContentType` so Stripe-style APIs aren't broken-baseline.
|
|
75
|
+
- **`.api-resources.local.yaml` `patches:` block** (ARV-169) — field-level
|
|
76
|
+
overlay survives `refresh-api`; replaces the deprecated re-declaration
|
|
77
|
+
pattern.
|
|
78
|
+
|
|
79
|
+
#### m-21 — deep-testing-and-tuning (ARV-188..256)
|
|
80
|
+
|
|
81
|
+
- **Severity rebalance** (ARV-250..256) under "no-OOB" constraint —
|
|
82
|
+
small-team API hygiene scanner positioning. SSRF / CORS / rate-limit
|
|
83
|
+
/ missing-auth probes recalibrated; `report categorization` into
|
|
84
|
+
security / reliability / contract / hygiene buckets (ARV-251).
|
|
85
|
+
- **Spec-lint cap at LOW/INFO** (ARV-255) — dedicated `zond lint` command
|
|
86
|
+
separates static spec hygiene from runtime probes.
|
|
87
|
+
- **Mock-API testbed** (ARV-193) — `apis/_mock/` with 4 intentional bugs
|
|
88
|
+
per m-20 stateful probe; `tests/regression/mock-testbed.test.ts` is the
|
|
89
|
+
regression-floor for probe-quality.
|
|
90
|
+
- **`zond fixtures add` / `import --from-curl`** (ARV-195) — manual
|
|
91
|
+
fixture-bootstrap for path-FK ids that auto-discover/--seed can't reach
|
|
92
|
+
(vendor-dashboard ids).
|
|
93
|
+
- **Stripe form-encoding fix** (ARV-196) — bootstrap seed POST honors
|
|
94
|
+
`application/x-www-form-urlencoded` with bracket nesting
|
|
95
|
+
(`card[number]`, `items[0][price]`).
|
|
96
|
+
|
|
97
|
+
### Performance & operability
|
|
98
|
+
|
|
99
|
+
- **`--max-requests` cap** for `zond checks run` (ARV-227) — shared
|
|
100
|
+
budget for per-response + stateful phases bounds long runs against
|
|
101
|
+
large specs (github / kubernetes).
|
|
102
|
+
- **Schema-validation safety net** (ARV-214) — oversized response schemas
|
|
103
|
+
in `--validate-schema` skip with a stderr warning instead of hanging
|
|
104
|
+
for 15+ min on AJV.compile. Configurable via
|
|
105
|
+
`ZOND_VALIDATE_SCHEMA_MAX_BYTES` (default 1 MiB) and
|
|
106
|
+
`ZOND_VALIDATE_SCHEMA_SLOW_COMPILE_MS` (default 1000ms).
|
|
107
|
+
- **Rate-limiter adaptive mode** (ARV-8 follow-ups) — paces from
|
|
108
|
+
`RateLimit-*` response headers (RFC 9568) so multi-worker runs respect
|
|
109
|
+
vendor budgets globally.
|
|
110
|
+
|
|
111
|
+
### Skills & workflow
|
|
112
|
+
|
|
113
|
+
- Skills consolidated 5 → 3 (`zond`, `zond-checks`, `zond-triage`) with
|
|
114
|
+
`zond init --prune-stale-skills` (ARV-197) for upgrades.
|
|
115
|
+
- Skill `update-on-feature-change` ritual formalized; per-feature CLI
|
|
116
|
+
changes gate on skill update (`feedback_update_skills_per_feature`
|
|
117
|
+
memory).
|
|
118
|
+
- Iron rules in `skills/zond.md`: `--dry-run` for destructive ops,
|
|
119
|
+
`--redact-identity` for triage artefacts, mandatory
|
|
120
|
+
`zond doctor --missing-only` first step.
|
|
121
|
+
|
|
122
|
+
### Fixed (selected)
|
|
123
|
+
|
|
124
|
+
- ARV-145: `zond add api` no longer crashes on cyclic OpenAPI specs
|
|
125
|
+
(Stripe). `decycleSchema` writes `x-circular` sentinel; downstream
|
|
126
|
+
parsers skip cleanly.
|
|
127
|
+
- ARV-200: extractEndpoints filters `x-circular` param stubs (R10/F1
|
|
128
|
+
feedback-loop crash).
|
|
129
|
+
- ARV-209: `--validate-schema` auto-resolves spec from
|
|
130
|
+
`apis/<name>/tests/` path (R12/F11 — manual `--spec` no longer
|
|
131
|
+
required for skill-driven runs).
|
|
132
|
+
- ARV-244: `cleanup --orphans` percent-encodes unsafe characters in
|
|
133
|
+
`deletePath`.
|
|
134
|
+
- ARV-238: `clean --api <name>` resolves global `--api` fallback.
|
|
135
|
+
- 50+ feedback-loop bug fixes from R01..R18 against Resend / Sentry /
|
|
136
|
+
Stripe / GitHub baselines (search `git log --grep "R[0-9]\+/F"` for the full list).
|
|
137
|
+
|
|
138
|
+
### Workspace contract
|
|
139
|
+
|
|
140
|
+
- **Manifest vs values** (m-17, decision-7) — `.api-fixtures.yaml` is
|
|
141
|
+
the manifest of required vars; `.env.yaml` carries values. The split
|
|
142
|
+
is enforced by `prepare-fixtures` ("not in manifest, ignored" warning)
|
|
143
|
+
and documented in `skills/zond.md`.
|
|
144
|
+
- **`.api-resources.local.yaml`** (ARV-111) — survives
|
|
145
|
+
`add-api`/`refresh-api`. Use `extensions:` for full resource entries,
|
|
146
|
+
`patches:` for field-level overlays (readback_diff, idempotency,
|
|
147
|
+
pagination, lifecycle, seed_body).
|
|
148
|
+
- **Single API-resolution chain** (TASK-290) — `--api` flag → `ZOND_API`
|
|
149
|
+
env → `.zond/current-api` (set by `zond use <name>`).
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
The legacy m-13 TASK-* changelog continues below; entries originally in
|
|
154
|
+
`[Unreleased]` are now part of 0.23.0.
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
|
|
158
|
+
- **TASK-301: workspace defaults for `--timeout` and `--rate-limit` in `zond.config.yml`.**
|
|
159
|
+
New `defaults.timeout_ms` and `defaults.rate_limit` (alias `timeoutMs`,
|
|
160
|
+
`rateLimit`, `rate_limit: auto`) feed `cleanup`, `prepare-fixtures`,
|
|
161
|
+
`probe mass-assignment`, `probe security`, `request`, and `run`.
|
|
162
|
+
Resolution chain: **CLI flag → `apis/<name>/.env.yaml` meta → workspace
|
|
163
|
+
defaults → built-in fallback** (30000 ms / undefined rate limit).
|
|
164
|
+
`.env.yaml` already supported `rateLimit:`; now also supports
|
|
165
|
+
`timeoutMs:`. The init template's `zond-config.yml` documents the
|
|
166
|
+
`defaults` block. New helpers: `loadWorkspaceDefaults`,
|
|
167
|
+
`resolveTimeoutMs`, `resolveRateLimit` in `core/workspace/config.ts`.
|
|
168
|
+
|
|
169
|
+
### Changed (breaking)
|
|
170
|
+
|
|
171
|
+
- **TASK-300: `zond probe validation` and `zond probe methods` are merged into `zond probe static`.**
|
|
172
|
+
Both classes are static-input checks (no HTTP) and now share one entry
|
|
173
|
+
point: `zond probe static --output <dir>` runs both by default. Filter
|
|
174
|
+
via `--include validation,methods` (or `--exclude`). The old subcommands
|
|
175
|
+
are removed without a deprecation alias — same model as TASK-298
|
|
176
|
+
(`validate` + `lint-spec` → `check`). `zond audit` now spawns a single
|
|
177
|
+
`probe static` stage (output dir `apis/<name>/probes/static/`) in place
|
|
178
|
+
of the two former stages.
|
|
179
|
+
|
|
180
|
+
- **TASK-299: `zond discover` and `zond bootstrap` are merged into `zond prepare-fixtures`.**
|
|
181
|
+
Single-pass discover is now `zond prepare-fixtures --api <name>` (the
|
|
182
|
+
former `zond discover` flow). Multi-pass cascade is `--cascade`, with
|
|
183
|
+
`--seed` / `--force` / `--max-passes` (the former `zond bootstrap`).
|
|
184
|
+
`--seed` implies `--cascade`. The old top-level commands are removed
|
|
185
|
+
without deprecation. `zond audit --seed` now spawns
|
|
186
|
+
`prepare-fixtures --apply --seed` instead of `bootstrap`.
|
|
187
|
+
|
|
188
|
+
- **TASK-298: `zond validate` and `zond lint-spec` are merged into `zond check`.**
|
|
189
|
+
Use `zond check tests <path>` for the YAML-test schema validator and
|
|
190
|
+
`zond check spec [spec]` for the OpenAPI static analyser. The old
|
|
191
|
+
top-level commands are removed (no deprecation alias). Flag surface is
|
|
192
|
+
unchanged. Single mental model — both surfaces are conformance checks
|
|
193
|
+
on workspace inputs, neither makes HTTP calls.
|
|
194
|
+
|
|
195
|
+
### Removed (breaking)
|
|
196
|
+
|
|
197
|
+
- **TASK-284: `zond serve` and the WebUI are removed.** Agent-first / CLI-only
|
|
198
|
+
surface per vector-3. Use `zond report export` for shareable HTML reports.
|
|
199
|
+
`src/ui/` is gone along with hono / react / tanstack / tailwind dependencies.
|
|
200
|
+
- **TASK-285: `zond update` (and `self-update` alias) is removed.** Use the
|
|
201
|
+
system package manager: re-run `install.sh`, or `npm install -g @kirrosh/zond@latest`,
|
|
202
|
+
or `bun install -g @kirrosh/zond@latest`. README has the upgrade section.
|
|
203
|
+
- **TASK-286: `zond export postman` is removed (decision-4 reversed).** The
|
|
204
|
+
parallel YAML→Postman exporter (`src/cli/commands/export.ts` +
|
|
205
|
+
`src/core/exporter/postman.ts`, ~963 LOC) had no measured demand;
|
|
206
|
+
OpenAPI-driven tooling already covers the round-trip use case.
|
|
207
|
+
- **TASK-287: `zond report case-study` standalone subcommand is removed.**
|
|
208
|
+
The case-study markdown drafts are still produced by `zond report bundle`
|
|
209
|
+
(default `--include case-study`); the per-failure CLI surface and its flags
|
|
210
|
+
collapse into the bundle path. `renderCaseStudy` core renderer is unchanged.
|
|
211
|
+
|
|
212
|
+
### Removed (breaking)
|
|
213
|
+
|
|
214
|
+
- **TASK-288: deprecated top-level `probe-*` aliases removed.** The
|
|
215
|
+
one-release deprecation window for `probe-validation`, `probe-methods`,
|
|
216
|
+
`probe-mass-assignment`, `probe-security` (TASK-182) is closed. Use
|
|
217
|
+
`zond probe <class>` instead. `warnDeprecatedProbe` helper removed.
|
|
218
|
+
|
|
219
|
+
### Changed (breaking)
|
|
220
|
+
|
|
221
|
+
- **TASK-296: `--json` envelope `errors[]` is now structured.** Every
|
|
222
|
+
error is `{ code: ZondErrorCode, message: string, details?: object }`
|
|
223
|
+
instead of a flat string. `code` is a closed enum
|
|
224
|
+
(`unknown_error`, `env_missing`, `fixture_missing`, `network_timeout`,
|
|
225
|
+
`network_error`, `sandbox_blocked`, `spec_load_failure`,
|
|
226
|
+
`yaml_parse_error`, `workspace_not_found`, `file_not_found`,
|
|
227
|
+
`permission_denied`, `argument_invalid`, `api_not_registered`,
|
|
228
|
+
`db_error`, `auth_config_error`) so an agent can route on `code`
|
|
229
|
+
without parsing the human message. Agents that previously did
|
|
230
|
+
`errors[0]` now read `errors[0].message`. Sites not yet classified
|
|
231
|
+
emit `code: "unknown_error"` (still structured, still routable).
|
|
232
|
+
|
|
233
|
+
### Added
|
|
234
|
+
|
|
235
|
+
- **TASK-294: `recommended_action` field on every Issue / SecurityFinding /
|
|
236
|
+
mass-assignment / discover finding.** Closes the agent-routing gap
|
|
237
|
+
for findings outside `db diagnose`. New enum values: `fix_spec`,
|
|
238
|
+
`fix_fixture`. See `skills/zond.md` for the full table.
|
|
239
|
+
|
|
240
|
+
- **TASK-292: 5 iron rules in `skills/zond.md`.** Promotes from
|
|
241
|
+
audit-and-consolidation §6: NEVER destructive ops on shared/prod org
|
|
242
|
+
without `--dry-run`; NEVER report cleanup-failure as API bug; NEVER
|
|
243
|
+
share triage artefacts without `--redact-identity`; MUST timeout
|
|
244
|
+
bootstrap cascade (default 8 passes); MUST run
|
|
245
|
+
`zond doctor --api <name> --missing-only` first. Each has a one-line
|
|
246
|
+
rationale embedded next to the rule.
|
|
247
|
+
|
|
248
|
+
- **TASK-290: global `--api` flag + `ZOND_API` env + `.zond/current-api` file.**
|
|
249
|
+
`zond` now resolves the active API from a single chain (highest wins):
|
|
250
|
+
per-command `--api` > root `--api` > `ZOND_API` env > `.zond/current-api`
|
|
251
|
+
(set by `zond use <name>`; was `.zond-current` at workspace root).
|
|
252
|
+
The root `--api` value is mirrored into `ZOND_API_GLOBAL` by a preAction
|
|
253
|
+
hook so deeply-nested code can read it without a `cmd` reference.
|
|
254
|
+
|
|
255
|
+
### Deprecated
|
|
256
|
+
|
|
257
|
+
- **TASK-289: `zond run --no-real-parents` → `--use-synthetic-parents`.**
|
|
258
|
+
Double-negative renamed to a positive flag. The old name still works
|
|
259
|
+
one release with a stderr warning, then drops.
|
|
260
|
+
- **TASK-291: `zond lint-spec --filter-rule` is a deprecated alias for
|
|
261
|
+
the whitelist subset of `--rule`.** The two flags are unified: `--rule`
|
|
262
|
+
now accepts `B1` (whitelist), `!B2` (disable), `B3=high|low|off` (override).
|
|
263
|
+
`--filter-rule` still works one release with a stderr warning.
|
|
264
|
+
|
|
265
|
+
### Added
|
|
266
|
+
|
|
267
|
+
- **TASK-29: `zond db diagnose --json` now surfaces `suggested_fixes`.**
|
|
268
|
+
Two actionable signals on top of the existing `agent_directive` /
|
|
269
|
+
`recommended_action` / `env_issue` envelope:
|
|
270
|
+
(1) **placeholder path-params on 404s** — when a 404 hits a URL still
|
|
271
|
+
containing literal `example`, all-zero UUIDs, `your-…-here`,
|
|
272
|
+
`replace-me`, or sentinel hex tails (`…dead/beef/cafe`), the segment
|
|
273
|
+
is flagged with a fix message pointing at `zond discover --apply` or
|
|
274
|
+
the matching fixture in `.env.yaml`. Deduplicated across failures so
|
|
275
|
+
one broken segment doesn't repeat N times.
|
|
276
|
+
(2) **unfilled `.env.yaml` keys** — reads the API's `.env.yaml` and
|
|
277
|
+
flags values that are empty, `<TODO>` / `<…>`, `example`,
|
|
278
|
+
`your-…-here`, or `replace-me`. The agent gets a concrete list of
|
|
279
|
+
keys to fill before re-running, instead of guessing from a 404 burst.
|
|
280
|
+
|
|
281
|
+
- **TASK-36: tagless endpoints fall back to per-resource grouping.**
|
|
282
|
+
`groupEndpointsByTag` previously piled every untagged endpoint into a
|
|
283
|
+
single `untagged` bucket — Resend's `/audiences` POST/GET/DELETE all
|
|
284
|
+
ended up in one fat `smoke-untagged.yaml` instead of a focused
|
|
285
|
+
`audiences-smoke` / `crud-audiences` pair. Untagged endpoints now key
|
|
286
|
+
by their first non-templated path segment (`/audiences/{id}` →
|
|
287
|
+
`audiences`, `/{tenant}/jobs/{id}` → `jobs`), so tagless specs
|
|
288
|
+
produce the same per-resource suite layout as tagged ones. Path of
|
|
289
|
+
`/` keeps the legacy `untagged` key.
|
|
290
|
+
|
|
291
|
+
- **TASK-116: `zond run --all` + CI context autodetection.** `--all`
|
|
292
|
+
discovers every `apis/<name>/tests/` directory in the workspace and
|
|
293
|
+
merges them into a single `runs.id` — one run row per CI invocation,
|
|
294
|
+
even with multiple registered APIs (without it, each `zond run` lands
|
|
295
|
+
on its own row, so cross-build comparison is impossible). On every
|
|
296
|
+
`zond run` the CLI now also stamps the run row with CI context
|
|
297
|
+
auto-detected from env vars (GitHub Actions, GitLab CI, CircleCI,
|
|
298
|
+
Buildkite, Jenkins, or generic `CI=true`): `trigger=ci`, `commit_sha`,
|
|
299
|
+
`branch`. Manual runs still default to `trigger=manual` with no
|
|
300
|
+
commit/branch. `ZOND_TRIGGER` / `ZOND_COMMIT_SHA` / `ZOND_BRANCH`
|
|
301
|
+
override autodetection for wrappers that strip the native vars.
|
|
302
|
+
`RunFilters` gained `trigger`, so `listRuns({ trigger: "ci" })` /
|
|
303
|
+
`zond db runs --trigger ci` (UI/CLI filter) limits the dashboard to
|
|
304
|
+
CI rows.
|
|
305
|
+
|
|
306
|
+
- **TASK-142: `zond request --validate-schema` and `--validate-against "METHOD:/path"`.**
|
|
307
|
+
One-off ad-hoc requests can now check the response body against the
|
|
308
|
+
OpenAPI response schema without wrapping the call in YAML. Auto-resolves
|
|
309
|
+
the endpoint from request method + URL.path (templated paths like
|
|
310
|
+
`/users/{id}` matched via the same regex used by `run --validate-schema`).
|
|
311
|
+
Selects the response branch from the actual status code (200 → 200 schema,
|
|
312
|
+
404 → 404 schema, anything else → `default`). Output adds a
|
|
313
|
+
`Schema validation: PASS / FAIL` block with the matched endpoint,
|
|
314
|
+
response branch, and human-readable schema errors (`schema.required`,
|
|
315
|
+
`schema.type`, etc.). FAIL → exit 1; `no-endpoint`/`no-spec`/`no-schema`
|
|
316
|
+
→ soft no-op with a one-line hint. `--validate-against` overrides the
|
|
317
|
+
auto-resolver when the URL doesn't fit the spec template (e.g.
|
|
318
|
+
parameterized resources fetched by slug). Requires `--api <name>` —
|
|
319
|
+
the spec is loaded from the registered collection.
|
|
320
|
+
|
|
321
|
+
- **TASK-143: `zond report bundle <range>` — batch triage exporter.**
|
|
322
|
+
One command instead of `4 runs × 2 formats = 8 calls`. Range forms:
|
|
323
|
+
`A..B` (inclusive numeric range), `A,B,C` (comma list), or
|
|
324
|
+
`--session <id>` (resolve all runs from a CLI session via `runs.session_id`).
|
|
325
|
+
For each run writes `<dir>/<run-id>/case-study.md` (only when failures
|
|
326
|
+
exist), `<dir>/<run-id>/report.html` (single-file HTML), and
|
|
327
|
+
`<dir>/<run-id>/diagnose.json`. A top-level `index.md` lists run-id /
|
|
328
|
+
spec / totals / artefact links / agent_directive snippet from
|
|
329
|
+
`diagnose`. `--include` filters the artefact set (subset of
|
|
330
|
+
`case-study`, `export`, `diagnose`); `--body-cap`/`--no-body-cap`
|
|
331
|
+
forwards to both case-study and HTML renderers. Default output dir
|
|
332
|
+
is `triage/bundle/<timestamp>/` when `--output` is omitted.
|
|
333
|
+
|
|
334
|
+
- **TASK-146: `probe mass-assignment --emit-template "METHOD:/path"`.**
|
|
335
|
+
Generates a ready-to-edit YAML probe template for one endpoint, so the
|
|
336
|
+
user doesn't have to copy-paste the boilerplate from the skill (Phase
|
|
337
|
+
5.1) when the auto-prober marked a verdict INCONCLUSIVE / INCONCLUSIVE-5XX.
|
|
338
|
+
For POST endpoints with discoverable item path (GET-by-id / DELETE
|
|
339
|
+
counterpart) the emitter produces a full `create → verify → cleanup`
|
|
340
|
+
chain with `always: true` cleanup. Privileged-field injection is the
|
|
341
|
+
union of (a) classic mass-assignment vectors (`is_admin`, `role`,
|
|
342
|
+
`owner_id`, …) and (b) `readOnly: true` / `x-zond-protected` properties
|
|
343
|
+
lifted from the request body schema. Output to stdout by default, or
|
|
344
|
+
`--output <file>` to write a YAML file directly. Note: the body
|
|
345
|
+
serializer was tightened so `not_equals: true` (boolean) no longer
|
|
346
|
+
silently emits as `not_equals: "true"` (string) — assertions against
|
|
347
|
+
real boolean fields now compare correctly.
|
|
348
|
+
|
|
349
|
+
- **TASK-153: `probe security` fuzzy-echo classifier for CRLF.** The echo
|
|
350
|
+
detector previously used verbatim substring match, which missed real
|
|
351
|
+
stored-CRLF bugs when the backend stripped `\r`, URL-decoded `%0d%0a`
|
|
352
|
+
before saving, or truncated the field at the first newline (only the
|
|
353
|
+
tail landed in storage). The classifier now branches by class: SSRF and
|
|
354
|
+
open-redirect stay verbatim (URL preserved as-is), CRLF additionally
|
|
355
|
+
tries URL-decoded pairs, CR/LF normalization variants, and tail-only
|
|
356
|
+
match after a newline. The match kind (`verbatim` / `url-decoded` /
|
|
357
|
+
`CRLF→LF` / `CR stripped` / `tail after CRLF` / …) is recorded in
|
|
358
|
+
`finding.reason` for investigation. Bodies are walked as a tree of
|
|
359
|
+
string leaves so CR/LF chars aren't hidden behind JSON escape
|
|
360
|
+
sequences in the haystack.
|
|
361
|
+
|
|
362
|
+
- **TASK-145: `zond doctor --missing-only` + `--query` + canonical `--json` shape.**
|
|
363
|
+
The `--json` envelope is now documented as the canonical contract — all
|
|
364
|
+
diagnostic data lives under `.data` (no `.diagnostics` wrapper). `--help`
|
|
365
|
+
spells out every dot-path (`.data.fixtures.required[]`,
|
|
366
|
+
`.data.staleArtifacts[]`, …) so agents stop guessing. **`--missing-only`**
|
|
367
|
+
hides rows already healthy in both text and JSON: required fixtures with
|
|
368
|
+
values, fresh artifacts, optional fixtures, and `extraInEnv` are dropped.
|
|
369
|
+
**`--query <dotpath>`** resolves a subtree of the report and emits it as
|
|
370
|
+
raw JSON to stdout (no envelope), so pipelines no longer need `jq` for
|
|
371
|
+
the common cases (`zond doctor --query fixtures.required`,
|
|
372
|
+
`--query staleArtifacts`). Unknown paths fail with exit 2 and a list of
|
|
373
|
+
the canonical entry points.
|
|
374
|
+
- **TASK-140: `zond db run --status` now accepts ranges & classes.**
|
|
375
|
+
In addition to the existing exact-code form (`--status 502`), the flag
|
|
376
|
+
parses class wildcards (`5xx`, `4xx`, …), inclusive ranges
|
|
377
|
+
(`500-599`), open-ended comparisons (`>=500`, `<400`, `>500`, `<=400`),
|
|
378
|
+
and any comma-separated mix of those (`5xx,429`, `500,502,504`).
|
|
379
|
+
Triage of large failure runs (e.g. 2000+-step Sentry hunts) no longer
|
|
380
|
+
needs `jq` over `--json`. Invalid syntax produces a one-line error;
|
|
381
|
+
the parser is unit-tested in `tests/cli/status-filter.test.ts`.
|
|
382
|
+
- **TASK-144: `zond run --retry-on-network <N>`.** Auto-retry on transient
|
|
383
|
+
TCP/transport errors (`ECONNRESET`, `EPIPE`, `socket hang up`,
|
|
384
|
+
`fetch failed`, abort/timeout without HTTP response) with exponential
|
|
385
|
+
backoff + full jitter (base 250 ms, cap 8 s). Default `1`, set `0` to
|
|
386
|
+
disable. **HTTP status codes (incl. 5xx) are NOT retried by this path**
|
|
387
|
+
— 5xx is a real server response, not a flaky socket; rate-limited 429
|
|
388
|
+
retries continue to flow through the rate-limiter. Retried steps surface
|
|
389
|
+
`network_retry: <count>` in `--report json` and the `--json` envelope so
|
|
390
|
+
flaky-network shells stay visible during triage.
|
|
391
|
+
- **TASK-186: unified `Exporter` interface + sanitizer pipeline.**
|
|
392
|
+
`src/core/exporter/exporter.ts` now defines `Exporter<I, O>` plus a
|
|
393
|
+
`runExporter()` pipeline; `applySanitizer()` is the one place
|
|
394
|
+
sanitization happens. `generateJsonReport` and `generateJunitXml` are
|
|
395
|
+
pure renderers that hand off to `runExporter`. The cli sites that
|
|
396
|
+
used to call `redact()` directly (HTML report, case-study draft,
|
|
397
|
+
probe-mass-assignment digest, probe-security digest) now call
|
|
398
|
+
`applySanitizer()`, signalling the single sanitization seam. New
|
|
399
|
+
exporters get sanitization for free; `redact()` is no longer imported
|
|
400
|
+
from cli/exporter code.
|
|
401
|
+
- **TASK-184: typed `--json` envelope helpers (closes TASK-73 / TASK-74).**
|
|
402
|
+
`src/cli/json-envelope.ts` now exports a discriminated-union
|
|
403
|
+
`EnvelopeResult<T>` plus two new entry points: `writeEnvelope(cmd, result)`
|
|
404
|
+
(writes the envelope and returns the exit code) and `withEnvelope(cmd, produce)`
|
|
405
|
+
(wraps an async producer, renders thrown errors as `ok: false`).
|
|
406
|
+
Existing `jsonOk` / `jsonError` / `printJson` keep working — the new
|
|
407
|
+
helpers are an opt-in convenience layer for new commands. Test suite
|
|
408
|
+
pins the success/error/meta/warnings shape end-to-end.
|
|
409
|
+
|
|
410
|
+
### Changed
|
|
411
|
+
|
|
412
|
+
- **TASK-187: split `src/db/queries.ts` by domain.** The 750-line module
|
|
413
|
+
is now split across `src/db/queries/{types,runs,sessions,results,collections,dashboard,settings,coverage}.ts`.
|
|
414
|
+
`src/db/queries.ts` survives as a façade that re-exports everything,
|
|
415
|
+
so all 27 callers stay unchanged for one release; the façade will be
|
|
416
|
+
deleted in the next minor (callers should migrate to the per-domain
|
|
417
|
+
paths). `coverage.ts` and `settings.ts` are reserved placeholders for
|
|
418
|
+
future features and ignored by knip.
|
|
419
|
+
- **TASK-185: extract shared probe scaffolding into `core/probe/runner.ts`.**
|
|
420
|
+
The four probe cli commands (`validation`, `methods`, `mass-assignment`,
|
|
421
|
+
`security`) used to each repeat: `readOpenApiSpec` → `extractEndpoints`
|
|
422
|
+
→ tag-filter / list-tags → mkdir output → write each suite with
|
|
423
|
+
`autoGenHeader` → record in manifest. That scaffolding now lives in
|
|
424
|
+
two helpers, `loadSpecForProbe` and `writeProbeSuites`, so each cli
|
|
425
|
+
command shrinks to ~100 lines and the suite-emit path is identical
|
|
426
|
+
across them. Live HTTP orchestration in `mass-assignment-probe.ts` /
|
|
427
|
+
`security-probe.ts` is untouched.
|
|
428
|
+
- **TASK-183: merge `init.ts` and `init/`.** The `init` command had two
|
|
429
|
+
files that looked like entry points: `src/cli/commands/init.ts`
|
|
430
|
+
(handler) and `src/cli/commands/init/` (helpers). Moved the handler
|
|
431
|
+
into `src/cli/commands/init/index.ts` so the directory is the
|
|
432
|
+
command's only home; behaviour unchanged.
|
|
433
|
+
- **TASK-181: sync `install.ps1` ↔ `install.sh`.** PowerShell installer
|
|
434
|
+
now detects ARM64 alongside x64 (was hard-coded to `win-x64`), wraps
|
|
435
|
+
the release-tag fetch in try/catch with a useful error message, and
|
|
436
|
+
matches the .sh installer's tone. The two scripts diverged in late
|
|
437
|
+
April when `install.sh` gained codesign/xattr / fallback-to-local
|
|
438
|
+
logic; this brings them in line for the cross-platform behaviour
|
|
439
|
+
that's actually shared (detection + download + verify).
|
|
440
|
+
- **TASK-179: knip cleanup.** Deleted three unused barrel modules
|
|
441
|
+
(`src/core/diagnostics/render-md.ts`, `src/core/parser/index.ts`,
|
|
442
|
+
`src/core/runner/index.ts`), trimmed the `tailwindcss` direct
|
|
443
|
+
dependency (provided transitively by `bun-plugin-tailwind`), and
|
|
444
|
+
stripped 25+ unused `export` keywords across `src/core` and `src/db`
|
|
445
|
+
so symbols become module-private. The historical `executeRun` runner
|
|
446
|
+
in `src/core/runner/execute-run.ts` (superseded by `run.ts`) was
|
|
447
|
+
dropped; only `AUTH_PATH_RE` survives. `knip.json` now treats
|
|
448
|
+
`tests/`, `scripts/`, and `benchmarks/` as entries and silences
|
|
449
|
+
noise on commander `*Options` types and shadcn `*Variants`.
|
|
450
|
+
- **TASK-178: build artefacts out of repo root.** `bun run build` now
|
|
451
|
+
emits the compiled binary to `dist/zond` (was `./zond`); the
|
|
452
|
+
codesign-darwin script's default arg follows. The default SQLite path
|
|
453
|
+
is now `<workspace>/.zond/zond.db` (next to `.zond/manifest.json`)
|
|
454
|
+
rather than `<workspace>/zond.db`. Legacy `<workspace>/zond.db` is
|
|
455
|
+
still honoured if present, so existing workspaces keep working without
|
|
456
|
+
a migration step.
|
|
457
|
+
|
|
458
|
+
### Removed
|
|
459
|
+
|
|
460
|
+
- **TASK-180: collapse `docs/INDEX.md` and `docs/project-backlog.md`.**
|
|
461
|
+
Both duplicated content already in README + ZOND.md + AGENTS.md.
|
|
462
|
+
Removed; AGENTS.md and README.md updated to point straight at
|
|
463
|
+
`backlog/` and `backlog/decisions/`.
|
|
464
|
+
- **TASK-177: remove `.mcp.example.json`.** Leftover from the
|
|
465
|
+
pre-decision-2 MCP integration. MCP support was dropped entirely; the
|
|
466
|
+
example config no longer documents anything.
|
|
467
|
+
- **TASK-176: drop `CLAUDE.md`.** The file was a 13-line wrapper that
|
|
468
|
+
pointed Claude Code at `AGENTS.md`. Modern Claude Code reads
|
|
469
|
+
`AGENTS.md` directly, so the redirect is unnecessary. AGENTS.md
|
|
470
|
+
remains the single source of truth for AI agents.
|
|
471
|
+
|
|
472
|
+
### Changed
|
|
473
|
+
|
|
474
|
+
- **TASK-151 round-5 follow-up: eventual-consistency retry on POST
|
|
475
|
+
cleanup.** SaaS APIs that route `POST` to a write replica and read
|
|
476
|
+
paths through a follower (Sentry observed this round-5) returned
|
|
477
|
+
404 to immediate `DELETE` cleanup, even though the resource existed
|
|
478
|
+
~10s later. `tryCleanup` now retries 404 with two short backoffs
|
|
479
|
+
(default 200ms / 1s, configurable via `cleanupRetryDelaysMs`). A
|
|
480
|
+
404 that survives retries is flagged
|
|
481
|
+
`persisted across retries — likely real leak`. 5xx, network
|
|
482
|
+
errors, 401/403 fail fast (not transient).
|
|
483
|
+
- **Skill: documented CI exit codes.** Phase 5.2 now states that
|
|
484
|
+
`zond probe-security` exits non-zero on either `HIGH > 0` or
|
|
485
|
+
`cleanup.error > 0`, and that `grep -q "Cleanup failures"
|
|
486
|
+
digest.md` is a reliable signal for the latter.
|
|
487
|
+
|
|
488
|
+
- **TASK-151 round-4 follow-up: per-field restore + cleanup-failure
|
|
489
|
+
surfacing.** The first cut of snapshot+restore sent the full GET
|
|
490
|
+
body back as a single PUT, which `422`'d on partial-PUT APIs (Sentry,
|
|
491
|
+
Stripe) — the round-3 user re-ran the probe and found `org.name`,
|
|
492
|
+
`project.name`, `project.subjectPrefix` left as the attack payload.
|
|
493
|
+
Fixes:
|
|
494
|
+
1. `restoreOriginal` now replays each dirty field as its own
|
|
495
|
+
single-key PUT, so partial-PUT APIs accept it. Caller passes the
|
|
496
|
+
set of mutated keys (full-baseline → all body keys, partial
|
|
497
|
+
baseline / per-attack → just the targeted field).
|
|
498
|
+
2. `findDeleteCounterpart` / `findGetByIdCounterpart` are
|
|
499
|
+
trailing-slash tolerant. `POST /keys/` + `DELETE /keys/{id}/`
|
|
500
|
+
now matches; previously the regex required identical slash forms
|
|
501
|
+
and silently leaked DSN keys.
|
|
502
|
+
3. POST cleanup failures (no DELETE counterpart, missing id, DELETE
|
|
503
|
+
4xx, network error) accumulate into `verdict.cleanup.error`.
|
|
504
|
+
4. `formatSecurityDigest` prints a mandatory
|
|
505
|
+
`## ⚠️ Cleanup failures` section first when any verdict has a
|
|
506
|
+
cleanup error, plus a `🧹 cleanup-failure` tag next to the
|
|
507
|
+
verdict line in its severity bucket. The CLI now exits non-zero
|
|
508
|
+
on cleanup failures (data-integrity gate, distinct from the
|
|
509
|
+
HIGH-finding gate).
|
|
510
|
+
|
|
511
|
+
- **TASK-151: `probe-security` snapshot+restore cleanup for PUT/PATCH.**
|
|
512
|
+
Cleanup used to be `DELETE-if-2xx`, which silently destroyed live data
|
|
513
|
+
on rename'ы — a probe overwrote a Sentry DSN-key with the attack
|
|
514
|
+
payload and left it that way. probe-security now does a `GET` before
|
|
515
|
+
baseline (when there's a GET counterpart on the same path),
|
|
516
|
+
caches the original body, and restores it via `PUT`/`PATCH` after
|
|
517
|
+
every 2xx response. Strips read-only fields (`id`, `created_at`,
|
|
518
|
+
`updated_at`) from the restore body, forwards `If-Match` when
|
|
519
|
+
`requiresEtag` is set, and surfaces restore failures in
|
|
520
|
+
`verdict.cleanup.error` so they show up in the digest. POST keeps
|
|
521
|
+
the existing `DELETE`-counterpart cleanup.
|
|
522
|
+
|
|
523
|
+
- **TASK-152: `probe-security` partial-body fallback on PUT/PATCH.**
|
|
524
|
+
Sentry / Stripe / GitHub-shaped APIs accept partial PUT — sending the
|
|
525
|
+
spec's full body returns `422` and the proven-HIGH CRLF on
|
|
526
|
+
`subjectPrefix` lands in `INCONCLUSIVE-BASELINE`. probe-security now
|
|
527
|
+
retries the baseline with a single-key body per detected field; if any
|
|
528
|
+
partial baseline succeeds, attacks proceed using that shape and the
|
|
529
|
+
finding `reason` is annotated `[partial-body]`. Only PUT/PATCH —
|
|
530
|
+
partial bodies on POST would just trip required-field validation.
|
|
531
|
+
|
|
532
|
+
### Added
|
|
533
|
+
|
|
534
|
+
- **TASK-138: `zond probe-security <classes>` — live SSRF / CRLF /
|
|
535
|
+
open-redirect probes.** Replaces the markdown templates the audit skill
|
|
536
|
+
used to ship for Phase 5.2/5.3 (one HIGH stored CRLF on Sentry came
|
|
537
|
+
from one of those templates — but only after hand-copying it per
|
|
538
|
+
endpoint). Detects vulnerable fields by name + `format` hints
|
|
539
|
+
(`*_url` / `webhook` / `format: uri` for SSRF; `subject` / `*_prefix`
|
|
540
|
+
/ `name` / `description` for CRLF; `redirect` / `next` / `return_to`
|
|
541
|
+
for open-redirect), sends a **baseline-OK** request first (skips the
|
|
542
|
+
endpoint with `INCONCLUSIVE-BASELINE` if baseline ≠ 2xx — eliminates
|
|
543
|
+
the 5×404 noise the markdown templates produced on scope-locked
|
|
544
|
+
endpoints), then attacks each detected field with the class's
|
|
545
|
+
payloads. Classifies HIGH (5xx **or** payload echoed in 2xx body —
|
|
546
|
+
stored injection candidate), LOW (2xx, no echo — verify manually),
|
|
547
|
+
OK (4xx). Idempotent cleanup via DELETE counterpart. `--dry-run`
|
|
548
|
+
enumerates fields without sending requests. `--emit-tests <dir>`
|
|
549
|
+
produces regression YAML suites with `always: true` cleanup.
|
|
550
|
+
|
|
551
|
+
- **TASK-137: `probe-mass-assignment` body-FK auto-discovery.** Required
|
|
552
|
+
body fields named `*_id` / `*_slug` / `*_uuid` / `*_key` are now resolved
|
|
553
|
+
pre-baseline by hitting the matching collection list endpoint
|
|
554
|
+
(`audience_id` → `GET /audiences`). Eliminates most
|
|
555
|
+
`inconclusive-baseline` noise, where the spec-generated random UUID was
|
|
556
|
+
rejected before extras ever reached validation. Enabled by default
|
|
557
|
+
(gated by the existing `--discover` / `--no-discover` flag — same as
|
|
558
|
+
the path-param discovery from TASK-92). When discovery still misses an
|
|
559
|
+
FK, the INCONCLUSIVE summary now lists the unresolved field names so
|
|
560
|
+
the user knows exactly what to add to env. Follow-up
|
|
561
|
+
`--retry-inconclusive <run-id>` tracked as TASK-150.
|
|
562
|
+
|
|
563
|
+
- **TASK-136: `zond discover --api <name>` — auto-fill `.env.yaml` FK ids
|
|
564
|
+
from list-endpoints.** Phase 2.5 of an audit used to be manual: hit
|
|
565
|
+
`GET /audiences`, `GET /projects`, etc., copy slugs into `.env.yaml`,
|
|
566
|
+
repeat for every FK. `discover` walks `.api-resources.yaml`, finds owner
|
|
567
|
+
list-endpoints for each path-FK var, calls them with the workspace
|
|
568
|
+
`auth_token`, and proposes a diff. Suffix-aware extraction (`*_slug` →
|
|
569
|
+
`slug`, `*_uuid` → `uuid`, `*_id` → `id`). Default dry-run; `--apply`
|
|
570
|
+
writes with a `.env.yaml.bak` backup. Skips vars already filled with a
|
|
571
|
+
non-placeholder value. v1 limitation: only collection-level list
|
|
572
|
+
endpoints (no nested paths — that's TASK-137 territory).
|
|
573
|
+
|
|
574
|
+
- **TASK-139: `zond generate --explain`.** Prints a per-POST diagnostic table
|
|
575
|
+
(`resource | post | get/{id} | put/patch | delete | list | verdict | reason`)
|
|
576
|
+
without writing files, so you can debug "why didn't `generate` emit a CRUD
|
|
577
|
+
chain for resource X?" against a real spec. Pairs with the relaxed
|
|
578
|
+
detector below.
|
|
579
|
+
|
|
580
|
+
### Changed
|
|
581
|
+
|
|
582
|
+
- **TASK-139: relaxed CRUD detector — trailing slashes and id-like field
|
|
583
|
+
names.** `detectCrudGroups` now matches `POST /alerts/` against
|
|
584
|
+
`GET /alerts/{id}` (and any combination of trailing slashes), and
|
|
585
|
+
`getCaptureField` looks for the path-param name (`{slug}` → `slug`,
|
|
586
|
+
`{rule_id}` → `id`/`rule_id`) plus `slug`/`uuid`/`key`/`version`/`name`
|
|
587
|
+
string fields before falling back to type-shape heuristics. Together
|
|
588
|
+
these produce CRUD chains for Sentry-style resources (alert-rules,
|
|
589
|
+
dashboards, releases) that previously fell through the strict regex.
|
|
590
|
+
|
|
591
|
+
### Changed
|
|
592
|
+
|
|
593
|
+
- **TASK-135: `probe-validation` no longer short-circuits on parent path
|
|
594
|
+
params.** Probes now emit non-attacked path parameters as runtime
|
|
595
|
+
placeholders (`{{organization_id_or_slug}}`) so `zond run` resolves them
|
|
596
|
+
from `.env.yaml`. Previously every parent slot was baked as the
|
|
597
|
+
synthetic sentinel `nonexistent-zzzzz`, which made nested-path probes
|
|
598
|
+
return 404 from the parent before the leaf validator ever fired —
|
|
599
|
+
hiding real 5xx bugs in `repos/{repo}/commits`-style endpoints. Use
|
|
600
|
+
`--no-real-parents` to keep the legacy fully-synthetic rendering.
|
|
601
|
+
|
|
602
|
+
### Added
|
|
603
|
+
|
|
604
|
+
- **TASK-110: `zond report case-study <failure-id>` — markdown drafts for
|
|
605
|
+
one failure.** Companion to TASK-107: zooms into a single `results.id`
|
|
606
|
+
and produces a ready-to-edit case-study (TL;DR, spec snippet, curl,
|
|
607
|
+
response, "why it matters", provenance) primed for `gh issue create
|
|
608
|
+
--body-file -` or a Slack write-up. Powers a **Case study draft**
|
|
609
|
+
button on the Run detail UI (clipboard via
|
|
610
|
+
`GET /api/results/:id/case-study.md`). Missing fields become explicit
|
|
611
|
+
`<TODO: ...>` placeholders.
|
|
612
|
+
|
|
613
|
+
- **TASK-107: `zond report export <run-id>` — single-file HTML run reports.**
|
|
614
|
+
Materialises a stored run as a self-contained HTML (inline CSS + JS, no
|
|
615
|
+
external assets) you can attach to a GitHub issue, drop into Slack, or
|
|
616
|
+
archive offline. Includes pass-rate ring, KPI strip, collapsible failure
|
|
617
|
+
cards with provenance + frozen OpenAPI excerpts, **Copy curl** and
|
|
618
|
+
**Copy as GitHub issue** buttons, failure-class filter chips, and an
|
|
619
|
+
endpoint × method coverage map. Light/dark themes via
|
|
620
|
+
`prefers-color-scheme`; print-friendly for browser-PDF export.
|
|
621
|
+
|
|
622
|
+
### Breaking
|
|
623
|
+
|
|
624
|
+
- **TASK-73: top-level `--json` removed.** `--json` was previously a global
|
|
625
|
+
option that propagated to every subcommand; on `run` it collided with
|
|
626
|
+
`--report json` and crashed (`paths[0] must be of type string`). It is now
|
|
627
|
+
a per-command option attached only to subcommands that produce a JSON
|
|
628
|
+
envelope. **Migration**: replace `zond run … --json` with
|
|
629
|
+
`zond run … --report json`. Other commands (`db diagnose --json`,
|
|
630
|
+
`validate --json`, `coverage --json`, …) keep working unchanged — only
|
|
631
|
+
the flag's scope changed, not its meaning.
|
|
632
|
+
|
|
633
|
+
### Round-2 papercuts continued (TASK-70 / TASK-72 / TASK-75)
|
|
634
|
+
|
|
635
|
+
- **TASK-72: `--tag` no longer silently swallows YAML parse errors.** Tag
|
|
636
|
+
filter prints every parse error as a warning; if every file fails to parse
|
|
637
|
+
the run exits 2; if the tag filter empties to zero AND parse errors exist,
|
|
638
|
+
the run exits 1 with a message pointing at the parse failures instead of
|
|
639
|
+
the misleading "No suites match the specified tags".
|
|
640
|
+
|
|
641
|
+
- **TASK-75: pre-flight `{{var}}` check + `--strict-vars`.** Every `{{var}}`
|
|
642
|
+
reference is checked against env, parameterize, set keys and prior-step
|
|
643
|
+
captures before a request goes out. Missing references emit a warning by
|
|
644
|
+
default; `--strict-vars` makes them a hard-fail (exit 2) so CI catches
|
|
645
|
+
typos before the server returns "invalid email format".
|
|
646
|
+
|
|
647
|
+
- **TASK-70: env_issue overrides per-failure recommendation.** When
|
|
648
|
+
`db diagnose` detects a run-level env_issue, every non-5xx failure's
|
|
649
|
+
`recommended_action` becomes `fix_env` and the misleading per-failure
|
|
650
|
+
hint/schema_hint is suppressed. Real backend bugs (5xx) keep
|
|
651
|
+
`report_backend_bug`.
|
|
652
|
+
|
|
5
653
|
## [0.22.0] — 2026-04-29
|
|
6
654
|
|
|
7
655
|
### Round-2 papercuts (TASK-68 → TASK-86)
|