Repository navigation
feat: route rules in one routes.rego table; Bearer per RFC 7235 in JWTAuth and the policy - #38
Merged
Merged
Conversation
The generated preamble only read `Authorization: Bearer <jwt>`, while FastAPI's security helpers compare the scheme case-insensitively. A client sending `bearer <jwt>` was refused by OPA but accepted by the app. Version 0.5.7. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QA7Vjn4bbjxRsvyz8DNHPQ
A route was two statements, route_patterns[[method, path]] and route_rules[[method, path]]. It is now one: route_rules[[method, path, pattern]] := rule, with the pattern still Starlette's compile_path regex, so OPA matches what FastAPI routes. The preamble matches on route[2]; the hook reads a rule back by method and path. The key is plain JSON, which `opa fmt` leaves as it is. A file in the two-statement format is rewritten and keeps its rules. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QA7Vjn4bbjxRsvyz8DNHPQ
routes.rego now ends in three tables, one route per line: prefix_rules and route_rules hold the service's rules keyed by [method, path], and route_patterns holds Starlette's compile_path regex for each route, regenerated every run. A rule reads as one line of route_rules instead of a statement per route, and the regex stays out of the way in its own table. Entries are split by bracket depth, so a rule over several lines is kept as written. Empty tables are left out, as an empty object fails `opa check --strict`. A file in the one-statement-per-route format is rewritten and keeps its rules. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QA7Vjn4bbjxRsvyz8DNHPQ
…table parser
Bearer: the scheme is case-insensitive and any spaces before the token are
ignored (RFC 7235), in both places. JWTAuth._transform_bearer used a
case-sensitive "Bearer " prefix and now uses FastAPI's
get_authorization_scheme_param, as monitoring already does; the policy
trims spaces before the token. One table of headers is tested against
both.
Parser: one loop splits old statements and table entries by bracket
depth, ignoring brackets inside strings. Every mistake now fails without
writing instead of being dropped or reset:
- a table opener or closer with trailing spaces is still recognised (it
reset every rule to "todo");
- any `x := {}` and a comment line fail, naming the line (`x := {}` was
dropped);
- text between a key and its colon, a key with extra elements and a
non-list key fail, naming the text;
- an unclosed table names the table and its line;
- errors no longer print the retired `route_rules[...]` syntax.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QA7Vjn4bbjxRsvyz8DNHPQ
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.
Two policy changes, version 0.5.7.
Route rules in one table
routes.regoended in two statements per route. It now ends in three tables, one route per line:route_rulesandprefix_rulesare the service's; the hook reads each entry back and keeps it as written, multi-line rules included. One loop splits old statements and table entries by bracket depth, ignoring brackets inside strings.x := 1,x := {}), a comment, text between a key and its colon, a key with extra elements or not a list, an unclosed table. Trailing spaces on a table's opener or closer are fine.route_patternsis regenerated every run and never edited: Starlette's owncompile_pathregex, so OPA matches what FastAPI routes.opa check --strict. The preamble reads them throughdata.policy.*, which compiles either way.Bearer per RFC 7235, in the app and the policy
The scheme is case-insensitive and any spaces before the token are ignored (RFC 7235), now in both places:
JWTAuth._transform_bearerused a case-sensitive"Bearer "prefix; it now uses FastAPI'sget_authorization_scheme_param, asmonitoring.pyalready does.bearermatches the scheme in any case and trims spaces before the token.One table of headers (
Bearer,bearer,BEARER, extra spaces before or after,Bearerx…, a tab,Basic) is tested against both.Verification
pytest: 281 passed, OPA decision tests included. The new parser, bearer and migration tests each fail against a mutant of the code they cover (string-blind bracket counting, escapes, comments, trailing spaces,x := {}, junk before the colon, extra key elements, case-sensitive or untrimmed bearer, old-format migration).prek run --all-filesclean; the rendered file isopa fmt-stable and passesopa check --strictand--v0-compatiblewith all tables, without prefix rules, and with no routes.routes.regoof notify, assistant, iam, persona, ai and twitter: first run rewrites, second run is a no-op, every rule kept (23/168/49/29/42/21),opa check --strictpasses, notify's decisions unchanged.Services pick it up by bumping fastloom and the hook
revtogether.🤖 Generated with Claude Code
https://claude.ai/code/session_01QA7Vjn4bbjxRsvyz8DNHPQ