Saturday, 13 June 2026

Enable Updating GitHub Environment Variables via GitHub Actions Workflow

 To update environment  variables defined in GitHub environment, via a GitHub action workflow we cannot use the default GITHUB_TOKEN .

  • GITHUB_TOKEN can interact with repository contents (depending on permissions), create releases, comment on PRs, update issues, etc.
  • GITHUB_TOKEN cannot update repository environments, environment secrets, or environment variables via the GitHub REST API.

    Therefore, we need to use a Fine-Grained Personal Access Token (PAT) , provided it has the appropriate repository permissions.

    For updating GitHub environment variables, the token needs:

    • Repository access to the target repository.
    • Environments permission: Read and write.
  • Let's see how we can setup such a token step by steps.
    • Go to GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens.
    • Click Generate new token.
    • Configure the token:
      • Resource owner: Select the owner of the repository.

    Common name variable_read_write used as later it can expand to other repos as and when needed. Set to expire in 90 days.


    Repository access limited to the required repo for now.
    • Configure the token:
      • Repository access: Select Only select repositories (or All repositories if appropriate) and choose your repository.


    The permisions for environments read and write set explicitly. No addtional permision except required metadata read.
    • Configure the token:
      • Repository permissions:
        • EnvironmentsRead and write.
    • Generate and copy the token.

    • Store the token as a secret, for example:
      • Repository secret: GH_VARIABLES_PAT, or
      • Environment secret if only workflows targeting a specific environment should be able to use it.
    WhatWhereName 
    Fine-Grained PAT with Environment R/WRepo → Settings → Secrets → ActionsGH_VARIABLES_PAT



    Once we do this we would be able to use it in workflows as shown in below workflow, and use the token to update environment variables.

    on:
      workflow_call:
        inputs:
          environment:
            required: true
            type: string
          stage:
            required: true
            type: string
    
    jobs:
      setup_blue_green_control:
        name: "${{ inputs.stage }}: setup_blue_green_control"
        runs-on: ubuntu-24.04
        environment: ${{ inputs.environment }}
        steps:
          - uses: actions/checkout@v6.0.3
    
          - uses: ./.github/actions/step/log_blue_green_parameters
            with:
              environment: ${{ inputs.environment }}
              stage: ${{ inputs.stage }}
              sys_is_blue_deployed: ${{ vars.SYS_IS_BLUE_DEPLOYED }}
              sys_is_green_deployed: ${{ vars.SYS_IS_GREEN_DEPLOYED }}
              sys_is_green_live: ${{ vars.SYS_IS_GREEN_LIVE }}
              sys_is_skip_healthcheck: ${{ vars.SYS_IS_SKIP_HEALTHCHECK }}
              sys_live_aks_nodepool: ${{ vars.SYS_LIVE_AKS_NODEPOOL }}
              sys_svc_deploy_dns_zone: ${{ vars.SYS_SVC_DEPLOY_DNS_ZONE }}
              sys_svc_deploy_nodepool_suffix: ${{ vars.SYS_SVC_DEPLOY_NODEPOOL_SUFFIX }}
    
          - name: "${{ inputs.stage }}: setup_blue_green_control"
            shell: bash
            env:
              GH_VAR_TOKEN: ${{ secrets.GH_VARIABLES_PAT }}
              GH_REPO: ${{ github.repository }}
              GH_ENVIRONMENT: ${{ inputs.environment }}
              SYS_DEPLOYMENT_PHASE: ${{ inputs.stage }}
              SYS_IS_BLUE_DEPLOYED: ${{ vars.SYS_IS_BLUE_DEPLOYED }}
              SYS_IS_GREEN_DEPLOYED: ${{ vars.SYS_IS_GREEN_DEPLOYED }}
              SYS_IS_GREEN_LIVE: ${{ vars.SYS_IS_GREEN_LIVE }}
              SYS_SVC_DEPLOY_NODEPOOL_SUFFIX: ${{ vars.SYS_SVC_DEPLOY_NODEPOOL_SUFFIX }}
              SYS_LIVE_AKS_NODEPOOL: ${{ vars.SYS_LIVE_AKS_NODEPOOL }}
            run: |
              update_var() {
                local var_name="$1"
                local var_value="$2"
                local api_base="https://api.github.com/repos/${GH_REPO}/environments/${GH_ENVIRONMENT}/variables"
                echo "Updating ${var_name} to '${var_value}'..."
    
                http_status=$(curl -s -o /tmp/gh_api_response.json -w "%{http_code}" -X PATCH \
                  -H "Authorization: Bearer ${GH_VAR_TOKEN}" \
                  -H "Accept: application/vnd.github+json" \
                  -H "X-GitHub-Api-Version: 2022-11-28" \
                  "${api_base}/${var_name}" \
                  -d "{\"name\":\"${var_name}\",\"value\":\"${var_value}\"}")
    
                if [ "${http_status}" = "204" ]; then
                  echo "Updated ${var_name} successfully (HTTP ${http_status})."
                else
                  echo "ERROR: Failed to update ${var_name}. HTTP ${http_status}. Response:"
                  cat /tmp/gh_api_response.json
                  exit 1
                fi
              }
    
              if [ "${SYS_DEPLOYMENT_PHASE}" = "deploy" ]; then
                update_var "SYS_IS_SKIP_HEALTHCHECK" "false"
    
                if [ "${SYS_IS_GREEN_LIVE}" = "true" ] && [ "${SYS_IS_BLUE_DEPLOYED}" = "false" ]; then
                  echo "Green is live. Setting blue nodepool to deploy..."
                  update_var "SYS_IS_BLUE_DEPLOYED" "true"
                elif [ "${SYS_IS_GREEN_LIVE}" = "false" ] && [ "${SYS_IS_GREEN_DEPLOYED}" = "false" ]; then
                  echo "Blue is live. Setting green nodepool to deploy..."
                  update_var "SYS_IS_GREEN_DEPLOYED" "true"
                elif [ "${SYS_IS_GREEN_LIVE}" = "true" ]; then
                  echo "Green is live. Retry deploying blue nodepool..."
                else
                  echo "Blue is live. Retry deploying green nodepool..."
                fi
    
              elif [ "${SYS_DEPLOYMENT_PHASE}" = "switch" ]; then
                if [ "${SYS_IS_GREEN_LIVE}" = "false" ] && [ "${SYS_SVC_DEPLOY_NODEPOOL_SUFFIX}" = "green" ]; then
                  echo "Green deployed. Setting green to go live..."
                  update_var "SYS_IS_GREEN_LIVE" "true"
                elif [ "${SYS_IS_GREEN_LIVE}" = "true" ] && [ "${SYS_SVC_DEPLOY_NODEPOOL_SUFFIX}" = "blue" ]; then
                  echo "Blue deployed. Setting blue to go live..."
                  update_var "SYS_IS_GREEN_LIVE" "false"
                else
                  echo "New app deployed instance is ${SYS_SVC_DEPLOY_NODEPOOL_SUFFIX}. Setting as live..."
                fi
    
              elif [ "${SYS_DEPLOYMENT_PHASE}" = "destroy" ]; then
                if [ "${SYS_IS_GREEN_LIVE}" = "true" ] && [ "${SYS_IS_BLUE_DEPLOYED}" = "true" ]; then
                  echo "New green nodepool is live now. Setting blue nodepool to destroy..."
                  update_var "SYS_IS_BLUE_DEPLOYED" "false"
                elif [ "${SYS_IS_GREEN_LIVE}" = "false" ] && [ "${SYS_IS_GREEN_DEPLOYED}" = "true" ]; then
                  echo "New blue nodepool is live now. Setting green nodepool to destroy..."
                  update_var "SYS_IS_GREEN_DEPLOYED" "false"
                else
                  echo "Live nodepool is ${SYS_LIVE_AKS_NODEPOOL}. Retry destroying none live nodepool..."
                fi
              fi
    

    No comments:

    Popular Posts