Skip to content

test: pin raw path segments and scaffold route-policy completeness - #1720

Merged
ColeMurray merged 3 commits into
mainfrom
test/hono-pr0-guardrails
Sep 2, 2026
Merged

test: pin raw path segments and scaffold route-policy completeness#1720
ColeMurray merged 3 commits into
mainfrom
test/hono-pr0-guardrails

Conversation

@ColeMurray

@ColeMurray ColeMurray commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

First step of the follow-up series that retires the routing adapter left by #1716. This PR adds only tests; no production behavior changes.

Encoded path segments are pinned (test/integration/route-admission-matrix.test.ts). Two new tests through the real Worker and the sentinel catalog:

  • Session ids reach the index lookup and the sandbox token binding as the raw segment. An encoded letter in the id misses (404 for the owner, 401 for a sandbox token that verifies against the un-encoded session).
  • Repository handlers decode owner and name exactly once: a nested owner (group%2Fsubgroup) is one segment, a slash in the name (web%2Fapp) is refused after that decode, and a doubly-encoded slash (web%252Fapp) survives because nothing decodes it a second time.
  • RBAC member ids decode once too: an id that is canonical only after a second decode is refused with 400.
  • The sentinel test replaces every handler with one that echoes match.groups, proving the adapter delivers abc%2Fdef, group%2Fsubgroup / web%252Fapp, and a doubly-encoded member id untouched.

Why these matter: the next PR moves parameter access to Hono, whose c.req.param() decodes values, so these tests are the red-then-green story for keeping raw segments where handlers decode themselves.

Dropped during review: an earlier revision carried a route-policy registry with a build-time walk over app.routes. Reconstructing handler chains from Hono's flat route list needed positional rules and an unwrap for mounted sub-apps, which is more machinery than the guarantee deserves. The "every route is admitted" invariant will instead be enforced at request time in the next PR: the lifecycle middleware refuses any response that admission did not precede, and the matrix test exercises every route in CI so a route registered without admit() fails before deploy.

Verification

  • Unit: 231 files, 3,459 passed.
  • Integration (workerd, real D1): 96 files, 1,128 passed on the first revision; the matrix suite re-run green after the registry was removed. The four matrix snapshots are byte-identical.
  • Typecheck (src, tsconfig.test.json, test/integration), ESLint, and Prettier clean.

https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1

Guardrails ahead of the Hono shim retirement. The matrix suite now pins
that percent-encoded segments reach admission and handlers undecoded, and
that repository and RBAC handlers decode exactly once. A route-policy
registry with a build-time completeness walk lands with its own tests; the
production check is marked as an expected failure until admit() tags
policies.

Claude-Session: https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate
Tests

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 85d7daaa-df68-420f-b549-8c67c87e6e20

📥 Commits

Reviewing files that changed from the base of the PR and between 563e526 and 22b6fb9.

📒 Files selected for processing (2)
  • packages/control-plane/src/routing/route-policy-registry.test.ts
  • packages/control-plane/src/routing/route-policy-registry.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The routing API now exports its Hono app factory and environment type. A route-policy registry checks admission coverage. Integration tests cover encoded path matching and single-decoding validation.

Changes

Control plane routing

Layer / File(s) Summary
Expose the control-plane app factory
packages/control-plane/src/routing/hono-app.ts
Exports ControlPlaneHonoEnv and createControlPlaneApp. The HTTP handler uses the renamed factory.
Track and validate route admission policies
packages/control-plane/src/routing/route-policy-registry.ts, packages/control-plane/src/routing/route-policy-registry.test.ts
Adds middleware policy registration, lookup, route-order validation, exemption handling, missing-policy detection, mounted sub-application coverage, and build-time assertion tests.
Validate encoded route segments
packages/control-plane/test/integration/route-admission-matrix.test.ts
Tests encoded session, sandbox, repository, and member segments, including preserved encoding and once-only decoding responses.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 22b6f

This PR adds path-segment regression coverage and a route-policy completeness scaffold without changing production request behavior; no actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the raw path integration tests and route-policy completeness work. It omits the exported app rename, but the title does not need to cover every change.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/hono-pr0-guardrails

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@open-inspect open-inspect Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

PR #1720, test: pin raw path segments and scaffold route-policy completeness, by @ColeMurray changes 4 files (+256/-3). The encoded-segment coverage is strong, but the new completeness registry can accept a route whose admission middleware is unreachable, so the guardrail needs one correctness fix before it is relied on.

Critical Issues

  • [Security/Correctness] packages/control-plane/src/routing/route-policy-registry.ts:54 - Policy presence is aggregated by method/path without considering execution order. An untagged handler can return before a later tagged middleware, while the route is still reported complete. Record policy as part of atomic route registration or otherwise verify that admission precedes every terminal handler.

Suggestions

None beyond the blocking inline finding.

Nitpicks

None.

Positive Feedback

  • The integration cases pin raw, single-decoded, and double-encoded path behavior through both the real Worker and sentinel handlers.
  • The registry tests cover mounted sub-apps, app.use() exclusion, exemptions, and method/path isolation clearly.
  • Focused unit and integration tests pass, including the intentional expected failure, and control-plane typechecking passes.

Questions

None.

Verdict

Request Changes: Ensure the completeness check cannot credit admission middleware that is unreachable behind an earlier handler.

Comment thread packages/control-plane/src/routing/route-policy-registry.ts Outdated

@open-inspect open-inspect Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The encoded-path guardrails are focused and the changed files remain reasonably sized, but the proposed policy-completeness architecture is not sound enough to become a security boundary. Hono's public route list contains flattened handler records, not atomic route-registration chains. Aggregating those records by method and path can therefore certify an admission middleware that is not on the executable path, while handler wrapping can also erase the WeakMap identity. The cleaner move is to make policy part of the canonical native-route registration API so a route, its admission middleware, and its terminal handler are registered atomically instead of trying to infer that invariant afterward. The production check should also be a real, specific assertion rather than an expected failure that accepts any exception.

Requesting changes because the central guardrail can report an unprotected route as complete.

Comment thread packages/control-plane/src/routing/route-policy-registry.ts Outdated
Comment thread packages/control-plane/src/routing/route-policy-registry.test.ts Outdated
The first handler registered for a method+path must be the tagged policy,
since Hono stops at the first handler that answers without calling next.
Wrapped sub-app handlers are unwrapped before lookup, and the production
check now asserts the exact untagged list instead of expecting any failure.

Claude-Session: https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate
Tests

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

Completeness will be enforced at request time by the lifecycle middleware
refusing any response that admission did not precede, so the registry and
its build-time walk over app.routes are not needed.

Claude-Session: https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Terraform Validation Results

Step Status
Format
Init
Validate
Tests

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

@ColeMurray
ColeMurray merged commit 1e86a6b into main Sep 2, 2026
13 checks passed
@ColeMurray
ColeMurray deleted the test/hono-pr0-guardrails branch September 2, 2026 19:31
ColeMurray added a commit that referenced this pull request Sep 2, 2026
## Summary

Second step of the series retiring the routing adapter left by #1716
(guardrails landed in #1720). This PR replaces the mechanism around
every route while leaving all 171 route handlers untouched; after it,
the remaining shim is one `legacy()` adapter function that later PRs
delete module by module.

**Admission is Hono middleware.** `admit(policy)`
(`src/routing/admit.ts`) evaluates the route's declarative policy
through the unchanged `admitRoute()` pipeline and sets
`c.var.admission`. Denials answer from the middleware, with an
authorization denial audited before anything is logged, as before. A
principal-less policy that requires authorization is refused when the
middleware is built.

**The lifecycle is one `app.use("*")`** (`src/routing/hono-app.ts`) that
owns what `dispatchMatchedRoute` and the outer handler used to: the DB
guard (undecorated 503), the HEAD guard (404, never Hono's implicit
GET), the request context and start time, the request log, the audit of
allowed decisions after the handler including the 500 path, and the
common response headers with the route's `Cache-Control`. `app.onError`
maps `HttpError` to the `{ error }` envelope and logs anything else as
the sanitized 500; a non-`Error` throw takes the same path.

**Default deny.** If a handler answers without `admit()` having run
ahead of it, the lifecycle replaces the response with a sanitized 500,
drops the handler's headers, and logs `router.unadmitted_response`.
Every policy, including `public`, sets the admission variable, so a
route registered without `admit()` fails closed on its first request;
the matrix suite drives every route in CI. This is the request-time
check chosen in review of #1720 over the build-time registry.

**Host-injected entrypoint.** `createControlPlaneApp(catalog, host)`
takes a host whose one job is to build the `BackgroundTasks` port from
whatever the platform passed as the execution context. `cloudflareHost`
wraps `waitUntil`; the unit-test host hands the port straight through,
which deletes the fake `ExecutionContext` in `router.test-support.ts`.
`handleControlPlaneHttp` and `createControlPlaneHttpHandler` keep their
signatures, so `index.ts` is unchanged.

**Deleted:** `Route.pattern`, `parsePattern`, the raw-path re-match and
its `router.match_mismatch` branch, `route-dispatch.ts`, the start-time
`WeakMap`. Admission now takes `params: RouteParams` (raw segments read
back from the pathname by position, `src/routing/route-params.ts`)
instead of a `RegExpMatchArray`, and `legacyMatch()` rebuilds the array
handlers still read from those params.

**Test changes.** Unit tests that selected routes by `route.pattern` use
`matchRoute()` / `routePathPattern()` from test support instead; no
assertions changed. The conformance snapshot drops the `pattern` field
from each of its 171 rows (identities, groups, policies, and order
verified identical before and after). New `hono-app.test.ts` covers the
default deny (including header non-leakage), preflight and 404
exemptions, HEAD, `HttpError` mapping, unexpected and non-`Error`
throws, and both build-time refusals.

## Behavior notes

- No status, body, header, or log-ordering change on any route. The four
route-matrix snapshots are byte-identical.
- The request-duration clock now starts in the lifecycle middleware,
after Hono selects the route, rather than before `app.fetch`. The
difference is the router lookup.
- Parameter values handlers see are still raw. Decoding by default
arrives with the module conversions.

## Verification

- Unit: 232 files, 3,464 passed.
- Integration (workerd, real D1): 96 files, 1,128 passed.
- Typecheck (`src`, `tsconfig.test.json`, `test/integration`), ESLint,
and Prettier clean.

https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Updated request routing and authorization handling for more consistent
policy enforcement.
* Improved handling of denied requests, unexpected errors, unsupported
methods, and route-related failures.
* Strengthened route validation, including authorization requirements
and duplicate parameter detection.
* Improved request lifecycle behavior, including logging, trace
identifiers, response finalization, and CORS preflight handling.
* **Bug Fixes**
* Improved extraction and handling of route parameters, including
sandbox session-related requests.
* Ensured unexpected handler failures return a consistent server error
response with the appropriate headers and response policy.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
ColeMurray added a commit that referenced this pull request Sep 3, 2026
## Summary

Third step of the series retiring the routing adapter (#1720 guardrails,
#1721 mechanism). This PR converts the first six route modules to native
Hono sub-apps and establishes the pattern the remaining module PRs
follow. 12 routes convert; the other 159 still go through the catalog
adapter.

**A converted module** is a `Hono` sub-app whose routes register with
`admit(policy)` as their first middleware and a native handler behind
it:

```ts
export const keyboardShortcutRoutes = new Hono<ControlPlaneHonoEnv>();

keyboardShortcutRoutes.get(
  "/keyboard-shortcuts",
  admit({ ...SCM_AGNOSTIC_HUMAN_USER_ROUTE, authorization: ACTIVE_SELF }),
  async (c) => {
    const { ctx } = c.var.admitted;   // ctx.principal is typed UserPrincipal by the policy
    ...
  }
);
```

`admit()` is now generic over its policy and sets `c.var.admitted` as `{
request, ctx }`, where `request` is the request as authentication
returned it (sig1 verification consumes the original body) and `ctx` is
the request context narrowed by the policy's authentication kind,
exactly as `RouteContext<Authentication>` narrowed the legacy handler's
fourth argument. Handlers use `c.req.param()` for path parameters; none
of the six modules has one, so no decoding question arises in this PR.

**The catalog mounts modules in place.** `catalog` (renamed from
`routes`) is an ordered list of `Route | RouteModule`.
`createControlPlaneApp` mounts a sub-app with `app.route("/", module)`
where it appears and registers a legacy route through the adapter where
it appears, so registration order, and therefore precedence, is
unchanged. The path grammar and duplicate-parameter checks run for
module routes too.

**Route contracts come from Hono's own route list.**
`listRouteContracts(app)` walks `app.routes` and yields `{ method, path,
...policy }` for every entry whose handler is the `admit()` middleware,
which carries the policy it enforces. The policy tests, the
route-admission matrix, its sentinel suite, and the conformance suite
iterate that list instead of the catalog array, so they cover converted
and legacy routes alike. Both integration snapshots are byte-identical
to `main`.

**Handler-level tests become request-level.** `analytics.test.ts` went
through `createTestRequestHandler([analyticsRoutes])` with
`authenticate` mocked to return a user and
`ownerAuthorizationDatabase()` answering the effective-authorization
lookup, which is the pattern `router.authorization-audit.test.ts`
already used. Same assertions, plus a denial case that proves no store
is touched. The remaining 26 handler-level test files convert with their
modules.

Converted: `health` (moved out of `catalog.ts` into its own module),
`keyboard-shortcuts`, `model-preferences`, `sign-in-providers`,
`audit-events`, `analytics`.

## Verification

- Unit: 234 files, 3,474 passed.
- Integration (workerd, real D1): 96 files, 1,128 passed. Route-matrix
and conformance snapshots unchanged.
- Typecheck (`src`, `tsconfig.test.json`, `test/integration`), ESLint,
and Prettier clean.

https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Added a health check endpoint reporting service availability.
- Expanded support for modular route handling while preserving existing
endpoint access policies.
- Added route contract reporting for endpoint methods, paths, and access
requirements.

- **Bug Fixes**
- Preserved authentication, authorization, caching, and request-context
behavior across updated endpoints.
- Improved validation for unsupported route patterns and improperly
configured routes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
ColeMurray added a commit that referenced this pull request Sep 3, 2026
## Summary

Fourth step of the series retiring the routing adapter (#1720, #1721,
#1723). This PR converts the sessions cluster, the largest and most
policy-diverse group, to native Hono sub-apps: 42 routes across 13
session modules plus the Slack notification route. It is the design
proof for path parameters and for the sandbox-fallback and exact-sandbox
policies.

**Modules.** Each session module is a `Hono` sub-app registering
`admit(policy)` first, and `sessions.ts` nests them under one sub-app in
the old precedence order (`/sessions/inbox` still registers before
`/sessions/:id`). The catalog mounts that sub-app and the Slack
notification module where the spread and the inline route used to sit.

**Handlers** keep their bodies and take a typed params object in place
of the match array:

```ts
export async function handleGetChild(
  request: Request,
  env: Env,
  params: { id: string; childId: string },
  ctx: SessionRouteContext
): Promise<Response>
```

Registration passes `c.req.param()`, which Hono types from the path
literal, so a handler declaring `childId` cannot be wired to a route
without one. `withSessionRuntime(env, ctx)` replaces the
`sessionRoute()` wrapper: it attaches the runtime client at the call
site, and the handler-level tests use the same function to build their
context.

**Runtime proxy.** The three factories (`simpleProxy`,
`legacyTokenRefresh`, `lifecycleProxy`) now build handlers rather than
catalog entries, collected in `sessionRuntimeProxyHandlers` and
registered one route each. The tests select handlers from that map by
the production contract instead of scanning a route array.

**Decode once, in Hono.** Admission now reads `c.req.param()`, so the
session id the sandbox binding verifies, the automation id the ownership
check loads, and any actorless-grant path parameter are Hono's decoded
values, and admission's own `decodeURIComponent` calls are removed.
`rawRouteParams` survives only inside the legacy adapter, for the
modules not yet converted, and goes with them.

## Behavior change

An encoded session id now resolves the same session as its plain form:
`GET /sessions/%74est-…` returns the session rather than 404, and a
sandbox token on `/sessions/%74est-…/tunnel-urls` verifies rather than
401. The guardrail tests from #1720 record this as their new
expectation. No other route observed a different status: both
integration snapshots are byte-identical to `main`.

## Tests

Handler-level tests pass params objects and get their session runtime
from `withSessionRuntime`; assertions are unchanged.
`router.create-session.test.ts` calls the exported `handleCreateSession`
directly. No test lost coverage; the route-matrix suite covers every
converted route per credential class as before.

## Verification

- Unit: 234 files, 3,476 passed.
- Integration (workerd, real D1): 96 files, 1,128 passed. Route-matrix
and conformance snapshots unchanged.
- Typecheck (`src`, `tsconfig.test.json`, `test/integration`), ESLint,
and Prettier clean.

## Review follow-up (71224c4)

- **Malformed path segments are refused at admission.** Hono leaves a
segment it cannot decode as it arrived, so the automation-id
requirement's 400 had become a 404. `admit()` now checks every raw
`:param` segment once and answers `400 { error: "Invalid path encoding"
}` on every route before any lookup. This replaces the three
route-specific messages `main` produced for this input (`Invalid
automation route`, `Invalid user ID` on malformed member ids, and the
session routes' 404); the two RBAC integration expectations and the
routing-compatibility probe record the uniform envelope. Both matrix
snapshots are still byte-identical.
- **One call-site adapter.** `dispatch(c, handler)` in
`routing/admit.ts` is the only place a Hono context is unpacked for a
handler; `dispatchSession(c, handler)` adds the runtime client. A route
reads `admit(policy), (c) => dispatchSession(c, handleX)`. The context
type is checked against the policy, so a user-only handler behind a
user-or-service policy fails to compile (a curried `handle(handler)`
form was tried and rejected because Hono infers the environment from the
returned function and that check disappears).
- **Proxy tests dispatch through the production sub-app.** The test-only
handler map is gone; the runtime proxy registers its handlers directly,
and `session-runtime-proxy.test.ts` sends real requests through
`sessionRuntimeProxyRoutes`, with a 17-row wiring table that fails if a
route is bound to the wrong proxy.

https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Standardized routing and authorization across session, attachment,
media, child-session, prompt, pull-request, skills, WebSocket token, and
notification endpoints.
* Preserved existing endpoint paths, permissions, upload validation,
streaming, and error handling.
* Improved handling of percent-encoded path values so valid requests
resolve correctly.

* **Bug Fixes**
* Malformed percent-encoded path segments now return a clear 400 error
before processing.

* **Tests**
* Expanded coverage for routing, authorization, encoded paths, and
request dispatch.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
ColeMurray added a commit that referenced this pull request Sep 3, 2026
Last PR of the Hono series (#1720, #1721, #1723, #1724, #1726, #1727,
#1728, #1729). Every route module is a Hono sub-app, so the adapter that
carried catalog routes through admission has nothing left to serve.

## Removed

- `legacy()` and `legacyMatch()` in `routing/hono-app.ts`;
`createControlPlaneApp(modules, host)` mounts modules only.
- `RouteDefinition`, `Route`, `defineRoute()`, `defineRoutes()`, and
`extractRepoParams()` in `routes/shared.ts`. `RouteAdmissionPolicy` is
now an interface over `RoutePolicy` plus `authorization` and
`serviceActorClaims`; `cacheControl` lives on `AdmissionPolicy` in
`routing/admit.ts`.
- `RouteCatalogEntry`; the catalog is `readonly RouteModule[]`.
- `legacyRoutes()` in test support; `matchRoute()` no longer fabricates
a `RegExpMatchArray`.
- `routes/shared.test.ts`, replaced by
`routes/repository-params.test.ts` over the decoded pair.

## Kept on purpose

- `RouteParams`: admission's decoded-parameter dictionary. Hono exports
no such type.
- `rawRouteParams()`: the malformed-encoding guard's raw read-back
(added in #1724).

## Tests

Fixtures that need synthetic routes build a `Hono` module and pass it to
`createTestRequestHandler([module])`: the lifecycle suite, the contract
lister's suite, and the authorization-audit suite's eleven routes. The
two Worker-boundary suites build their shadow catalogs the same way:
conformance echoes the raw read-back through `rawRouteParams()`, and the
matrix's "raw path segments" probe from #1720 is now the decode-once
assertion on what handlers receive (`abc%2Fdef` arrives as `abc/def`,
`web%252Fapp` as `web%2Fapp`).

## Verification

| Check | Result |
|---|---|
| Typecheck (src, test, integration) | clean |
| ESLint, Prettier | clean |
| Unit | 234 files, 3,512 passed |
| Integration (workerd, real D1) | 96 files, 1,129 passed |
| Matrix and conformance snapshots | byte-identical |

https://claude.ai/code/session_01KdDpTgGEjXpBA9SaGQVUH1


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Repository paths now support nested owner namespaces, such as
`group/subgroup`.
- Repository names containing slash characters are rejected with a clear
validation message.
- URL path parameters are decoded consistently, improving handling of
encoded repository and member identifiers.

- **Refactor**
- Control-plane routing now uses the current route-module system,
providing consistent admission, route matching, and request handling
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant