chore(release): prep v0.2.0#16
Merged
Merged
Conversation
Implements the OPA conformance harness (#9 design follow-through), bumps the docs / changelog / roadmap to reflect everything merged since v0.1.0, and fixes a backward-compat regression where the new response phase would 503 every response on policies that only defined an 'allow' rule. OPA conformance harness (closes the design-only PR #9): - tools/rego2ast.py converts 'opa parse --format json' output to zopa-shaped AST JSON. Covers default rules, comparator builtins (eq/neq/lt/lte/gt/gte), bare ref / value, not (negated flag), every iterator, and the four string/collection builtins (startswith / endswith / contains / count). Skips with a descriptive Unsupported error on user-defined functions, with overrides, partial eval, multi-statement every bodies, some-in bridging, comprehensions, and numeric ref segments. - test/conformance/run.py drives each fixture end-to-end: opa parse -> rego2ast.py -> zopa.wasm.evaluate_addressed -> compare to the fixture's expected decision. PASS / SKIP / FAIL per case; non- zero exit on any FAIL. - 6 starter fixtures cover bool comparators, builtins, every, not, count, missing-path semantics. 15 / 15 cases pass locally. - New 'zig build test-conformance' step. New CI job 'test (conformance)' installs opa via curl and runs the suite. New wasm export evaluate_addressed(input, ast, package, target_rule) so generic-ABI hosts (incl. the conformance runner) can dispatch into a specific package within a Modules bundle. Backward-compat fix: - proxy_on_request_body and proxy_on_response_headers short-circuit at configure time when the policy doesn't define allow_body / allow_response. Without this gate, a v0.1 policy with only an 'allow' rule upgraded to v0.2 would have 503'd every response. Detection is a substring match against the quoted rule name in the policy JSON; false positives only cost an extra eval. Unit test for the corresponding eval-side fix is added. Eval-side correctness fix: - resolveValue's .ref arm now catches PathNotFound / PathNotObject and returns Value.nil instead of propagating the error. This matches Rego's 'missing path is undefined' posture: 'input.user .role == "admin"' against {} now denies (0) instead of erroring (-1). EvalTooDeep and other helper errors still propagate. New unit test 'missing ref inside compare denies' added. Doc / changelog / roadmap: - README.md: size 50K -> 60K everywhere, lifecycle section explains the per-phase target rules, supported-nodes line lists call / modules / kind, comparison table updated. - CHANGELOG.md: full 0.2.0 entry covering Added / Changed. - ROADMAP.md: Done in v0.2.0 section with all merged work; near- term reframed around streaming runtime, conformance corpus expansion, structured response replacement, per-context request snapshot. - docs/ast.md: documents 'modules' bundle, 'package' field on module, 'kind' field on some/every, and the new 'call' node with the v1 builtin table. - docs/proxy-wasm.md: per-phase target / input shape / deny status table; explicit 'phase opt-in via rule name' section explaining the substring-match gate. evaluate_target and evaluate_addressed added to the generic-ABI table. src/proxy_wasm.zig: stale 'Tracked in ROADMAP.md' comments updated to point at the body-aware-policies design doc and v2 plan.
This comment was marked as resolved.
This comment was marked as resolved.
Two medium / high feedback items from gemini-code-assist:
(high) src/proxy_wasm.zig:146 -- substring match for allow_body /
allow_response can produce false 403s. Scenario: a literal string
'allow_body' sits in policy data (e.g. a rule value), the substring
scan flips has_allow_body to true, body callback fires, eval finds
no rule with that name and returns false, shim returns 403. My
'cost-only' comment was wrong.
Replaced with a real AST scan: scanPhaseRules() parses the policy
JSON via the request arena (empty at configure time), walks every
module's rule list, and only sets the flag when an actual rule with
the matching name exists. Substring-in-string-data therefore can't
trip the flag.
(medium) tools/rego2ast.py:202 -- walk_term didn't handle 'set' or
'object' term types. Policies using set / object literals errored
out with Unsupported even though zopa supports both. Added both
arms; object keys must be strings (zopa's Value.object requires
that). walk_term_as_jsonvalue gained the same arms for nested
literals inside arrays / objects.
Two new conformance fixtures cover the addition: 07_object_literal_eq
exercises {key: value} literal equality (3 cases all pass), and
08_set_literal_count uses count({a,b,c}) == 3 to verify set literal
construction without needing a set-typed input (JSON has no set, so
'input.tags == {a,b}' would intentionally never match).
19 / 19 conformance cases pass. Release build size unchanged at
~61KB.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
tools/rego2ast.pywalksopa parseJSON into zopa AST;test/conformance/run.pydrives 6 starter fixtures via the newevaluate_addressedwasm export. 15 / 15 cases pass. Newtest (conformance)CI job.proxy_on_response_headersandproxy_on_request_bodynow opt in via the corresponding rule (allow_response/allow_body) being present in the policy. Without this gate every response on a request-only policy would have been replaced with a 503.resolveValue's.refarm foldsPathNotFound/PathNotObjecttoValue.nilinstead of propagating an error.input.user.role == "admin"against{}now denies (0) instead of erroring (-1).README.md,CHANGELOG.md,ROADMAP.md,docs/ast.md,docs/proxy-wasm.mdup to v0.2 reality (size 50K→60K, three-phase target rules, new builtins, modules bundle).evaluate_addressed(input, ast, package, target_rule)to address into a specific package within aModulesbundle.Test plan
zig fmt --check src test build.zig build.zig.zonzig buildandzig build --release=small(61K)zig build test-unit— all green, includes newmissing ref inside compare deniescasezig build test(Node integration) — all greenzig build test-wasmtime(Python wasmtime) — all greenzig build test-conformance— 15 / 15 pass, 0 skip, 0 failzig build bench— runs end-to-end (1.79μs / 4.67μs locally)markdownlint-cli2clean across all 29 markdown filesv0.2.0after merge → release.yml + oci.yml fireBackward compatibility
Existing v0.1 policies that only define an
allowrule are unaffected:allowand 403s on deny (unchanged)