Skip to content

fix(api): validate request bodies with Zod in 4 routes — restores the t06 gate (#9737) - #9779

Merged
diegosouzapw merged 1 commit into
release/v3.8.50from
fix/release-v3.8.50-basereds-route-validation
Aug 8, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.50from
fix/release-v3.8.50-basereds-route-validation

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Por que

O veredito do release-green (#9737) lista check:route-validation:t06 como HARD failure — e ele continua vermelho no tip atual (63cf354129), verificado numa worktree limpa. Quatro rotas chamam request.json() e validam à mão com typeof x === "string", o que a Hard Rule #7 proíbe e o gate detecta (ele varre o fonte e não tem allowlist).

O que muda

Rota Origem Schema
plugins/marketplace/install #9445 InstallBodySchema
services/dario/admin/accounts #8523 DeleteAccountBodySchema (body opcional do DELETE; caminho por query-param intocado)
services/dario/admin/login-start #8523 LoginStartBodySchema (o trim passa a ser do schema)
services/dario/admin/import-from-omniroute #8523 ImportBodySchema

Troca de mecanismo, não de contrato: os quatro mantêm status e mensagens idênticos (a suíte de sanitização das rotas de plugins segue 33/33).

Guard

tests/unit/route-body-validation-t06.test.ts roda a mesma regra do gate dentro da suíte unitária — assim a próxima rota nesse padrão falha no PR dela, em vez de aparecer semanas depois numa varredura de base-red (foi exatamente o que aconteceu aqui). Validado por mutação: renomear .safeParse( numa das rotas derruba o teste (1 fail); restaurei de cópia pré-sonda.

Gates

route-validation:t06 · file-size · test-discovery · mutation-test-coverage · dead-code → todos exit 0. typecheck:core limpo, eslint limpo.

Refs #9737

… t06 gate

The release-green verdict (#9737) lists check:route-validation:t06 as a HARD
failure and it is STILL red on the current tip: four routes call
request.json() and hand-roll `typeof x === "string"` checks instead of using
Zod, which Hard Rule #7 requires and the gate enforces (it scans source and
has no allowlist).

- src/app/api/plugins/marketplace/install (#9445): InstallBodySchema; the
  400 'Missing or invalid name field' response is preserved verbatim.
- src/app/api/services/dario/admin/accounts (#8523): DeleteAccountBodySchema
  for the optional { alias } DELETE body; query-param path untouched.
- src/app/api/services/dario/admin/login-start (#8523): LoginStartBodySchema;
  trimming now happens in the schema, so the forward body is unchanged.
- src/app/api/services/dario/admin/import-from-omniroute (#8523):
  ImportBodySchema for connectionId/alias; invalid shapes fall back to the
  same 'connectionId is required' 400 as before.

All four keep their exact status codes and messages — this is a validation
mechanism swap, not a contract change (plugins route suite still 33/33).

Adds tests/unit/route-body-validation-t06.test.ts, which runs the gate's own
rule inside the unit suite so the next such route fails on ITS OWN PR instead
of surfacing weeks later in a base-red sweep. Guard verified by mutation:
renaming .safeParse( in one route makes it fail (1 fail), restored from a
pre-probe copy.

Gates: route-validation:t06, file-size, test-discovery, mutation-test-coverage,
dead-code exit 0; typecheck:core clean; eslint clean.

Refs #9737
@diegosouzapw
diegosouzapw merged commit 24bdae2 into release/v3.8.50 Aug 8, 2026
22 checks passed
@diegosouzapw
diegosouzapw deleted the fix/release-v3.8.50-basereds-route-validation branch August 8, 2026 14:24
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
… t06 gate (diegosouzapw#9779)

The release-green verdict (diegosouzapw#9737) lists check:route-validation:t06 as a HARD
failure and it is STILL red on the current tip: four routes call
request.json() and hand-roll `typeof x === "string"` checks instead of using
Zod, which Hard Rule diegosouzapw#7 requires and the gate enforces (it scans source and
has no allowlist).

- src/app/api/plugins/marketplace/install (diegosouzapw#9445): InstallBodySchema; the
  400 'Missing or invalid name field' response is preserved verbatim.
- src/app/api/services/dario/admin/accounts (diegosouzapw#8523): DeleteAccountBodySchema
  for the optional { alias } DELETE body; query-param path untouched.
- src/app/api/services/dario/admin/login-start (diegosouzapw#8523): LoginStartBodySchema;
  trimming now happens in the schema, so the forward body is unchanged.
- src/app/api/services/dario/admin/import-from-omniroute (diegosouzapw#8523):
  ImportBodySchema for connectionId/alias; invalid shapes fall back to the
  same 'connectionId is required' 400 as before.

All four keep their exact status codes and messages — this is a validation
mechanism swap, not a contract change (plugins route suite still 33/33).

Adds tests/unit/route-body-validation-t06.test.ts, which runs the gate's own
rule inside the unit suite so the next such route fails on ITS OWN PR instead
of surfacing weeks later in a base-red sweep. Guard verified by mutation:
renaming .safeParse( in one route makes it fail (1 fail), restored from a
pre-probe copy.

Gates: route-validation:t06, file-size, test-discovery, mutation-test-coverage,
dead-code exit 0; typecheck:core clean; eslint clean.

Refs diegosouzapw#9737

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
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