Skip to content

Always validate YAML - #121

Merged
votdev merged 1 commit into
harvester:masterfrom
votdev:issue_9164_validate_yaml
Apr 28, 2026
Merged

votdev merged 1 commit into
harvester:masterfrom
votdev:issue_9164_validate_yaml

Conversation

@votdev

@votdev votdev commented Apr 8, 2026 •

Copy link
Copy Markdown
Member

Problem:

The content of the CR is not parsed when the filename has not been modified.

Solution:

  • Always parse spec.contents.
  • Switch to go.yaml.in/yaml/v4 because gopkg.in/yaml.v3 is not maintained anymore.

Related Issue(s):

harvester/harvester#9164

Test plan:

Case 1

  • Create the file cloudinit-passwd.yaml with the content:
apiVersion: node.harvesterhci.io/v1beta1
kind: CloudInit
metadata:
  name: passwd
spec:
  matchSelector: {}
  filename: 99_passwd.yaml
  contents: |
    stages:
      initramfs.after:
        - users:
            rancher:
              passwd: 1234
  • Run kubectl apply -f ./cloudinit-passwd.yaml.
  • Run ls -alh /oem on any node of the cluster. The output should look like:
harvester-node-0:/home/rancher # ls -alh /oem
total 154K
drwxr-xr-x   4 root root 1.0K Apr  9 10:19 .
drwxr-xr-x  18 root root 4.0K Apr  2 07:09 ..
-rw-rw-rw-.  1 root root 128K Apr  2 07:06 90_custom.yaml
-rw-------.  1 root root   68 Apr  9 10:19 99_passwd.yaml
-rw-r--r--.  1 root root  258 Apr  9 10:01 99_settings.yaml
-rw-r--r--.  1 root root  258 Apr  9 10:01 99_settings.yaml.bak
-rw-------.  1 root root  587 Apr  2 07:07 elemental.config
-rw-r--r--.  1 root root    0 Apr  2 07:09 grubcustom
-rw-r--r--.  1 root root 1.0K Apr  2 07:09 grubenv
-rw-------.  1 root root 2.9K Apr  2 07:07 harvester.config
drwxr-xr-x.  2 root root 1.0K Apr  2 07:09 install
drwx------   2 root root  12K Apr  2 07:06 lost+found
  • Run cat /oem/99_passwd.yaml on any node of the cluster. The output should look like:
harvester-node-0:/home/rancher # cat /oem/99_passwd.yaml 
stages:
  initramfs.after:
    - users:
        rancher:
          passwd: 1234

Case 2

  • Modify the file cloudinit-passwd.yaml created in test case 1 and change the password.
  • Apply the modification by running kubectl apply -f ./cloudinit-passwd.yaml.
  • On a node, run cat /oem/99_passwd.yaml. The new password should be shown.
    Case 3
  • Create the file cloudinit-bad-document.yaml with the content:
apiVersion: node.harvesterhci.io/v1beta1
kind: CloudInit
metadata:
  name: bad-document
spec:
  matchSelector: {}
  filename: 99_bad-document.yaml
  contents: |
    Hello, world
  • Run kubectl apply -f ./cloudinit-bad-document.yaml. The output should look like:
Error from server (InternalError): error when creating "./cloudinit-bad-document.yaml": admission webhook "validator.harvester-system.harvester-node-manager-webhook" denied the request: Internal error occurred: could not parse document as yaml
  • The file should not be created on the cluster nodes. Validate that by running ls -alh /oem/99_bad-document.yaml on any node, which should fail.
harvester-node-0:/home/rancher # ls -alh /oem/99_bad-document.yaml
ls: cannot access '/oem/99_bad-document.yaml': No such file or directory

Additional documentation or context

@votdev
votdev force-pushed the issue_9164_validate_yaml branch from ede39fa to 4fc2d0b Compare April 8, 2026 11:20
@votdev
votdev marked this pull request as ready for review April 9, 2026 11:24
@votdev
votdev requested review from a team, brandboat and tserong as code owners April 9, 2026 11:24
Copilot AI review requested due to automatic review settings April 9, 2026 11:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the CloudInit admission validation so spec.contents is always parsed/validated (even when spec.filename is unchanged) and tightens validation to require a YAML document with a mapping at the root. It also introduces go.yaml.in/yaml/v4 (vendored) as the YAML parser to enable parsing into yaml.Node for structure validation.

Changes:

  • Remove the update-time early return and always validate spec.contents; adjust duplicate-filename checks to ignore the object being updated.
  • Add/extend tests to cover the update regression and YAML-structure validation behavior.
  • Vendor go.yaml.in/yaml/v4 and update go.mod/go.sum/vendor/modules.txt accordingly.

Reviewed changes

Copilot reviewed 3 out of 35 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/admitter/cloudinit.go Always validates contents; ignores self in duplicate filename check; adds YAML structure validation via yaml.Node.
pkg/admitter/cloudinit_test.go Adds regression coverage for update behavior and unit tests for the new YAML validation helper.
go.mod Adds dependency on go.yaml.in/yaml/v4 v4.0.0-rc.4 and adjusts YAML deps.
go.sum Adds checksums for go.yaml.in/yaml/v4.
vendor/modules.txt Records vendored go.yaml.in/yaml/v4 module entries.
vendor/go.yaml.in/yaml/v4/yaml.go Vendored YAML v4 API surface and classic APIs.
vendor/go.yaml.in/yaml/v4/loader.go Vendored loader implementation used by the webhook (NewLoader, Load).
vendor/go.yaml.in/yaml/v4/dumper.go Vendored dumper implementation (supporting the library’s API completeness).
vendor/go.yaml.in/yaml/v4/doc.go Vendored package docs describing v4 options and behavior.
vendor/go.yaml.in/yaml/v4/README.md Vendored upstream README for yaml v4.
vendor/go.yaml.in/yaml/v4/LICENSE Vendored upstream license text.
vendor/go.yaml.in/yaml/v4/NOTICE Vendored upstream notice file.
vendor/go.yaml.in/yaml/v4/CONTRIBUTING.md Vendored upstream contributing guide.
vendor/go.yaml.in/yaml/v4/GNUmakefile Vendored upstream build/test automation.
vendor/go.yaml.in/yaml/v4/.gitignore Vendored upstream ignore rules.
vendor/go.yaml.in/yaml/v4/.typos.toml Vendored upstream spelling/typos tool config.
vendor/go.yaml.in/yaml/v4/internal/libyaml/api.go Vendored libyaml API helpers.
vendor/go.yaml.in/yaml/v4/internal/libyaml/composer.go Vendored composer producing node trees for loaders.
vendor/go.yaml.in/yaml/v4/internal/libyaml/doc.go Vendored internal package docs.
vendor/go.yaml.in/yaml/v4/internal/libyaml/errors.go Vendored YAML error types used by loader/constructor paths.
vendor/go.yaml.in/yaml/v4/internal/libyaml/node.go Vendored node representation used for structure validation.
vendor/go.yaml.in/yaml/v4/internal/libyaml/options.go Vendored options system used by loader/dumper defaults.
vendor/go.yaml.in/yaml/v4/internal/libyaml/reader.go Vendored reader/encoding logic used by parser.
vendor/go.yaml.in/yaml/v4/internal/libyaml/representer.go Vendored representer for marshaling (library completeness).
vendor/go.yaml.in/yaml/v4/internal/libyaml/resolver.go Vendored scalar resolver (tag/type resolution).
vendor/go.yaml.in/yaml/v4/internal/libyaml/serializer.go Vendored serializer stage for emitting.
vendor/go.yaml.in/yaml/v4/internal/libyaml/writer.go Vendored writer buffering for emitter.
vendor/go.yaml.in/yaml/v4/internal/libyaml/yaml.go Vendored core types/constants for parser/emitter.
vendor/go.yaml.in/yaml/v4/internal/libyaml/yamlprivate.go Vendored internal constants/helpers.
vendor/go.yaml.in/yaml/v4/internal/libyaml/yamldatatest_loader.go Vendored test-data loader utility from upstream.
vendor/go.yaml.in/yaml/v4/internal/libyaml/README.md Vendored internal libyaml documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/admitter/cloudinit.go Resolved
Comment thread pkg/admitter/cloudinit_test.go Resolved
Comment thread pkg/admitter/cloudinit_test.go Resolved
Comment thread go.mod Resolved

@brandboat brandboat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the patch!

Comment thread pkg/admitter/cloudinit.go Resolved
Comment thread pkg/admitter/cloudinit.go Resolved
Comment thread pkg/admitter/cloudinit.go Resolved
@votdev
votdev force-pushed the issue_9164_validate_yaml branch 4 times, most recently from 9a90268 to 9cedb9b Compare April 22, 2026 11:48
brandboat
brandboat previously approved these changes Apr 23, 2026

@brandboat brandboat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

tserong
tserong previously approved these changes Apr 23, 2026

@tserong tserong left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The only thing I wondered about was the bump to go.yaml.in/yaml/v4, but if we're moving that way anyway (harvester/harvester#10355) including it here makes sense. I did just notice though that pkg/utils/oem.go has a "gopkg.in/yaml.v1" - probably should bump that one too.

Additional improvements:
- Switch to `go.yaml.in/yaml/v4` because `gopkg.in/yaml.v(1|3)` is not maintained anymore.

Related to: harvester/harvester#9164

Signed-off-by: Volker Theile <vtheile@suse.com>
@votdev
votdev dismissed stale reviews from tserong and brandboat via 9595b71 April 27, 2026 14:23
@votdev
votdev force-pushed the issue_9164_validate_yaml branch from 9cedb9b to 9595b71 Compare April 27, 2026 14:23
@votdev

votdev commented Apr 27, 2026

Copy link
Copy Markdown
Member Author

LGTM. The only thing I wondered about was the bump to go.yaml.in/yaml/v4, but if we're moving that way anyway (harvester/harvester#10355) including it here makes sense. I did just notice though that pkg/utils/oem.go has a "gopkg.in/yaml.v1" - probably should bump that one too.

Fixed

@votdev
votdev merged commit 0a821b1 into harvester:master Apr 28, 2026
7 checks passed
@votdev
votdev deleted the issue_9164_validate_yaml branch April 28, 2026 06:31
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.

4 participants