feat: model input validation before build and run (#3097)
* feat: validate model inputs before build and run
Validate CLI inputs for `cog predict`, `cog run`, and `cog train` against
the model's OpenAPI schema before the expensive build/pull/start steps, so
bad inputs fail fast instead of after a full Docker build or container start.
- Add pkg/predict/input_validation.go with schema-driven validation that
reports friendly errors (unknown/missing inputs, type mismatches, enum
values, numeric constraints).
- Extract static schema generation into pkg/schema/static so both the image
build and CLI preflight share one code path.
- predict/train: generate the schema up front from cog.yaml (local source)
or the image's openapi_schema label (existing image) and validate before
building/starting. Images without the label fall back to the runtime
schema fetched after start, preserving prior behavior.
- Surface file-read failures with the offending input name.
- Add unit and integration tests covering the new validation paths and pin
user-facing error wording to guard against kin-openapi changes.
* refactor: make openapi.Generate the config-aware schema entry point
Rename the config-aware schema generator package to pkg/schema/openapi so
call sites read openapi.Generate(cfg, dir). Rename the existing renderer
file to openapi_spec.go to free the openapi name.
* refactor: rename openapi.Generate to GenerateSchema and clarify locals
Rename the entry point to openapi.GenerateSchema so it's clear what it
produces. In generateLocalOpenAPISchema, rename the loaded document to
`spec` (was shadowing `schema`) and the raw bytes to `openapiSchema`
(avoids implying JSON Schema).
* style: consolidate cmd declarations into var blocks
Address review feedback: use a single var block for the local
declarations in cmdPredict/cmdTrain instead of mixing var and := syntax.
* fix: coerce CLI inputs to schema types and refine preflight fallback
Address PR review feedback on input preflight validation:
- Coerce '-i name=true' to a boolean and repeated/single '-i name=v'
array values to the array's item type, so booleans and numeric/bool
arrays reach the runtime with the intended type and pass preflight
validation instead of failing as strings.
- Preserve typed array elements through Inputs.toMap (previously arrays
were always flattened to []string).
- Only run preflight validation for existing images when the schema
label actually carries the Input/TrainingInput component; otherwise
fall back to the runtime schema (guards minimal/malformed labels).
- Include the input name in JSON-mode file read errors for parity with
the -i path.
- Add integration coverage for omitting a required input (local source
before build, and existing image before start).
* refactor: generate local schema once; match runtime null semantics
Address remaining PR review feedback:
- #7: local-source 'cog predict'/'cog train' now generate the OpenAPI
schema once for input preflight and pass the bytes into the build via
BuildOptions.OpenAPISchema, so the build reuses them instead of
regenerating. This removes the second generation and the chance of
drift between the validated schema and the image label. Extracted the
schema-selection logic into resolveBuildSchema for unit coverage.
- #8: the runtime validates inputs as strict JSON Schema and ignores the
OpenAPI 'nullable' keyword, so it rejects an explicit null for every
field. kin-openapi honors 'nullable' and would accept it, letting a
'--json' request pass preflight only to 422 at runtime. Reject explicit
nulls in preflight so it matches runtime. (The other cases the reviewer
flagged -- numeric strings and Any/object inputs -- were verified to
already match the strict runtime.) Documented the one intentional
divergence: unknown inputs are rejected at the CLI rather than stripped
as the runtime does.
* refactor: rename local schema vars for clarity
Rename schemaJSON/schema to openAPISchemaJSON/openAPISchema in the
cmdPredict/cmdTrain local-source paths to make the raw-bytes vs parsed
distinction explicit and match the BuildOptions.OpenAPISchema field.
* fix: align preflight validation with runtime schemas
* refactor: simplify input coercion
* test: cover oneOf/enum/not null branches; harden and dedup validation
Address adversarial review feedback:
- Add tests for the previously untested null-composition branches of
schemaAllowsNullWithoutNullable (oneOf exactly-one, enum null
containment, not) plus oneOf null rejection/acceptance through the
public ValidateInputMapForMode entry point, protecting preflight vs
runtime parity.
- Dedup the two identical quoting loops and four-way message branch in
validateKnownInputs into a quoteJoin helper.
- Harden missingRequiredInput to key off schemaErr.SchemaField
('required') before parsing the free-text reason.
- Document validation ownership across the three entry points and add a
defensive nil guard in NewInputsForMode.
* Clean up comments
* Document defensive walker
* consolidate integration tests
* fix: return nil instead of partial map on toMap error
* fix: handle incomplete input schemas safely
* fix: harden preflight input validation