GitLab CI
Add human approval steps to your GitLab CI/CD pipelines.
Setup
- Go to Settings → CI/CD → Variables
- Add
OTTR_API_KEY(masked, protected)
Pipeline Configuration
This pipeline builds, requests approval, waits for human action, then deploys:
.gitlab-ci.yml
stages:
- build
- approval
- deploy
variables:
OTTR_API_URL: "https://api.ottr.run"
build:
stage: build
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
request-approval:
stage: approval
script:
- |
RESPONSE=$(curl -s -X POST "$OTTR_API_URL/v1/approvals" \
-H "Authorization: Bearer $OTTR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key_path": "deploy/'"$CI_PROJECT_PATH"'/'"$CI_PIPELINE_ID"'",
"value": "approved",
"ttl_seconds": 1800,
"info": "Deploy '"$CI_COMMIT_SHORT_SHA"' to production?",
"actions": [
{"key": "approve", "value": "approved", "label": "Deploy", "style": "primary"},
{"key": "reject", "value": "rejected", "label": "Cancel", "style": "danger"}
]
}')
URL=$(echo $RESPONSE | jq -r '.url')
echo "APPROVAL_URL=$URL" >> approval.env
echo "Approval URL: $URL"
artifacts:
reports:
dotenv: approval.env
wait-for-approval:
stage: approval
needs: [request-approval]
script:
- |
KEY_PATH="deploy/$CI_PROJECT_PATH/$CI_PIPELINE_ID"
echo "Waiting for approval..."
for i in $(seq 1 180); do
RESULT=$(curl -s "$OTTR_API_URL/v1/key/$KEY_PATH" \
-H "Authorization: Bearer $OTTR_API_KEY")
if [ "$RESULT" = '"approved"' ]; then
echo "Approved!"
exit 0
elif [ "$RESULT" = '"rejected"' ]; then
echo "Rejected"
exit 1
fi
sleep 10
done
echo "Timeout waiting for approval"
exit 1
timeout: 30 minutes
deploy:
stage: deploy
needs: [wait-for-approval]
script:
- echo "Deploying to production..."
# Your deployment commands here
environment:
name: productionHow it works
- build - Compiles your application
- request-approval - Creates ottr approval URL, outputs to job log
- wait-for-approval - Polls until approved/rejected (30 min timeout)
- deploy - Runs only after approval
Why ottr vs GitLab's manual jobs?
- No GitLab account required for approvers
- Simple URL - share via Slack, email, SMS
- Built-in expiry and audit trail
- Works across GitLab, GitHub, Jenkins, etc.
Tips
- Use
CI_PIPELINE_IDin key_path for unique approvals - Adjust the loop count in wait-for-approval to change timeout
- Configure Slack notifications for automatic alerts