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

Type flags are lost when value is transformed via runtime function #9714

Open
santi opened this issue Feb 1, 2023 · 5 comments
Open

Type flags are lost when value is transformed via runtime function #9714

santi opened this issue Feb 1, 2023 · 5 comments
Labels
enhancement New feature or request type system
Milestone

Comments

@santi
Copy link

santi commented Feb 1, 2023

Bicep version
Bicep CLI version 0.14.6 (f1dae16)

Describe the bug
Since the latest release (v0.14.6) of the Bicep CLI, type narrowing is being applied when using the @allowed decorator on parameters. According to the official docs, these constraints should be applied when an argument is passed into the param.

With the recent change (in v0.14.6), the type for the parameter now becomes the union of the literals supplied in the @allowed decorator, which makes compilation fail when trying to supply any value that is not one of the exact types present in the union type, even when the value of the argument is actually the correct value.

AFAIK there are no ways to cast variables to a specific type (so that we can provide the value as an argument to the parameter with the correct type) which breaks the possibility of using any functions for string manipulation, because the returned type is always string, and can thus not be given as an argument to the param.

I believe this is an (unintended?) bug, and should be reverted to the previous behaviour of not changing the actual type of the parameter, and instead just apply the constraints during validation of the template.

To Reproduce
Steps to reproduce the behavior:

// module1.bicep
@allowed([ 'dev', 'prod' ])
param env string
// main.bicep
param inputWithEnvSuffix string // e.g. 'something-dev'
var environment = split(inputWithEnvSuffix, '-')[1]

module mod './module1.bicep' {
  name: 'some name'
  params: {
    env: environment
  }
}

yields the following error in main.bicep:
The property "env" expected a value of type "'dev' | 'prod'" but the provided value is of type "string".bicep(BCP036)

Additional context
This worked fine in Bicep CLI version 0.12.1 (e43d137)

@ghost ghost added the Needs: Triage 🔍 label Feb 1, 2023
@jeskew
Copy link
Contributor

jeskew commented Feb 1, 2023

0.14 included an update to the signature of split, which is now understood by the type checker to return an array of strings rather than an untyped array. This means that split(inputWithEnvSuffix, '-')[1] has been changed from any to string, causing the error reported.

There's a special flag on string parameters that permits "loose" matching, which is why the following will work with Bicep 0.14 or 0.12:

param environment string

module mod './module1.bicep' {
  name: 'some name'
  params: {
    env: environment
  }
}

That flag gets dropped when the parameter is passed to any function, but it shouldn't be.

@jeskew
Copy link
Contributor

jeskew commented Feb 1, 2023

By the way, a workaround you can use immediately is the any function:

param inputWithEnvSuffix string // e.g. 'something-dev'
var environment = split(inputWithEnvSuffix, '-')[1]

module mod './module1.bicep' {
  name: 'some name'
  params: {
    env: any(environment)
  }
}

This will update the types used to be equivalent to those in Bicep 0.12, where split(...)[1] will always be of type any.

On our side, we'll look into how/whether to propagate flags through function invocations.

@santi
Copy link
Author

santi commented Feb 2, 2023

Thank you for the explanation and workaround! I'll use the any() function for now, would love to hear whether or not you decide on propagating flags through the split function

@stephaniezyen stephaniezyen added discussion This is a discussion issue and not a change proposal. and removed Needs: Triage 🔍 labels Feb 8, 2023
@jeskew
Copy link
Contributor

jeskew commented Feb 8, 2023

Notes from the team discussion:

  • The two flags that should exhibit some form of propagation/taint tracking are AllowLooseAssignment and IsSecure.
    • AllowLooseAssignment
      • Any symbol whose type bears the AllowLooseAssignment flag will not have its value known until runtime, so a general approach of applying the flag to the return type of a function if any of the function arguments had that flag makes sense.
      • There are some special cases that should not propagate flags, e.g., int(), string(), and other type-cast functions.
    • IsSecure
      • In general, anything derived from a secure value should itself be treated as secure.
        • Type cast functions like string() are an exception.
      • Aggregate values should be aware that they contain secure values, but the IsSecure flag should not taint sibling properties. For example, in the following snippet, secret, derived, hasSecureElements, and iShouldBeSecure should be considered secure, but iShouldNotBeSecure should not.
        @secure()
        param secret string
        
        var dervied = toLower(secret)
        
        var hasSecureElements = {
         key: secret
         anotherKey: 'some string'
        }
        
        var iShouldBeSecure = hasSecureElements.key
        
        var iShouldNotBeSecure = hasSecureElements.anotherKey
      • IDE hovers/tooltips on secure values should indicate that the value is secure (they currently do not)

@jeskew jeskew added type system enhancement New feature or request and removed discussion This is a discussion issue and not a change proposal. labels Feb 8, 2023
@jeskew jeskew added this to the v1.0 milestone Feb 8, 2023
@jeskew jeskew added this to Bicep Feb 8, 2023
@github-project-automation github-project-automation bot moved this to Todo in Bicep Feb 8, 2023
@jeskew jeskew changed the title @allowed decorator narrows types and ignores declared type of param Type flags are lost when value is transformed via runtime function Feb 8, 2023
@santi
Copy link
Author

santi commented Feb 9, 2023

@jeskew Thank you again for the detailed follow-up! What you have discussed and noted down totally makes sense in terms of what I would expect from the Bicep type system. 💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request type system
Projects
Status: Todo
Development

No branches or pull requests

3 participants