Search code examples
azure-devopsazure-pipelines-yaml

YAML template to prevent the use of certain variable group


I've created a YAML template to extends from with a fixed stage "Deploy" (can not be modified by users, only pass params) and an optional stage "PreDeploy" that should be entirely provided by template users (if they want to add this stage).

parameters:
- name: application
  type: string
  default: ""
- name: PreDeployStage
  type: stage
  default: 
     stage: 
     jobs:
     - job: 

stages:
- ${{ parameters.PreDeployStage }}
- stage: 'Deploy'

The pipeline which extends from this template could be something like this:

# azure-pipelines.yml
resources:
repositories:
- repository: temp
type: git
name: templates
ref: refs/heads/main

extends:
template: template.yml@temp
parameters:
Application: APP
PreDeployStage:
  stage: Custom
  jobs:
  - job: StoleSecrets
    variables:
      - group: Secrets
    pool: default
    steps:
      - task: Whatever task which access to the vars stored in Secrets 

There is a variable group called "Secrets" that should never be used in a stage other than "Deploy". In order to prevent template users to provide a stage which uses this variable group (either at stage level or job level) I was wondering if something like this can be used (idea would be to delete all references to "Secrets" variable group in the provided stage).

Is this possible?

EDIT

The workaround proposed by @Alvin Zhao - MSFT gives me a validation error on the steps section:

enter image description here

When trying to save, this is the result:

enter image description here

Seems that the problem is totally focused there because if I replaced the expression with a concrete task, passes validation and works as expected:

enter image description here

The script that currently consumes the template is:

enter image description here


Solution

  • Based on the further disucssions, the pipeline had been passing a whole stage syntax as the value of ${{ parameters.PreDeployStage }} into the extended template.yml. Users were able modify the parameter value to be passed in the YAML defintion azure-pipelines.yml; if with variables: - group: Secrets added, the pipeline would proceed to reference the variable group Secrets.

    The requirement is to first detect if the parameter value to be passed into template contains such lines to reference variable group Secrets and then remove to prevent them from passing.

    Here are modifed YAML defintion (removing any possibly referenced variables group defined on stage level) and the template for your reference.

    azure-pipelines.yml

    # azure-pipelines.yml
    
    resources:
      repositories:
      - repository: temp
        type: git
        name: templates
        ref: refs/heads/main
    
    extends:
      template: template.yml@temp
      parameters:
        Application: APP
        PreDeployStage:
          stage: Custom
          variables:
          - group: Secrets # Includes a variable Var1 with the value 1
          - group: VG-Y # Includes a variable VarY with the value Y
          jobs:
          - job: DoNothing
            variables:
            - group: Secrets 
            - group: VG-X # Includes a variable VarX with the value X
            pool: default
            steps:
            - script: |
                echo Whatever task which access to the vars stored in Secrets variable group
                echo "Stage variables defined in parameter $(jsonStageVar)"
                echo "Job variables defined in parameters $(jsonJobVar)"
                echo "Parameter expects to use Secrets varialbe group? - $(useSecrects)"
    
                echo The value of var1 in group Secrets is "$(Var1)"
                echo The value of varX in group VG-X is "$(VarX)"
                echo The value of varY in group VG-Y is "$(VarY)"
    
    

    template.yml

    # template.yml
    
    parameters:
    - name: application
      type: string
      default: ""
    - name: PreDeployStage
      type: stage
      default: {}
    
    stages:
    - stage: ${{ parameters.PreDeployStage.stage }}
      variables:
      - name: jsonStageVar
        value: ${{ convertToJson(parameters.PreDeployStage.variables) }}
      - ${{ each stageVariable in parameters.PreDeployStage.variables }}:
        - ${{ if eq(stageVariable.group, 'Secrets') }}:
          - name: useSecrects
            value: true
        - ${{ else }}:
          - ${{ stageVariable }}
      jobs:
      - ${{ each tempJob in parameters.PreDeployStage.jobs}}:
        - job: ${{ tempJob.job }}
          pool: ${{ tempJob.pool }} 
          variables:
          - name: jsonJobVar
            value: ${{ convertToJson(tempJob.variables) }}
          - ${{ each jobVariable in tempJob.variables }}:
            - ${{ if eq(jobVariable.group, 'Secrets') }}:
              - name: useSecrects
                value: true
            - ${{ else }}:
              - ${{ jobVariable }}
          steps:
          - ${{ tempJob.steps }}
    
    
    - stage: 'Deploy'
      jobs:
      - job: JobDeploy
        steps:
        - script: echo This is Deploy stage
    

    From the expaned YAML defintion in the downloaded logs, we can see the lines - group: secrets defined in the variables sections on stage and job levels are replaced.

    enter image description here

    enter image description here

    Please also note that the modified template.yml splits some but not all properties of the stage and job(s) to be passed in. If other stage/job properties shall be passed, you need to add those mapping properties in temlate.yml as well; otherwise, they will be ignored during template expansion and will not take effect.