Skip to content

ValidateOpenAPIDocument mutates the caller's yaml.Node tree when rendering a violation (data race / order-dependent results when rules run concurrently) #322

Description

@ddkwing

Summary

When schema_validation.ValidateOpenAPIDocument builds a SchemaValidationFailure, it renders the located node with yaml.Marshal(located) (schema_validation/validate_document.go, around line 381 in v0.14.0). located is a node from the document's own tree, not a copy.

go.yaml.in/yaml/v4 (v4.0.0-rc.6) mutates the node it is given while encoding: it rewrites Tag and Style on it and its descendants. So rendering a violation writes to the caller's tree.

In vacuum this tree is shared. oas3-schema (which calls ValidateOpenAPIDocument) and oas3-valid-schema-example run concurrently in the motor's worker pool and read the same nodes. That has two effects:

  1. go test -race reports a data race between the two rules. Our code does not appear in the stack.
  2. The results depend on which rule runs first. On one real-world spec (~2.5k lines, OpenAPI 3.1), 40 runs of the recommended ruleset produced 3–4 distinct result sets. One oas3-valid-schema-example finding ("got object, want null", on a schema with allOf: [$ref] plus type: null) appears in some runs and not in others, and the order of oas3-schema sub-errors changes. Specs that produce no oas3-schema violations are fully stable, which fits the explanation that the mutation only happens on the error-rendering path.

Expected

Rendering a violation should not modify the document being validated. It should be read-only on the input tree.

Suggested fix

Marshal a deep copy of located instead of the node itself. Alternatively, render it without going through the encoder's tag/style resolution.

Versions

  • github.com/pb33f/libopenapi v0.38.7
  • github.com/pb33f/libopenapi-validator v0.14.0
  • github.com/daveshanley/vacuum v0.30.6
  • go.yaml.in/yaml/v4 v4.0.0-rc.6
  • Go 1.26.0 (darwin/arm64 locally, linux in CI)

Reproduction

Any OpenAPI 3.x document with a schema violation that oas3-schema reports, linted by vacuum's recommended ruleset via motor.ApplyRulesToRuleSet under go test -race. I can provide a minimised spec if that helps. The real one is internal.

cc @daveshanley, since this shows up through vacuum's motor.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions