microsoft / PSRule

Validate infrastructure as code (IaC) and objects using PowerShell rules.
https://microsoft.github.io/PSRule/v2/
MIT License
396 stars 49 forks source link

Challenges with nullable types #1640

Closed AlexanderSehr closed 11 months ago

AlexanderSehr commented 1 year ago

Description of the issue

When creating a Bicep module with nullable parameters which is referenced and tested via another Bicep file, we encountered some issues running PSRule on that test file.

I created a simplified module to reproduce the issue - which in turn is tested using a CI environment that runs the PS Rule GitHub action.

Consider the following structure

We discovered that implementations like param minimumTlsVersion string? or param roleAssignments roleAssignmentType (where the type is nullable) cause PSRule to fail. Maybe it's a misconfiguration on our part, but we've not been able to find out why.

We did find a workaround: If we specify nullable values in the test case it works - even if we just hand them over with a null value (e.g., minimumTlsVersion: null)

To Reproduce

Steps to reproduce the issue:

Expected behaviour

Error output

Using the above workaround I ran tests with different combinations in the pipeline as linked below:

Module in use and version:

Captured output from $PSVersionTable:

Name                           Value
----                           -----
PSVersion                      7.3.7
PSEdition                      Core
github-actions[bot] commented 1 year ago

Thanks for raising your first issue, the team appreciates the time you have taken 😉

BernieWhite commented 1 year ago

@AlexanderSehr Thanks for reporting this. I can see the issue. Thanks for the reproduction.

AlexanderSehr commented 1 year ago

@BernieWhite, with the issues closed, do you already know when the fix would become available? I guess it'll require a release first.

BernieWhite commented 1 year ago

@AlexanderSehr stable release is imminent (https://github.com/Azure/PSRule.Rules.Azure/pull/2525). However, you can try it out, from pre-release v1.31.0-B0048.

AlexanderSehr commented 1 year ago

cc: @eriqua Updates incoming (:

BernieWhite commented 1 year ago

Fixed with PSRule for Azure release v1.31.0.

AlexanderSehr commented 12 months ago

Hey @BernieWhite any chance we could re-open the issue?

For us on the CARML/AVM-side the issue still persists with the new version. For reference, this was the original error we came across with version 1.29.0:

Error: Failed to expand bicep source '/home/runner/work/bicep-registry-modules/bicep-registry-modules/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep'. Exception calling "GetBicepResources" with "2" argument(s): "Unable to expand resources because the source file '/home/runner/work/bicep-registry-modules/bicep-registry-modules/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep' was not valid. An error occurred evaluating expression '[length(coalesce(parameters('accessPolicies'), createArray()))]' line 611. The parameter named 'accessPolicies' was not set or a defaultValue was defined."

and this is the one we come across with version 1.31.0:

Error: Failed to expand bicep source '/home/runner/work/bicep-registry-modules/bicep-registry-modules/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep'. Exception calling "GetBicepResources" with "2" argument(s): "Unable to expand resources because the source file '/home/runner/work/bicep-registry-modules/bicep-registry-modules/avm/res/key-vault/vault/tests/e2e/defaults/main.test.bicep' was not valid. An error occurred evaluating expression '[length(variables('secretList'))]' line 849. An error occurred evaluating expression '[coalesce(tryGet(parameters('secrets'), 'secureList'), createArray())]' line 630. Cannot access child value on Newtonsoft.Json.Linq.JValue."

I'll attribute the different parameter it's complaining about to the fact that the module continued to be worked on since the original run and maybe the parameter order changed.

In either case, the issue that we have a parameter like

@description('Optional. All access policies to create.')
param accessPolicies array?

@description('Optional. All secrets to create.')
@secure()
param secrets object?

that is used in a logic like

var formattedAccessPolicies = [for accessPolicy in (accessPolicies ?? []): { (...) }

var secretList = secrets.?secureList ?? []

For reference, what the logic does in either case is to use the coalesce feature to check if a parameter is null, and if so default to an empty array (I guess the same would be true if it were an object).

BernieWhite commented 11 months ago

@AlexanderSehr Additional fixes in v1.31.3.