Skip to content

feat: add JSON schema validation for devcontainer files#63

Closed
nozaq wants to merge 7 commits into
mainfrom
claude/json-schema-validation-xhgzq9
Closed

feat: add JSON schema validation for devcontainer files#63
nozaq wants to merge 7 commits into
mainfrom
claude/json-schema-validation-xhgzq9

Conversation

@nozaq

@nozaq nozaq commented Jul 25, 2026

Copy link
Copy Markdown
Member

This PR adds comprehensive JSON schema validation for devcontainer configuration files, complementing the existing rule-based linting engine.

Summary

Decolint now validates devcontainer.json, devcontainer-template.json, and devcontainer-feature.json files against the official Dev Container JSON schemas. The schemas are vendored from the upstream devcontainers/spec and microsoft/vscode repositories and embedded in the binary, requiring no network access.

Key Changes

  • New schema package: Provides schema validation via Validate() function that checks file structure, property names, value types, enums, and unknown properties

    • Supports three validation variants: "off" (disabled), "base" (spec only), and "main" (spec + VS Code + Codespaces extensions)
    • Generates user-friendly diagnostics with suggestions for misspelled properties using Levenshtein distance
    • Intelligently reduces error trees to surface the most relevant failures (e.g., at "oneOf"/"anyOf" nodes, reports only the best-matching branch)
  • Vendored schemas: Added five official JSON schemas to schema/data/:

    • devContainer.base.schema.json - core spec schema
    • devContainer.schema.json - main schema composing base + extensions
    • devContainerFeature.schema.json - feature metadata schema
    • devContainer.codespaces.schema.json - GitHub Codespaces extensions
    • devContainer.vscode.schema.json - VS Code extensions
    • REVISIONS.json - tracks upstream commit SHAs
  • Schema update tooling: Added internal/updateschemas command to refresh vendored schemas from upstream repositories, with automated CI workflow (schema-sync.yml) to detect stale schemas

  • Integration with linter:

    • Schema validation runs by default as a non-configurable pass (always enabled, not suppressible via rule severities)
    • New -schema flag and schema config file member to select validation variant
    • Validation errors reported as "schema-validation" findings with appropriate severity
    • Document offset calculation enhanced to position schema diagnostics correctly in source
  • Testing: Comprehensive test coverage for schema validation, error message generation, property name suggestions, and variant parsing

Implementation Details

  • Uses santhosh-tekuri/jsonschema/v6 for schema compilation and validation
  • Schemas are registered at their canonical GitHub URLs but resolved offline from embedded copies
  • VS Code schema internal references (machine settings, MCP config) are stubbed as permissive schemas since decolint validates structure, not VS Code settings
  • Error diagnostics intelligently suppress false positives (e.g., unknown-property errors when real value errors exist)
  • Version string now includes schema revision information

https://claude.ai/code/session_01DpyKDWbaKADMJ3kkyWKuN6

claude added 2 commits July 24, 2026 03:03
…chema

Validate devcontainer.json and Feature files against the vendored,
embedded official Dev Container schemas, catching the class of problems
the rules do not: misspelled or unknown property names, wrong value
types, and out-of-range enum values.

- New schema package: embeds the spec base/main/feature schemas plus the
  VS Code and Codespaces extension schemas, compiles them fully offline,
  and maps validation errors to source positions with "did you mean"
  suggestions for misspelled properties.
- The -schema flag and "schema" config member select the variant
  (main/base/off); main is the default. Findings are always errors under
  the schema-validation ID, independent of rule severities and ignore
  comments. Validation runs on the file as written, before merging and
  substitution.
- decolint -version now reports the vendored schema revision; the
  schema-sync workflow and "make update-schemas" keep the vendored copies
  current.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DpyKDWbaKADMJ3kkyWKuN6
…lidation-xhgzq9

# Conflicts:
#	cmd/decolint/main.go
#	cmd/decolint/main_test.go
#	cmd/decolint/opts.go
@nozaq nozaq changed the title Add JSON schema validation for devcontainer files feat: add JSON schema validation for devcontainer files Jul 25, 2026
claude added 5 commits July 25, 2026 04:31
golangci-lint's wrapcheck flagged the error from schema.ParseVariant as
returned unwrapped. Wrap it the way the surrounding code wraps
cross-package errors, and phrase the package's own message like
parseFormat's so the two compose without repeating "schema".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DpyKDWbaKADMJ3kkyWKuN6
The schema sync job only failed when the vendored schemas fell behind
upstream, leaving the update itself to be done by hand. Have it open a
pull request with the refreshed files instead, using the housekeeper app
token the way the templates repository's release workflow does.

The job's own token now only needs to read the repository, since every
write goes through the app token.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DpyKDWbaKADMJ3kkyWKuN6
Every main package now lives under cmd, so the schema updater sits
alongside the decolint binary rather than in internal. Only "make
update-schemas" referred to it; the released artifacts are unaffected,
since build and install name ./cmd/decolint explicitly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DpyKDWbaKADMJ3kkyWKuN6
The schema updater recorded the upstream commits on every run, so the
sync workflow would have raised a pull request whenever either branch
moved — and microsoft/vscode moves many times a day without touching a
schema. It now compares what it downloads against what is vendored and
writes nothing unless a schema itself differs.

The sources were also marshaled from a map, whose order json/v2 leaves
unspecified, so the file was reordered on every run and looked changed
either way. Marshal them deterministically, as the config file already
does for the same reason.

REVISIONS.json is regenerated here, so the committed file matches what
the updater produces: same schema contents, ordered sources, and the
commit those contents currently come from.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DpyKDWbaKADMJ3kkyWKuN6
The updateschemas binary landed in the previous commit; it is build
output, not source.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DpyKDWbaKADMJ3kkyWKuN6
@nozaq nozaq closed this Jul 25, 2026
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.

2 participants