Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loadYamlContent(..) converts unset properties (should be: null) to empty strings ('') #14143

Open
headcr4sh opened this issue May 24, 2024 · 3 comments
Milestone

Comments

@headcr4sh
Copy link

Bicep version
Bicep CLI version 0.27.1 (4b41cb6d4b)

Describe the bug
While using a combination of loadYamlContent() in conjunction with union() and string() to construct an OpenTelemetry Collector configuration file (don't ask...!) I stumbled upon a rather interesting bug:

yamlTest.bicep:

targetScope = 'subscription'

// expected: `{"toplevel":{"nested1":null,"nested2":null,"nested3":""}}`
// got: `{"toplevel":{"nested1":"","nested2":null,"nested3":""}}`
var yamlAsString = string(loadYamlContent('./example.yaml'))

example.yaml:

toplevel:
  nested1:
  nested2: null
  nested3: ''

To Reproduce
Steps to reproduce the behavior:
Create the two files as described above and use bicep to build the ARM template, e.g. by using the following shell script:

cat <<EOF > ./example.yaml
toplevel:
  nested1:
  nested2: null
  nested3: ''
EOF

cat <<EOF > ./yamlTest.bicep
targetScope = 'subscription'

// expected: '{"toplevel":{"nested1":null,"nested2":null,"nested3":""}}'
// got: '{"toplevel":{"nested1":"","nested2":null,"nested3":""}}'
#disable-next-line no-unused-vars
var yamlAsString = string(loadYamlContent('./example.yaml'))
EOF

az bicep build --file ./yamlTest.bicep --outfile ./yamlTest.out.json
jq -r '.variables' ./yamlTest.out.json

# Now: just compare the contents of the variable with the given YAML input

Additional context
Mitigation in my case was to explicitly set the properties to null, but it was kind of counter-intuitive and took me some time to figure out that Bicep's loadYamlContent() was doing something unexpected.

@ahelland
Copy link

From what I can tell after a quick debug lookup is that the Yaml deserialization is handled by a third-party library called SharpYaml (https://github.com/xoofx/SharpYaml/tree/master) which happens to treat an empty value the same as ''.

@headcr4sh
Copy link
Author

headcr4sh commented May 24, 2024

I just had a look at the YAML 1.2.2 specification:

YAML allows the node content to be omitted in many cases. Nodes with empty content are interpreted as if they were plain scalars with an empty value. Such nodes are commonly resolved to a “null” value.

Example 7.3: Completely Empty Flow Nodes seems to further clarify how empty node content should be resolved.

I tried different YAML parsers (e.g. yq, pyyaml and Go's yaml/v2 package, which is based on LibYYAML) and it seems as if most parsers resolve empty node values to null, whereas SharpYaml seems indeed to be a notable exception which I assume handles things in an unexpected way which is not in line with the spec.

EDIT:
Raised an issue in the SharpYaml repo: #119

@anthony-c-martin
Copy link
Member

Thanks for digging into this!

@stephaniezyen stephaniezyen added this to the Committed Backlog milestone Jun 5, 2024
@stephaniezyen stephaniezyen modified the milestones: Committed Backlog, v1.1 Jun 5, 2024
@stephaniezyen stephaniezyen moved this from Todo to Blocked in Bicep Jun 5, 2024
@stephaniezyen stephaniezyen modified the milestones: v1.1, v1.0 Jun 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Blocked
Development

No branches or pull requests

4 participants