Skip to content

Reject Yaml tags and explicit keys, resolve alias keys, and keep non-space white space - #10276

Open
effect-bot wants to merge 17 commits into
v4/next-minorfrom
agent/nelson-effect-bot/eff-3232-stage3-hardening
Open

effect-bot wants to merge 17 commits into
v4/next-minorfrom
agent/nelson-effect-bot/eff-3232-stage3-hardening

Conversation

@effect-bot

Copy link
Copy Markdown
Contributor

Stage 3 of the YAML expansion. Yaml.parse and Yaml.parseAll used to read some input as text and return a wrong value without any error. This PR either rejects that input or parses it correctly.

This branch is built on #10271 (stage 1), which hasn't merged yet. Until it does, this PR also shows the stage 1 commits. Only the last two commits belong to this stage.

Behavior

  • Tags fail. a: !!str 123 used to give "!!str 123", and !!str a: 1 gave the key "!!str a". Now every tag is rejected: core, local, non-specific and verbatim tags, on values, keys, collections and flow items. Resolving core tags is planned as a separate change. A ! inside a plain scalar (x!y, hello!) is still text.
  • Alias keys. *name : value now uses the anchored scalar as the key; a number becomes its string form. Before, the key was the literal text "*name". An alias to a collection used as a key fails. An alias key needs a space before the :, because : is a valid character in an anchor name. That matches yaml 2.9.1.
  • Explicit keys fail with a clear error: block ? key, the flow mapping form {? a : 1} and the flow sequence form [? a]. The flow forms used to give the keys "? a".
  • Nesting depth. Collections can be nested up to 1000 levels deep; block and flow count together. Deeper input fails with an EncodingError instead of a stack overflow.
  • White space. YAML 1.2.2 §5.5 treats only spaces and tabs as white space. The parser used JavaScript's trim() and \s, which also removed no-break spaces (U+00A0), U+2028, U+3000 and similar characters from values and keys. It also treated # after them as the start of a comment. Those characters are now kept as content, and the results match yaml 2.9.1.

Integers beyond Number.MAX_SAFE_INTEGER still lose precision under JavaScript number semantics. The docs now say so and suggest quoting such values.

Docs

  • The module header lists what is rejected and the limits that remain.
  • The parse JSDoc covers tags, explicit keys, the depth limit, alias keys and precision. Its example has a rejected tag.
  • .changeset/yaml-parser-hardening.md is the release note.

Validation

  • Yaml.test.ts: 216 of 217 pass.
    • The failing test, "rejects deeper block nesting", has a bug in its input generator: 100,000 levels of indentation make a string of about 5 × 10⁹ characters, so it throws RangeError: Invalid string length before parsing starts.
    • The parser part of that test passes: 1001 levels fail with the depth error, and so do 3000 to 5000 levels of block mappings or sequences.
    • The test will be fixed in a separate run.
  • YAML, CLI, Skills, ai-codegen and openapi-generator tests: 860 passed, 3 skipped, plus the test above.
  • pnpm lint, pnpm jsdocs --check and the Yaml.ts doctests pass.
  • pnpm check reports one error, the apiStabilityLeak in cluster/ShardingRegistrationEvent.ts, which also occurs on v4/next-minor.

Closes EFF-3232

Rebased onto v4/next-minor, which already returns Result from Yaml.parse
(#10224). parseAll parses document streams with per-document anchors,
accepts %YAML 1.2, and rejects other directives and plain scalars
starting with '%'.
Start-marker lines read as mapping entries, anchor-only documents
consuming the next marker, hashes inside quoted start-line content, and
separation whitespace after '...' and directive parameters.
Block mappings and sequences end at column-0 document markers, an empty
node does not consume a following marker, start-marker content is
comment-stripped in its own lexical context, and trailing separation
whitespace is allowed after '...' and directive parameters.
A byte order mark may start any document prefix, and only spaces and
tabs separate a document end marker from a comment.
A BOM may start any document prefix, not only the input. Only spaces
and tabs are separation after '...' and directive parameters.
Replace the document marker checks scattered through mapping, sequence,
empty node, flow, plain, quoted and block scalar parsing with one
per-document line bound computed when the document starts.
findIndex from the start of the input made a stream of many documents
quadratic; a forward loop from the current line keeps it linear.
Tags, alias keys, explicit keys, nesting depth, and non-separation
whitespace (NBSP, U+2028) that is currently trimmed as if it were
YAML white space.
Reject tags and explicit keys instead of reading them as text, resolve
scalar aliases used as mapping keys, bound collection nesting at 1000
levels, and treat only spaces and tabs as YAML white space.
@changeset-bot

changeset-bot Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3c4abc8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 33 packages
Name Type
effect Minor
@effect/opentelemetry Minor
@effect/vitest Minor
@effect/ai-anthropic Minor
@effect/ai-cloudflare Minor
@effect/ai-openai-compat Minor
@effect/ai-openai Minor
@effect/ai-openrouter Minor
@effect/ai-typesafe Minor
@effect/atom-react Minor
@effect/atom-solid Minor
@effect/atom-vue Minor
@effect/platform-browser Minor
@effect/platform-bun Minor
@effect/platform-deno Minor
@effect/platform-node-shared Minor
@effect/platform-node Minor
@effect/sql-clickhouse Minor
@effect/sql-d1 Minor
@effect/sql-libsql Minor
@effect/sql-mssql Minor
@effect/sql-mysql2 Minor
@effect/sql-pg Minor
@effect/sql-pglite Minor
@effect/sql-sqlite-bun Minor
@effect/sql-sqlite-do Minor
@effect/sql-sqlite-node Minor
@effect/sql-sqlite-react-native Minor
@effect/sql-sqlite-wasm Minor
@effect/docgen Minor
@effect/doctest Minor
@effect/graphql-generator Minor
@effect/openapi-generator Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
arbitrary-combinators.ts 39.35 KB 39.35 KB 0.00 KB (0.00%)
basic.ts 7.18 KB 7.18 KB 0.00 KB (0.00%)
batching.ts 11.06 KB 11.06 KB 0.00 KB (0.00%)
brand.ts 6.84 KB 6.84 KB 0.00 KB (0.00%)
cache.ts 11.49 KB 11.49 KB 0.00 KB (0.00%)
config.ts 22.77 KB 22.77 KB 0.00 KB (0.00%)
differ.ts 21.92 KB 21.92 KB 0.00 KB (0.00%)
http-client.ts 26.90 KB 26.90 KB 0.00 KB (0.00%)
http-router.ts 36.88 KB 36.88 KB 0.00 KB (0.00%)
logger.ts 11.96 KB 11.96 KB 0.00 KB (0.00%)
metric.ts 9.42 KB 9.42 KB 0.00 KB (0.00%)
optic.ts 7.05 KB 7.05 KB 0.00 KB (0.00%)
pubsub.ts 15.97 KB 15.97 KB 0.00 KB (0.00%)
queue.ts 12.77 KB 12.77 KB 0.00 KB (0.00%)
schedule.ts 11.74 KB 11.74 KB 0.00 KB (0.00%)
schema-bigdecimal.ts 14.02 KB 14.02 KB 0.00 KB (0.00%)
schema-binary.ts 41.06 KB 41.06 KB 0.00 KB (0.00%)
schema-class.ts 21.65 KB 21.65 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 29.51 KB 29.51 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 27.91 KB 27.91 KB 0.00 KB (0.00%)
schema-string-transformation.ts 15.27 KB 15.27 KB 0.00 KB (0.00%)
schema-string.ts 12.26 KB 12.26 KB 0.00 KB (0.00%)
schema-template-literal.ts 16.19 KB 16.19 KB 0.00 KB (0.00%)
schema-toArbitrary.ts 38.87 KB 38.87 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 26.10 KB 26.10 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 20.83 KB 20.83 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 20.97 KB 20.97 KB 0.00 KB (0.00%)
schema-toFormatter.ts 21.07 KB 21.07 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 26.11 KB 26.11 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 21.16 KB 21.16 KB 0.00 KB (0.00%)
schema.ts 20.75 KB 20.75 KB 0.00 KB (0.00%)
stm.ts 14.15 KB 14.15 KB 0.00 KB (0.00%)
stream.ts 10.33 KB 10.33 KB 0.00 KB (0.00%)

Sequence-item mapping depth, alias keys resolving to '<<' in flow
mappings, anchor and tag properties on keys, colons in alias names, and
U+2028/U+2029 in anchored values.
Trim and fold white space with linear scans, count a sequence item's
mapping before its first value, read anchors and tags on keys, keep
colons in alias names, merge only through a plain '<<' key, and keep
U+2028/U+2029 in anchored values.
Share one scalar-key resolver between block and flow mappings, read plain
flow scalars and keys through one helper that rejects indicator prefixes,
name the flow anchor-name boundary once, and add the flow-key quoting
migration note to the changeset.

This branch has not been deployed

No deployments
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