feat(validation): JSON-Schema compile timeout + depth pre-scan#255
Closed
zeevdr wants to merge 1 commit into
Closed
feat(validation): JSON-Schema compile timeout + depth pre-scan#255zeevdr wants to merge 1 commit into
zeevdr wants to merge 1 commit into
Conversation
Lands the second half of #217 (security review finding 6): bound the JSON-Schema compiler so a malicious per-field constraint cannot hang the server during the first compile. Sits on top of #254, which already caps schema doc bytes and field count at the ingest layer. - internal/validation/limits.go — new Limits struct (CompileTimeout, MaxDepth) + DefaultLimits (5 s, depth 64) + shared Option/WithLimits pattern usable by both the factory and individual field validators. - internal/validation/json_schema.go — newJSONSchemaValidator now takes Limits. A pre-compile depth scan rejects pathological nesting before invoking the compiler; the Compile call itself runs in a goroutine and is bounded by CompileTimeout. jsonschema/v6 has no CompileContext, so the timeout is a wall-clock backstop — the goroutine may continue past the deadline, but the depth scan + upstream MaxDocBytes cap bound the worst-case work. - NewValidatorFactory(store, opts...) and NewFieldValidator(..., opts...) accept the shared Option type; existing zero-opt call sites continue to compile unchanged. - cmd/server reads SCHEMA_COMPILE_TIMEOUT (Go duration) and SCHEMA_MAX_REF_DEPTH env vars and threads them through WithLimits on the shared validator factory. Closes #217.
6 tasks
zeevdr
added a commit
that referenced
this pull request
Apr 29, 2026
…Service (#254) Lands the first half of #217: bound schema document size and field count at CreateSchema / ImportSchema, so a single malicious import cannot exhaust the server before validator caching helps. Compile-timeout for the JSON-Schema compiler ships in the stacked follow-up #255. - internal/schema/limits.go — new Limits struct (MaxFields, MaxDocBytes) + DefaultLimits (10 000 fields, 5 MiB). - schema.NewService(store, opts...) — store stays positional; logger, metrics, validators, and limits move to With...() options. Mirrors the config / audit / auth / server functional-options sweep from #235, #236, #249. - ImportSchema rejects YAML payloads above MaxDocBytes before parsing, and CreateSchema / ImportSchema reject schemas above MaxFields after parsing. Zero on either dimension means unlimited. - cmd/server reads SCHEMA_MAX_FIELDS and SCHEMA_MAX_DOC_BYTES env vars and threads them through WithLimits. Both documented in docs/server/configuration.md. Refs #217.
5 tasks
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.
Summary
json_schemaconstraint cannot hang the server on first compile.validation.Limits(CompileTimeout,MaxDepth) with a sharedOption/WithLimitspattern — same option type works for bothNewValidatorFactoryandNewFieldValidator.DefaultLimitsis 5 s + depth 64.CompileTimeout. Becausejsonschema/v6has noCompileContext, the timeout is a wall-clock backstop — the goroutine may continue past the deadline, but the pre-scan plus the upstreamMaxDocBytescap (feat(schema): configurable ingest limits + functional options for NewService #254) bound the worst-case work.cmd/serverreadsSCHEMA_COMPILE_TIMEOUT(Go duration) andSCHEMA_MAX_REF_DEPTHenv vars and threads them through the shared validator factory.Test plan
make pre-commit(build, vet, format, lint, test, coverage)internal/validation/json_schema_test.gocover:DefaultLimits, depth-exceeded rejection, depth-disabled (MaxDepth: 0), malformed-JSON falls through to compiler, timeout-zero-is-unbounded, and directscanJSONDepthcases (objects, arrays, non-JSON)factory_concurrent_test.go/validator_bench_test.go/cache_race_test.gocallers continue to compile (zero-opt form preserved)SCHEMA_COMPILE_TIMEOUTandSCHEMA_MAX_REF_DEPTHdocumented indocs/server/configuration.md.agents/context/security-review.mdupdated — finding 6 now marked complete across both halvesCloses #217. Merge after #254.
🤖 Generated with Claude Code