Skip to content

CI/CD Integration

Soup integrates with any CI/CD system that can run shell commands.

For CI/CD, create a dedicated API token:

  1. Cloud: Go to Settings → API Tokens → Create Token
  2. Self-hosted: Use the CLI to create a token

Store the token as a secret in your CI/CD system.

Set SOUP_TOKEN in your pipeline:

Terminal window
export SOUP_TOKEN=your-token
soup get my-app production DATABASE_URL
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Soup CLI
run: curl -fsSL https://soup.dev/install.sh | sh
- name: Deploy with secrets
env:
SOUP_TOKEN: ${{ secrets.SOUP_TOKEN }}
run: |
eval $(soup export my-app production)
./deploy.sh

Create .github/actions/soup/action.yml:

name: 'Soup Secrets'
description: 'Load secrets from Soup'
inputs:
project:
description: 'Soup project name'
required: true
environment:
description: 'Soup environment'
required: true
token:
description: 'Soup API token'
required: true
runs:
using: 'composite'
steps:
- name: Install Soup
shell: bash
run: curl -fsSL https://soup.dev/install.sh | sh
- name: Export secrets
shell: bash
env:
SOUP_TOKEN: ${{ inputs.token }}
run: |
soup export ${{ inputs.project }} ${{ inputs.environment }} --format shell >> $GITHUB_ENV

Use it:

- uses: ./.github/actions/soup
with:
project: my-app
environment: production
token: ${{ secrets.SOUP_TOKEN }}
- name: Deploy
run: echo $DATABASE_URL # Secret is available
stages:
- deploy
deploy:
stage: deploy
image: alpine:latest
before_script:
- apk add curl bash
- curl -fsSL https://soup.dev/install.sh | sh
script:
- eval $(soup export my-app production)
- ./deploy.sh
variables:
SOUP_TOKEN: $SOUP_TOKEN # Set in GitLab CI/CD settings
version: 2.1
jobs:
deploy:
docker:
- image: cimg/base:stable
steps:
- checkout
- run:
name: Install Soup
command: curl -fsSL https://soup.dev/install.sh | sh
- run:
name: Deploy
command: |
eval $(soup export my-app production)
./deploy.sh
workflows:
deploy:
jobs:
- deploy:
context: soup-secrets # Contains SOUP_TOKEN
pipeline {
agent any
environment {
SOUP_TOKEN = credentials('soup-token')
}
stages {
stage('Install Soup') {
steps {
sh 'curl -fsSL https://soup.dev/install.sh | sh'
}
}
stage('Deploy') {
steps {
sh '''
eval $(soup export my-app production)
./deploy.sh
'''
}
}
}
}
# Dockerfile
FROM node:20-alpine
# Install soup CLI
RUN curl -fsSL https://soup.dev/install.sh | sh
# Build with secrets (use BuildKit)
RUN --mount=type=secret,id=soup_token \
export SOUP_TOKEN=$(cat /run/secrets/soup_token) && \
eval $(soup export my-app production) && \
npm run build

Build with:

Terminal window
DOCKER_BUILDKIT=1 docker build \
--secret id=soup_token,env=SOUP_TOKEN \
-t my-app .

Better approach - inject at runtime:

FROM node:20-alpine
# Install app
COPY . .
RUN npm install
# Entrypoint loads secrets
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["npm", "start"]
entrypoint.sh
#!/bin/sh
eval $(soup export my-app production)
exec "$@"
apiVersion: v1
kind: Pod
spec:
initContainers:
- name: load-secrets
image: alpine:latest
command:
- sh
- -c
- |
curl -fsSL https://soup.dev/install.sh | sh
soup export my-app production --format dotenv > /secrets/.env
env:
- name: SOUP_TOKEN
valueFrom:
secretKeyRef:
name: soup-credentials
key: token
volumeMounts:
- name: secrets
mountPath: /secrets
containers:
- name: app
image: my-app:latest
command: ["sh", "-c", "source /secrets/.env && npm start"]
volumeMounts:
- name: secrets
mountPath: /secrets
volumes:
- name: secrets
emptyDir: {}

(Coming soon) Native integration with External Secrets Operator.

Create separate tokens for each CI/CD pipeline with minimal permissions.

Update tokens periodically and after team member changes.

In frequently-run pipelines, cache the Soup CLI installation:

# GitHub Actions
- uses: actions/cache@v4
with:
path: ~/.local/bin/soup
key: soup-cli-${{ runner.os }}

Check for Soup CLI installation and authentication early:

#!/bin/bash
set -e
# Verify soup is installed and authenticated
soup whoami || exit 1
# Continue with deployment
eval $(soup export my-app production)
./deploy.sh

Log that secrets were loaded without logging values:

Terminal window
echo "Loading secrets from Soup..."
SECRETS=$(soup export my-app production)
echo "Loaded $(echo "$SECRETS" | wc -l) secrets"
eval "$SECRETS"