Skip to content

[Feature Request] Extend @optional decorator with groups #1096

Open

Description

@wrong7

Description

Allow @optional decorators to include an argument to define a group so that a whole group is either defined or not.

Example

# Microsoft OAuth client. Set together with its secret and tenant.
# @optional(microsoft)
MICROSOFT_CLIENT_ID=

# Secret belonging to the Microsoft OAuth client above.
# @sensitive @optional(microsoft)
MICROSOFT_CLIENT_SECRET=

This will throw if only one of the group variables is defined

Motivation

It is common to have multiple variables that are optional as a whole, but required if one is defined

Proposed Solution

No response

Alternatives

A new decorator defining the name and the included variables

# @optionalGroup(google, GOOGLE_DRIVE_CLIENT_ID, GOOGLE_DRIVE_CLIENT_SECRET)

Additional Information

No response

Activity

  1. pullfrog commented on Sep 17, 2026

    @pullfrog
    Contributor
  2. theoephraim commented on Sep 18, 2026

    @theoephraim
    Member

    I realize it's not exactly the same, but why not just base requiredness off of one key item in the group

    # @optional
    MICROSOFT_CLIENT_ID=
    
    # @sensitive @required=if($MICROSOFT_CLIENT_ID)
    MICROSOFT_CLIENT_SECRET=
    

    Or add another internal var to track intent more clearly

    # @internal
    ENABLE_MICROSOFT=false
    
    # @required=if($ENABLE_MICROSOFT)
    MICROSOFT_CLIENT_ID=
    
    # @sensitive @required=if($ENABLE_MICROSOFT)
    MICROSOFT_CLIENT_SECRET=
    
  3. wrong7 commented on Sep 18, 2026

    @wrong7
    Author

    Yes that would work but only one way. If you define MICROSOFT_SECRET_KEY but not MICROSOFT_CLIENT_KEY nothing would tell you one is missing.

    The second aproach requires a new variable, sure it works but it's not very elegant.

    What this request is about is just QoL honestly

  4. theoephraim commented on Sep 18, 2026

    @theoephraim
    Member

    Yeah I see the point. Just not positive it's worth adding another way to do it. The explicit key is nice because you declare the intent first.

    If we do add it, it would be something like # @optional={group=somename} since the optional() implies its a function and can be called multiple times on an item. I guess my hesitation here is that the intent is not immediately evident. Like this means they must all be set, or all be empty, and thats not necessarily obvious. Should I also be able to set it on @required and a group on either one means all or none?

    The alternative is to put in a root decorator, which is a bit clearer, but also removes it from the items, and then there is a question of how an explicit required/optional on a specific item would interact with it.

    Will think on it a bit...

  5. wrong7 commented on Sep 18, 2026

    @wrong7
    Author

    A root decorator was my first approach but as you said it removes it from the item.
    Maybe what's needed here is just some functionality for the @tag() decorator beyond CLI filtering.

    I'm thinking you could declare a tag and then check with an internal variable the values of all of the variables with the tag (I don't think you can do this now).

    But then again this wouldn't be a straightforward method to achieve this, and it would be much more trouble than defining the @internal ENABLE_MICROSOFT=false you mentioned earlier.

    I think the conclusion here is that @tag() is already a group and it has more potential to it than just CLI filtering.

  6. theoephraim commented on Sep 19, 2026

    @theoephraim
    Member

    Agreed that tags have a lot of potential to be used for many things! I’ll think on it a bit.

  7. timche commented on Sep 28, 2026

    @timche
    Contributor

    +1 for this. A data point on why the existing decorators can't express it: the symmetric version (each item required when any of the others is set) is rejected as a cycle, even when none of them is set. Tried on 1.21.0:

    # @defaultSensitive=false
    # ---
    # @required=not(isEmpty(concat($CLIENT_ID, $CLIENT_SECRET)))
    TENANT_ID=
    # @required=not(isEmpty(concat($TENANT_ID, $CLIENT_SECRET)))
    CLIENT_ID=
    # @required=not(isEmpty(concat($TENANT_ID, $CLIENT_ID))) @sensitive
    CLIENT_SECRET=
    
    - Dependency cycle detected: (TENANT_ID, CLIENT_ID)
    - Dependency cycle detected: (TENANT_ID, CLIENT_ID, CLIENT_SECRET)
    

    Routing it through one internal helper (ANY_SET=not(isEmpty(concat(...))) with @required=$ANY_SET on each item) hits the same cycle. So today the choice is between anchoring on one key (only one direction is checked) and an explicit enable flag. The flag works, but for groups like credentials for an optional integration, it means a variable whose only job is to restate that the others are set. Something like @optional={group=azure}, or a tag-based check, would cover it without the extra variable.

  8. theoephraim commented on Sep 28, 2026

    @theoephraim
    Member

    @timche - thanks for the additional data point

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions