CollabOps

Variables and Secrets

Enterprise pipeline using three levels of environment variables — vars, secrets, and env

A pipeline that utilizes vars (organization/repository variables), secrets, and env (environment variables) across three levels. Variables and secrets are systematically managed throughout the entire process from Setup → Build → Test → Deploy.

Full Code

name: enterprise-pipeline

triggers:
  push:
    branches: ["main", "develop"]
  change_request:
    branches: ["main"]

# ─────────────────────────────────────────
# Workflow-level environment variables
# Accessible as $APP_NAME, $WORKSPACE_NAME from all Jobs/Steps
# ─────────────────────────────────────────
env:
  APP_NAME: my-application
  WORKSPACE_NAME: "${{ vars.WORKSPACE_NAME }}"

jobs:
  # ─────────────────────────────────────────
  # 1. Setup — Environment configuration
  # ─────────────────────────────────────────
  setup:
    steps:
      - name: print-config
        run: |
          echo "App: $APP_NAME"
          echo "Workspace: $WORKSPACE_NAME"
          echo "Project: ${{ vars.PROJECT_NAME }}"

      - name: configure-build
        run: |
          echo "Build type: $BUILD_TYPE"
          echo "Version: $VERSION"
        # Step-level env — Fetches values from vars and sets them as environment variables
        env:
          BUILD_TYPE: "${{ vars.BUILD_TYPE }}"
          VERSION: "${{ vars.VERSION }}"

  # ─────────────────────────────────────────
  # 2. Build — Build (using Job-level env)
  # ─────────────────────────────────────────
  build:
    needs: [setup]
    # Job-level environment variables — Available to all Steps in this Job
    env:
      NODE_ENV: production
      BUILD_DIR: "${{ vars.BUILD_DIRECTORY }}"
      API_BASE_URL: "${{ vars.API_BASE_URL }}"
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"

      - name: install-deps
        image: node:18
        run: |
          echo "Registry: $NPM_REGISTRY"
          npm ci
        env:
          # Pass sensitive token via secrets
          NPM_REGISTRY: "${{ vars.NPM_REGISTRY }}"
          NPM_TOKEN: "${{ secrets.NPM_TOKEN }}"

      - name: build
        image: node:18
        run: |
          echo "Building to $BUILD_DIR"
          echo "API URL: $API_BASE_URL"
          npm run build
        env:
          # Pass API key via secrets
          API_KEY: "${{ secrets.API_KEY }}"

      - name: upload-artifacts
        run: |
          echo "Uploading to ${{ vars.ARTIFACT_STORAGE }}"
        env:
          # Storage authentication credentials
          STORAGE_URL: "${{ vars.ARTIFACT_STORAGE }}"
          ACCESS_KEY: "${{ secrets.STORAGE_ACCESS_KEY }}"
          SECRET_KEY: "${{ secrets.STORAGE_SECRET_KEY }}"

  # ─────────────────────────────────────────
  # 3. Test — Tests (using DB secrets)
  # ─────────────────────────────────────────
  test:
    needs: [build]
    env:
      TEST_ENV: "${{ vars.TEST_ENVIRONMENT }}"
      TEST_TIMEOUT: "${{ vars.TEST_TIMEOUT_SECONDS }}"
    steps:
      - name: unit-test
        image: node:18
        run: |
          echo "Test env: $TEST_ENV"
          echo "Timeout: $TEST_TIMEOUT"
          npm test
        env:
          # Test DB connection info (secrets)
          TEST_DB_URL: "${{ secrets.TEST_DATABASE_URL }}"
          COVERAGE_TOKEN: "${{ secrets.COVERAGE_TOKEN }}"

      - name: integration-test
        image: node:18
        run: npm run test:integration
        env:
          API_ENDPOINT: "${{ vars.API_ENDPOINT }}"
          API_SECRET: "${{ secrets.API_SECRET }}"
          INTEGRATION_KEY: "${{ secrets.INTEGRATION_TEST_KEY }}"

      - name: generate-report
        run: echo "Report path: ${{ vars.REPORT_PATH }}"
        env:
          REPORT_PATH: "${{ vars.REPORT_PATH }}"
          REPORT_TOKEN: "${{ secrets.REPORT_UPLOAD_TOKEN }}"

  # ─────────────────────────────────────────
  # 4. Deploy — Deployment (cloud authentication secrets)
  # ─────────────────────────────────────────
  deploy:
    needs: [build, test]
    if: "collabops.ref == 'refs/heads/main' && collabops.event_name == 'push'"
    env:
      DEPLOY_ENV: "${{ vars.DEPLOYMENT_ENVIRONMENT }}"
      DEPLOY_REGION: "${{ vars.DEPLOYMENT_REGION }}"
    steps:
      - name: authenticate
        run: echo "Authenticating to ${{ vars.CLOUD_PROVIDER }}"
        env:
          CLOUD_PROVIDER: "${{ vars.CLOUD_PROVIDER }}"
          CLOUD_ACCESS_KEY: "${{ secrets.CLOUD_ACCESS_KEY }}"
          CLOUD_SECRET_KEY: "${{ secrets.CLOUD_SECRET_KEY }}"

      - name: deploy-staging
        run: echo "Deploying to staging: ${{ vars.STAGING_URL }}"
        env:
          STAGING_URL: "${{ vars.STAGING_URL }}"
          DEPLOY_KEY: "${{ secrets.DEPLOYMENT_KEY }}"

      - name: smoke-test
        run: echo "Smoke test: ${{ vars.SMOKE_TEST_ENDPOINT }}"
        env:
          SMOKE_TEST_ENDPOINT: "${{ vars.SMOKE_TEST_ENDPOINT }}"
          SMOKE_TEST_TOKEN: "${{ secrets.SMOKE_TEST_TOKEN }}"

      - name: deploy-production
        run: echo "Deploying to production: ${{ vars.PRODUCTION_URL }}"
        env:
          PRODUCTION_URL: "${{ vars.PRODUCTION_URL }}"
          PROD_ACCESS_KEY: "${{ secrets.PRODUCTION_ACCESS_KEY }}"
          PROD_SECRET_KEY: "${{ secrets.PRODUCTION_SECRET_KEY }}"

Variables vs Secrets Usage Guidelines

TypeContextPurposeExamples
vars$\{\{ vars.KEY \}\}Non-sensitive configuration valuesURLs, regions, build paths
secrets$\{\{ secrets.KEY \}\}Sensitive authentication informationAPI keys, tokens, passwords
envenv: blockStatic values within the WorkflowAPP_NAME, NODE_ENV

Three-Level env Priority

Step env  >  Job env  >  Workflow env
(highest)                   (lowest)

In this example:

APP_NAME is defined at the Workflow level → Used by all Jobs

NODE_ENV is defined at the build Job level → Used by all Steps in the build Job

NPM_TOKEN is defined only in the install-deps Step → Used only in that Step

Table of Contents