Skip to content

v0.21.0 — two binaries, framework-neutral security rules, and the first CRITICAL cross-layer finding

Choose a tag to compare

@eezz4 eezz4 released this 22 Jul 16:34

v0.21.0 — two binaries, version-stamped caches, framework-neutral security rules, and the first CRITICAL cross-layer finding

Highlights

  • Two binaries per release. zzop (the plain CLI: analyze, cross, endpoint, analyze-envelope, validate-envelope, validate-rule-pack, contract, version) and zzop-mcp (the MCP stdio server) — thin entries over one shared library. Release assets ship both, 5 platforms each, plus the .mcpb bundles. (Reverses v0.20.0's single-binary direction; npm remains removed.)
  • Version SSOT. The workspace Cargo.toml version is the single source; both binaries report it via CARGO_PKG_VERSION, and CI fails the release unless the pushed tag, Cargo.toml, and the plugin manifest all agree.
  • cross-layer/retrying-write-no-idempotency is now CRITICAL and two-sided. A retry-configured frontend write joined to a real provider route fires only when no idempotency guard is witnessed on that provider: natively (an inline handler reading the Idempotency-Key header) or via an injected idempotency-guarded attribute (Mode B attributes, exact IoKey or PathScope). Every finding carries a paste-ready data.injectionStub. Suppress per-site with the standard marker if a handler is idempotent in a way neither channel expresses.
  • http pack goes framework-neutral. auth-gates and route-exposure migrated from an apiRoutes.-only line scan to whole-tree io-scan over ASSEMBLED provides — they now fire on Express, Hono, NestJS, Spring, ASP.NET Core, FastAPI, Django, gin, axum routes alike. auth-gates vetoes on the auth-guarded attribute (native middleware/decorator/annotation recognition — produced even when mutating-route-no-auth is disabled — or Mode B injection) and deliberately dropped its same-line keyword carve-out (a lexical token is not auth evidence). read-model-path stays, explicitly reframed as a house-convention rule.
  • DSL io-scan matcher grew up. Evaluates whole-tree (it now sees router-mount/controller-prefix/file-convention/whole-corpus composed routes), and gained symbol_pattern, attr_present/attr_absent, anchor_exclude_pattern, file_exclude_pattern, plus suppress-marker support (// marker-ok and # marker-ok).
  • Precision fixes. Next.js pages/api verb detection is handler-body-scoped with the real request parameter name (helper-function mentions no longer mint verbs). Python instance-egress bindings are last-write-wins (a client variable reassigned to a dict no longer misreads .get as HTTP). Hand-rolled fixed-method wrappers over builtin fetch now join the cross-layer graph natively (the S7 self-report quiets automatically for them).

Behavior changes to expect

  • Findings previously at warning for cross-layer/retrying-write-no-idempotency are now critical (or vetoed entirely when the provider guard is witnessed).
  • http/auth-gates and http/route-exposure can fire on trees that never produced them before (any framework with /admin//internal resp. dev/debug-style route segments). Escape hatches: the auth-guarded attribute, // auth-gate-ok / # auth-gate-ok markers, rules: {"http/auth-gates": "off"}.
  • Keyword-bearing handler names (adminHandlers.x, guardedHandlers.y) no longer clear auth-gates; route-level HOF guards (requireAdmin(handler)) currently fire as a known, suppressible false positive until natively recognized.
  • Next.js pages/api routes may report FEWER verbs (helper-function false verbs removed) or degrade to the serve-all sentinel for HOF-wrapped default exports — disclosed via cross-layer/unknown-verb-route, never silently mis-keyed.
  • Every cache re-parses cold once after upgrading: all cache-bust tokens moved to package-version stamps (<scope>/<last-change-version>). Subsequent releases that leave a scope untouched will keep its warm cache — that is the new scheme's point.
  • Custom packs using io-scan rules: those findings now evaluate whole-tree (composed provides visible, attributes consultable) and honor suppress markers; they no longer appear in per-file cached findings.

Corpus check (RealWorld pairs)

No regressions: Angular×Spring 19 edges, axios×ASP.NET 19, axios×FastAPI 19, Vite×Django unchanged; Vite×Express improved 39 → 48 joined edges vs v0.20.0 (builtin-fetch wrapper joins + earlier fixes). New io-scan rules fire on zero corpus trees (no admin/debug paths there) — verified against synthetic e2e fixtures instead.