feat: registration fleet-policy gate + OpenAPI→MCP SSE gateway - #518
Open
izzywdev wants to merge 1 commit into
Open
feat: registration fleet-policy gate + OpenAPI→MCP SSE gateway#518izzywdev wants to merge 1 commit into
izzywdev wants to merge 1 commit into
Conversation
Adds `fuzefront-validate-registration`, a zero-dependency validator products run
in their own CI, and fixes the template defect that caused the problem it
catches.
## The failure class
A manifest can be entirely valid and still leave a product permanently
crippled. `mode: "portal"` with `modes` omitted is legal — the frozen contract
says an absent `modes` falls back to `[mode]`. Such a product registers
cleanly, appears in the portal, passes every existing gate, and can never ship
a mobile app, because a TWA can only wrap a `standalone` surface with a URL
that stands on its own.
Nothing is malformed. Nothing errors. A capability simply never exists. No
schema can catch this, because it is not a shape violation — it is a fleet
requirement, and the fleet is not in the schema.
The same shape applies to the policy step: a vendored pre-kit `register.sh`
registers the app and never submits policy.json, so the product gets no roles
and authorization fails closed for everyone. The symptom reads as a bug in the
product.
## The template was the source
`templates/manifest.json` shipped `mode: portal`, no `modes`, and no
`routing.host`. Every product that copied it inherited a registration that
cannot serve a mobile app. FuzeHub and FuzeContact are not two coincidences —
they are the template, propagated. Fixed to `["portal","standalone"]` with a
`routing.host`, and the templates are now checked by the validator in CI so
this cannot regress.
## What the gate enforces
- effective modes include BOTH `portal` and `standalone`
- `standalone` implies a non-empty `routing.host`
- `policy.json` exists, and a vendored `register.sh` actually submits it
Embed-only products are exempt from the surface rules: per the contract an
embed renders inside a third-party page with neither portal chrome nor
FuzeFront navigation, is not a portal destination, and may not register a menu
entry at all.
Matching is on the submission itself (`PUT /apps/{slug}/policy`), not the word
"policy" — a TODO comment must not satisfy the check.
## Verified
18 new tests, all passing. The full kit suite still passes (19 register.sh
behaviours, policy validator, schema freshness). Run against the real repos:
fuzecontact FAIL missing standalone + missing policy.json
fuzehub FAIL missing standalone
fuzebi PASS
fuzeservice PASS
fuzepicker PASS
which is exactly the known state — the gate reproduces the two defects that
prompted it and clears the three conformant repos.
Not verified: no product repo has adopted the check yet; wiring it into each
product's CI is follow-up work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
Contributor
Automated code review (gate-code-review)Credit balance is too low Report-only — this check never blocks merge. |
| if (Array.isArray(raw)) raw.forEach(v => query.append(p.name, String(v))); | ||
| else query.append(p.name, value); | ||
| } else { | ||
| headers[p.name] = value; |
| let cur: unknown = doc; | ||
| for (const p of parts) { | ||
| if (!cur || typeof cur !== 'object') return {}; | ||
| cur = (cur as Record<string, unknown>)[p]; |
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.
Part 1 — Registration fleet-policy gate (
packages/onboarding-kit)Adds
fuzefront-validate-registration, a zero-dependency validator products run in their own CI, and fixes the template defect that caused the problem it catches.The failure class this closes
A manifest can be entirely valid and still leave a product permanently crippled:
{ "mode": "portal", "routing": { "path": "/app/fuzehub" } } // modes omittedThat is legal — the frozen contract says an absent
modesfalls back to[mode]. So this product registers cleanly, appears in the portal, passes every existing gate, and can never ship a mobile app, because a TWA can only wrap astandalonesurface with a URL that stands on its own. Nothing is malformed; a capability simply never exists.Deliberately not a schema tightening.
modesalready hasminItems: 1, so a schema change catches nothing here — omission is the legal case, and its legality is what hides the gap. This is a fleet requirement, and the fleet is not in the schema.The policy step has the same shape: a vendored pre-kit
register.shregisters the app and never submitspolicy.json, so the product gets no roles and authorization fails closed for every user — which reads as a bug in the product.The template was the source
templates/manifest.jsonshippedmode: portal, nomodes, norouting.host. Every product that copied it inherited a registration that cannot serve mobile. FuzeHub and FuzeContact aren't two coincidences — they're the template, propagated. Fixed, and templates now run through the validator in CI so it can't regress.What it enforces
portalandstandalonestandaloneis the only surface a mobile TWA/APK can wrapstandaloneimplies non-emptyrouting.hostpolicy.jsonexists, and a vendoredregister.shsubmits itEmbed-only products are exempt — per the contract they aren't portal destinations at all. Matching is on the
PUT /apps/{slug}/policycall, not the word "policy", so a# TODOcomment can't satisfy it.Verification
18 new tests passing; full kit suite green (19
register.shbehaviours, policy validator, schema freshness). Against real repos:standalone+ missingpolicy.jsonstandaloneExactly the known state — reproduces both defects and clears the three conformant repos.
Not verified: no product repo has adopted the check yet, so this currently protects the kit and its templates, not the fleet.
Part 2 — OpenAPI → MCP SSE gateway (
packages/mcp-gateway)Authored by a parallel workstream. Config-driven gateway exposing a product's REST API as MCP tools over SSE — one shared implementation, deployed as one pod per product per the owner's ruling ("'just a proxy' doesn't mean shared, it means the implementation is merely a layer that exposes the REST API as tools").
I did not author this code and have not reviewed it line by line. Two open Semgrep findings against it are being addressed by its author:
src/spec.ts:64— prototype-pollution-loop (error)src/upstream.ts:72— remote-property-injection (warning)Both are on paths handling externally-supplied OpenAPI documents and upstream responses, so they warrant a real fix rather than a suppression.
Reviewers wanting to take Part 1 independently: it is confined to
packages/onboarding-kit/**and.github/workflows/onboarding-kit-tests.yml.