157 lines
4.2 KiB
YAML
157 lines
4.2 KiB
YAML
# GitLab CI pipeline for verifying ATProto signatures
|
|
|
|
variables:
|
|
REGISTRY: atcr.io
|
|
IMAGE_NAME: $CI_PROJECT_PATH
|
|
IMAGE_TAG: $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA
|
|
|
|
stages:
|
|
- build
|
|
- verify
|
|
- deploy
|
|
|
|
build_image:
|
|
stage: build
|
|
image: docker:latest
|
|
services:
|
|
- docker:dind
|
|
script:
|
|
- docker build -t $IMAGE_TAG .
|
|
- docker push $IMAGE_TAG
|
|
|
|
verify_signature:
|
|
stage: verify
|
|
image: alpine:latest
|
|
before_script:
|
|
- apk add --no-cache curl jq
|
|
script:
|
|
- |
|
|
echo "Verifying signature for $IMAGE_TAG"
|
|
|
|
# Install crane
|
|
wget https://github.com/google/go-containerregistry/releases/download/v0.15.2/go-containerregistry_Linux_x86_64.tar.gz
|
|
tar -xzf go-containerregistry_Linux_x86_64.tar.gz crane
|
|
mv crane /usr/local/bin/
|
|
|
|
# Get image digest
|
|
DIGEST=$(crane digest "$IMAGE_TAG")
|
|
echo "Image digest: $DIGEST"
|
|
|
|
# Extract repository path
|
|
REPO=$(echo "$IMAGE_TAG" | cut -d: -f1)
|
|
REPO_PATH=${REPO#$REGISTRY/}
|
|
|
|
# Check for ATProto signature
|
|
REFERRERS=$(curl -s "https://$REGISTRY/v2/$REPO_PATH/referrers/${DIGEST}?artifactType=application/vnd.atproto.signature.v1+json")
|
|
|
|
SIG_COUNT=$(echo "$REFERRERS" | jq '.manifests | length')
|
|
|
|
if [ "$SIG_COUNT" -eq 0 ]; then
|
|
echo "❌ No ATProto signature found"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ Found $SIG_COUNT signature(s)"
|
|
|
|
verify_full:
|
|
stage: verify
|
|
image: alpine:latest
|
|
before_script:
|
|
- apk add --no-cache curl jq bash
|
|
script:
|
|
- |
|
|
# Option 1: Use atcr-verify CLI (when available)
|
|
# wget https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify
|
|
# chmod +x atcr-verify
|
|
# ./atcr-verify "$IMAGE_TAG" --policy .atcr/trust-policy.yaml
|
|
|
|
# Option 2: Use shell script
|
|
chmod +x examples/verification/atcr-verify.sh
|
|
./examples/verification/atcr-verify.sh "$IMAGE_TAG"
|
|
|
|
echo "✓ Signature verified successfully"
|
|
|
|
verify_trust:
|
|
stage: verify
|
|
image: alpine:latest
|
|
before_script:
|
|
- apk add --no-cache curl jq
|
|
script:
|
|
- |
|
|
# Install crane and ORAS
|
|
wget https://github.com/google/go-containerregistry/releases/download/v0.15.2/go-containerregistry_Linux_x86_64.tar.gz
|
|
tar -xzf go-containerregistry_Linux_x86_64.tar.gz crane
|
|
mv crane /usr/local/bin/
|
|
|
|
wget https://github.com/oras-project/oras/releases/download/v1.0.0/oras_1.0.0_linux_amd64.tar.gz
|
|
tar -xzf oras_1.0.0_linux_amd64.tar.gz
|
|
mv oras /usr/local/bin/
|
|
|
|
# Get signature metadata
|
|
DIGEST=$(crane digest "$IMAGE_TAG")
|
|
REPO=$(echo "$IMAGE_TAG" | cut -d: -f1)
|
|
REPO_PATH=${REPO#$REGISTRY/}
|
|
|
|
REFERRERS=$(curl -s "https://$REGISTRY/v2/$REPO_PATH/referrers/${DIGEST}?artifactType=application/vnd.atproto.signature.v1+json")
|
|
SIG_DIGEST=$(echo "$REFERRERS" | jq -r '.manifests[0].digest')
|
|
|
|
# Pull signature artifact
|
|
oras pull "${REPO}@${SIG_DIGEST}" -o /tmp/sig
|
|
|
|
# Extract DID
|
|
DID=$(jq -r '.atproto.did' /tmp/sig/atproto-signature.json)
|
|
echo "Signed by DID: $DID"
|
|
|
|
# Check against trusted DIDs (from CI/CD variables)
|
|
if [[ ",$TRUSTED_DIDS," == *",$DID,"* ]]; then
|
|
echo "✓ DID is trusted"
|
|
else
|
|
echo "❌ DID $DID is not in trusted list"
|
|
exit 1
|
|
fi
|
|
|
|
deploy_production:
|
|
stage: deploy
|
|
image: bitnami/kubectl:latest
|
|
dependencies:
|
|
- verify_signature
|
|
- verify_full
|
|
- verify_trust
|
|
only:
|
|
- main
|
|
script:
|
|
- |
|
|
# Configure kubectl
|
|
echo "$KUBE_CONFIG" | base64 -d > /tmp/kubeconfig
|
|
export KUBECONFIG=/tmp/kubeconfig
|
|
|
|
# Deploy to production
|
|
kubectl set image deployment/myapp \
|
|
myapp=$IMAGE_TAG \
|
|
-n production
|
|
|
|
kubectl rollout status deployment/myapp -n production
|
|
|
|
# Verify deployment
|
|
kubectl get pods -n production -l app=myapp
|
|
|
|
# Alternative: Manual approval before deploy
|
|
deploy_production_manual:
|
|
stage: deploy
|
|
image: bitnami/kubectl:latest
|
|
dependencies:
|
|
- verify_signature
|
|
when: manual
|
|
only:
|
|
- main
|
|
script:
|
|
- |
|
|
echo "Deploying $IMAGE_TAG to production"
|
|
|
|
echo "$KUBE_CONFIG" | base64 -d > /tmp/kubeconfig
|
|
export KUBECONFIG=/tmp/kubeconfig
|
|
|
|
kubectl set image deployment/myapp \
|
|
myapp=$IMAGE_TAG \
|
|
-n production
|