Skip to content

v0.12.0 - Compile-Time Verification & Contract Manifests

Choose a tag to compare

@srdjan srdjan released this 16 Mar 21:15

Compile-Time Verification & Contract Manifests

This release adds two new compile-time analysis passes that turn zigttp from "a fast small JS runtime" into "a runtime that understands what your handler is allowed to do."

Handler Verification (-Dverify)

Statically proves handler correctness at build time:

  • Exhaustive returns - every code path returns a Response (missing else branches, switch without default)
  • Result safety - Result values from jwtVerify, validateJson, etc. must have .ok checked before .value is accessed
  • Unreachable code - statements after unconditional returns are flagged

This works because zigttp's JS subset eliminates all non-trivial control flow. The IR tree IS the control flow graph. Verification is a recursive tree walk, not a fixpoint dataflow analysis.

$ zig build -Dhandler=handler.ts -Dverify

verify error: not all code paths return a Response
  --> handler.ts:2:17
   = help: ensure every branch (if/else, switch/default) ends with a return statement

Contract Manifest (-Dcontract)

Emits a machine-readable contract.json describing what your handler is allowed to do:

  • Virtual module imports and which functions are used
  • Literal env var names ("dynamic": false when all calls use string literals)
  • Outbound hosts extracted from fetchSync() URL arguments
  • Cache namespace strings from cacheGet/cacheSet/etc.
  • Verification results (when combined with -Dverify)
{
  "modules": ["zigttp:auth", "zigttp:cache"],
  "functions": { "zigttp:auth": ["jwtVerify"], "zigttp:cache": ["cacheGet"] },
  "env": { "literal": ["JWT_SECRET"], "dynamic": false },
  "egress": { "hosts": ["api.example.com"], "dynamic": false },
  "cache": { "namespaces": ["sessions"], "dynamic": false }
}

Non-literal arguments honestly report "dynamic": true. No other JS runtime can do this because full JS is not statically analyzable.

Also in This Release

  • fetchSync - native outbound HTTP bridge with fetchSync(url, init?) returning response-shaped objects
  • Build fixes - transpiler output includes dep_count/dep_bytecodes; mkdir uses absolute path for Zig 0.16 sandbox compatibility
  • Memory safety - errdefer guards on all dupe-before-append paths in contract builder; proper cleanup on error in ContractBuilder.deinit()
  • JSON fix - \u escape in contract serializer now correctly emits hex instead of decimal
  • Code dedup - findHandlerFunction shared between precompile tool and verifier; three extract functions unified into extractLiteralArg

Build Commands

# Verify + contract + AOT + optimized (the full pipeline)
zig build -Doptimize=ReleaseFast -Dhandler=handler.ts -Dverify -Dcontract -Daot

Documentation

  • Verification specification
  • README updated with Compile-Time Toolchain section
  • User Guide updated with verification and contract sections