testing/adversarial_input_cases.ts

Schema-walk generation of adversarial inputs — payloads that must fail validation.

Focused cases: one representative wrong-type value per field, one format violation per constrained field, one null and one missing case per required field, plus whole-body structural attacks (non-object body, extra unknown keys). Hono-free, so the cross-process suites reuse the generators the in-process describe_adversarial_input and describe_rpc_attack_surface_tests run.

view source

Declarations
#

8 declarations

expected_invalid_reason
#

testing/adversarial_input_cases.ts view source

(input_schema: ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>, test_case: InputTestCase): string | undefined import {expected_invalid_reason} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

The error.data.reason an RPC refusal of test_case owes: the declared invalid_reason of the field it breaks, resolved as the dispatcher resolves a failure on that field (resolve_invalid_reason), or undefined — no reason — for an undeclared field or a whole-body case.

input_schema

the input schema the case was generated from

type ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>

test_case

a case generate_input_test_cases produced from it

returns

string | undefined

the owed reason, or undefined when the refusal carries none

generate_input_test_cases
#

testing/adversarial_input_cases.ts view source

(input_schema: ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>, options?: InputTestCaseOptions | undefined): InputTestCase[] import {generate_input_test_cases} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

Generate adversarial test cases for a route's input schema.

Produces focused, non-redundant cases:

  • Whole-body: send array instead of object, extra unknown key
  • Missing required fields (without defaults)
  • One wrong-type value per field
  • Null for required non-nullable fields
  • One format violation per constrained field
  • String length (empty, one under minLength, one over maxLength), numeric (out of range, non-integer, off a multipleOf grid) and array-length (empty, one under minItems, one over maxItems) boundaries

Format and boundaries come from the field's input-side JSON Schema (to_field_json_schema), so a field carrying a .transform() or pipe and a .nullable() / .nullish() field get them too. A bound only a .refine() enforces generates nothing — JSON Schema can't express it.

Each per-field case is single-fault: valid except for the field it breaks. It changes one field of a valid base body — options.base when given, else one built by generate_valid_object — or, for a field that base omits, of the valid body generate_valid_object_with_field builds around it, so a case can't also break an object-level rule (adding scope_kind without its paired scope_id, or slug beside an exactly-one-of id). A field no valid body carries keeps its wrong-type and null cases on the base and gets no format or boundary cases, which would test no bound. A per-field case is emitted only when the field refuses its value, so no case is accidentally valid.

input_schema

the input schema to attack

type ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>

options?

a base body to seed the cases, and a label for errors

optional

returns

InputTestCase[]

throws

  • Error - if the base body fails `input_schema.safeParse` — a seeded base the schema refuses, or a generated one that surfaces broken generation logic — naming the issues rather than producing nonsense adversarial cases.

generate_params_test_cases
#

testing/adversarial_input_cases.ts view source

(params_schema: ZodObject<$ZodLooseShape, $strip>): ParamsTestCase[] import {generate_params_test_cases} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

Generate adversarial test cases for a route's params schema.

Params are always strings from URL segments. Only generates cases for format-constrained fields (uuid, pattern) since unconstrained string params accept any string value, and only a violation the field refuses. Each case breaks one field of a valid params record.

params_schema

type ZodObject<$ZodLooseShape, $strip>

returns

ParamsTestCase[]

throws

  • Error - if no valid params record can be generated

generate_query_test_cases
#

testing/adversarial_input_cases.ts view source

(query_schema: ZodObject<$ZodLooseShape, $strip>): QueryTestCase[] import {generate_query_test_cases} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

Generate adversarial test cases for a route's query schema.

Query params are always strings from the URL. Generates cases for:

  • Missing required fields the field refuses to go without (a preprocessed field with a default accepts its absence)
  • Format violations on constrained fields (uuid, pattern) the field refuses

Each case breaks one field of a valid query record.

query_schema

type ZodObject<$ZodLooseShape, $strip>

returns

QueryTestCase[]

throws

  • Error - if no valid query record can be generated

InputTestCase
#

testing/adversarial_input_cases.ts view source

InputTestCase import type {InputTestCase} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

One adversarial body for an input schema, and the error code it owes.

label

type string

body

type unknown

field?

The one top-level field the case breaks; absent on a whole-body case (a non-object body, an extra unknown key). An RPC refusal of the case owes the field's declared invalid_reason (expected_invalid_reason).

type string

expected_error

type "invalid_request_body" | "invalid_json_body"

InputTestCaseOptions
#

testing/adversarial_input_cases.ts view source

InputTestCaseOptions import type {InputTestCaseOptions} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

base?

A valid body to build the cases from, in place of the generated one — for an input whose valid shape the generator can't reach, or one whose generated body the handler can't run. Each case is this body with one field broken, so it must pass the input schema itself: one that doesn't throws.

type Record<string, unknown>

label?

Names the input in error messages — the RPC method or route it belongs to.

type string

ParamsTestCase
#

testing/adversarial_input_cases.ts view source

ParamsTestCase import type {ParamsTestCase} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

One adversarial params set for a route's params schema.

label

type string

params

type Record<string, string>

QueryTestCase
#

testing/adversarial_input_cases.ts view source

QueryTestCase import type {QueryTestCase} from '@fuzdev/fuz_app/testing/adversarial_input_cases.js';

One adversarial query for a route's query schema.

label

type string

query

type Record<string, string>

Depends on
#

Imported by
#