Deploying with ENV

The following guide shows you how to use our GitHub Actions to deploy your application with secrets from ENV. ENV is designed to be incredible flexible and this is just one example of how to deploy with secrets from ENV to Google Cloud.

Setting GitHub Secrets

There are a few GitHub Secrets that you will need to set to be able to bootstrap and use env. The names of these secrets do not matter as you pass them to the various steps yourself.

  • HYPHEN_API_KEY: A Hyphen API key with access to the project, app, and environment you’re deploying.
  • HYPHEN_KEY_FILE: The contents of the .hxkey file. This file contains your encryption key and should never be checked into your repository, hence the need to include it as a secret.
  • DEV_GCP_SA_KEY: JSON credentials for deploying to GCP. Since your application won’t need this directly, we recommend not storing it in ENV. The same principle applies for other cloud providers.

Writing the Workflow

The following example workflow demonstrates a typical deployment process:

  1. Clones your repository
  2. Setups up Node v20
  3. Installs and authenticates the hx CLI
  4. Pulls the production ENV
  5. Runs a build process
  6. Set up and authenticate Google Cloud SDK
  7. Authenticated docker with Google Cloud
  8. Build a docker image using the build output
  9. Push the Docker image to Google Artifact Registry
  10. Deploys the image to Google Cloud Run using ENV Secrets
name: Deploy to Development

on:
  workflow_dispatch:
  push:
    branches: [main]

env:
  PROJECT_ID: my-development-environment
  SERVICE_NAME: my-app

jobs:
  setup-build-deploy:
    name: Deploy to Dev
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@v4
      
      - name: Use Node.js 20
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: setup hx CLI
        id: setup
        uses: Hyphen/setup-hx-action@v1
        with:
          apiKey: ${{ secrets.HYPHEN_API_KEY }}

      - name: Pull ENV
        id: pull-env
        uses: Hyphen/env-action@v1
        with:
          hxKeyFile: ${{ secrets.HYPHEN_KEY_FILE }}
          environment: production
          outputs: variables
      
      - name: Run Build
        run: npm run build:ts
    
      - name: Authenticate with Google Cloud
        uses: google-github-actions/auth@v2
        with:
          credentials_json: ${{ secrets.DEV_GCP_SA_KEY }}

      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v2

      - name: Docker Auth
        run: gcloud auth configure-docker

      - name: Build Docker Image
        run: docker build -t gcr.io/$PROJECT_ID/$SERVICE_NAME:$GITHUB_SHA .

      - name: Docker Push to Google Cloud
        run: docker push gcr.io/$PROJECT_ID/$SERVICE_NAME:$GITHUB_SHA

      - name: Deploy to [us-central1]
        run: |-
          gcloud run deploy $SERVICE_NAME \
            --image=gcr.io/$PROJECT_ID/$SERVICE_NAME:$GITHUB_SHA \
            --cpu=1 \
            --memory=2Gi \
            --no-cpu-throttling \
            --min-instances=1 \
            --timeout=300 \
            --platform=managed \
            --region=us-central1 \
            --allow-unauthenticated \
            --set-env-vars=ONE_SECRET=$ONE_SECRET \
            --set-env-vars=TWO_SECRET=$TWO_SECRET

Automatically add all secrets

In the above example we are explicitly sending environment variables, exported by the env-action, to the google CLI. This is tedious and it prone to errors, forgetting to add it in the deploy script, misspelling, etc.

This can easily be scripted through; We are going to add a script that iterates through all the environment variables and transforms them into the format the google CLI is looking for. If you are not using Google this script can easily be updated to transform them into the format AWS or Azure use.

This script does the following

  1. looks for all environment variables with the env prefix. Don't forget to update the env-action step to add whatever prefix you want to use.
  2. Removes the prefix from the variable name
  3. concatenates them into a key=value, key=value string. This is where you can change the format to match what Azure or AWS expects.
  4. Echos out the result so we can use command substitution to send it to the CLI
# Initialize an empty string to store the concatenated result.
result=""

# Iterate over all environment variables.
for var in $(env); do
    # Check if the variable starts with "env_"
    if [[ $var == env_* ]]; then
        # Extract the name and value by splitting at the first '='.
        name_with_prefix="${var%%=*}"
        value="${var#*=}"

        # Remove the "env_" prefix from the name.
        name="${name_with_prefix#env_}"

        # Concatenate the modified variable to the result string.
        # Append a space to separate each name=value pair.
        result+="${name}=${value}, "
    fi
done

# Trim any trailing spaces.
result=$(echo "$result" | sed 's/, $//')

# Output the concatenated result.
echo "$result"

Next, we need to update the env-action to include our desired prefix.

...
 - name: Pull ENV
   id: pull-env
	 uses: Hyphen/env-action@v1
	 with:
	 	 hxKeyFile: ${{ secrets.HYPHEN_KEY_FILE }}
		 environment: production
     variablePrefix: env_
     outputs: variables
...

The last thing we need to do is replace our --set-env-vars parameter in our deploy step

...
 - name: Deploy to [us-central1]
  run: |-
    gcloud run deploy $SERVICE_NAME \
      --image=gcr.io/$PROJECT_ID/$SERVICE_NAME:$GITHUB_SHA \
      --cpu=1 \
      --memory=2Gi \
      --no-cpu-throttling \
      --min-instances=1 \
      --timeout=300 \
      --platform=managed \
      --region=us-central1 \
      --allow-unauthenticated \
      --set-env-vars="$(./.github/workflows/transformEnvs.sh)"