How To: CI/CD Integration¶
Automate PyLocket protection in your CI/CD pipeline to protect every release automatically.
Authentication in CI/CD¶
Use an API token instead of interactive login. Generate one in the Developer Portal or CLI:
Store the token as a CI/CD secret (e.g., PYLOCKET_TOKEN).
Use it in commands:
Or pass it explicitly:
GitHub Actions¶
name: Build, Protect, Release
on:
push:
tags: ["v*"]
jobs:
protect:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- platform: linux-x64
artifact: dist/myapp
os_label: linux
- platform: win-x64
artifact: dist/myapp.exe
os_label: windows
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
pip install pylocket pyinstaller
pip install -r requirements.txt
- name: Build
run: pyinstaller --onefile myapp.py
- name: Protect
env:
PYLOCKET_TOKEN: ${{ secrets.PYLOCKET_TOKEN }}
run: |
pylocket protect \
--app ${{ vars.PYLOCKET_APP_ID }} \
--artifact ${{ matrix.artifact }} \
--platform ${{ matrix.platform }} \
--python 3.12
- name: Wait for protection
env:
PYLOCKET_TOKEN: ${{ secrets.PYLOCKET_TOKEN }}
run: |
# Get the latest build ID
BUILD_ID=$(pylocket status \
--app ${{ vars.PYLOCKET_APP_ID }} \
--latest --format json | jq -r '.build_id')
# Poll until ready
for i in $(seq 1 60); do
STATUS=$(pylocket status --build "$BUILD_ID" --format json | jq -r '.status')
echo "Build status: $STATUS"
if [ "$STATUS" = "READY" ]; then
echo "BUILD_ID=$BUILD_ID" >> "$GITHUB_ENV"
exit 0
fi
if [ "$STATUS" = "FAILED" ]; then
echo "::error::Protection failed"
exit 1
fi
sleep 10
done
echo "::error::Timed out waiting for protection"
exit 1
- name: Download protected artifact
env:
PYLOCKET_TOKEN: ${{ secrets.PYLOCKET_TOKEN }}
run: pylocket fetch --build "$BUILD_ID" --out dist/protected/
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: myapp-${{ matrix.os_label }}
path: dist/protected/
GitLab CI¶
# .gitlab-ci.yml
stages:
- build
- protect
- release
variables:
PYTHON_VERSION: "3.12"
build:
stage: build
image: python:3.12
script:
- pip install pyinstaller -r requirements.txt
- pyinstaller --onefile myapp.py
artifacts:
paths:
- dist/
protect:
stage: protect
image: python:3.12
script:
- pip install pylocket
- export PYLOCKET_TOKEN=$PYLOCKET_TOKEN
- pylocket protect
--app $PYLOCKET_APP_ID
--artifact dist/myapp
--platform linux-x64
--python $PYTHON_VERSION
- |
BUILD_ID=$(pylocket status --app $PYLOCKET_APP_ID --latest --format json | jq -r '.build_id')
while true; do
STATUS=$(pylocket status --build "$BUILD_ID" --format json | jq -r '.status')
[ "$STATUS" = "READY" ] && break
[ "$STATUS" = "FAILED" ] && exit 1
sleep 10
done
- pylocket fetch --build "$BUILD_ID" --out dist/protected/
artifacts:
paths:
- dist/protected/
Jenkins¶
// Jenkinsfile
pipeline {
agent any
environment {
PYLOCKET_TOKEN = credentials('pylocket-token')
PYLOCKET_APP_ID = 'app_abc123'
}
stages {
stage('Build') {
steps {
sh 'pip install pyinstaller -r requirements.txt'
sh 'pyinstaller --onefile myapp.py'
}
}
stage('Protect') {
steps {
sh '''
pip install pylocket
pylocket protect \
--app $PYLOCKET_APP_ID \
--artifact dist/myapp \
--platform linux-x64 \
--python 3.12
'''
script {
def buildId = sh(
script: 'pylocket status --app $PYLOCKET_APP_ID --latest --format json | jq -r .build_id',
returnStdout: true
).trim()
timeout(time: 10, unit: 'MINUTES') {
waitUntil {
def status = sh(
script: "pylocket status --build ${buildId} --format json | jq -r .status",
returnStdout: true
).trim()
return status == 'READY'
}
}
sh "pylocket fetch --build ${buildId} --out dist/protected/"
}
}
}
}
post {
success {
archiveArtifacts artifacts: 'dist/protected/**'
}
}
}
Best Practices¶
| Practice | Rationale |
|---|---|
Store PYLOCKET_TOKEN as a secret |
Never hardcode tokens in pipeline files |
Store PYLOCKET_APP_ID as a variable |
Makes it easy to change without editing the pipeline |
| Set a timeout on the status polling loop | Prevents infinite waits on failed builds |
Pin the pylocket CLI version |
Avoid unexpected behavior from CLI updates: pip install pylocket==1.0.0 |
See Also¶
- Advanced Tutorial — CI/CD overview
- CLI Reference — All command options
- Cross-Platform Builds — Multi-platform CI/CD matrix