A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
1# GitLab CI pipeline for verifying ATProto signatures 2 3variables: 4 REGISTRY: atcr.io 5 IMAGE_NAME: $CI_PROJECT_PATH 6 IMAGE_TAG: $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA 7 8stages: 9 - build 10 - verify 11 - deploy 12 13build_image: 14 stage: build 15 image: docker:latest 16 services: 17 - docker:dind 18 script: 19 - docker build -t $IMAGE_TAG . 20 - docker push $IMAGE_TAG 21 22verify_signature: 23 stage: verify 24 image: alpine:latest 25 before_script: 26 - apk add --no-cache curl jq 27 script: 28 - | 29 echo "Verifying signature for $IMAGE_TAG" 30 31 # Install crane 32 wget https://github.com/google/go-containerregistry/releases/download/v0.15.2/go-containerregistry_Linux_x86_64.tar.gz 33 tar -xzf go-containerregistry_Linux_x86_64.tar.gz crane 34 mv crane /usr/local/bin/ 35 36 # Get image digest 37 DIGEST=$(crane digest "$IMAGE_TAG") 38 echo "Image digest: $DIGEST" 39 40 # Extract repository path 41 REPO=$(echo "$IMAGE_TAG" | cut -d: -f1) 42 REPO_PATH=${REPO#$REGISTRY/} 43 44 # Check for ATProto signature 45 REFERRERS=$(curl -s "https://$REGISTRY/v2/$REPO_PATH/referrers/${DIGEST}?artifactType=application/vnd.atproto.signature.v1+json") 46 47 SIG_COUNT=$(echo "$REFERRERS" | jq '.manifests | length') 48 49 if [ "$SIG_COUNT" -eq 0 ]; then 50 echo "❌ No ATProto signature found" 51 exit 1 52 fi 53 54 echo "✓ Found $SIG_COUNT signature(s)" 55 56verify_full: 57 stage: verify 58 image: alpine:latest 59 before_script: 60 - apk add --no-cache curl jq bash 61 script: 62 - | 63 # Option 1: Use atcr-verify CLI (when available) 64 # wget https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify 65 # chmod +x atcr-verify 66 # ./atcr-verify "$IMAGE_TAG" --policy .atcr/trust-policy.yaml 67 68 # Option 2: Use shell script 69 chmod +x examples/verification/atcr-verify.sh 70 ./examples/verification/atcr-verify.sh "$IMAGE_TAG" 71 72 echo "✓ Signature verified successfully" 73 74verify_trust: 75 stage: verify 76 image: alpine:latest 77 before_script: 78 - apk add --no-cache curl jq 79 script: 80 - | 81 # Install crane and ORAS 82 wget https://github.com/google/go-containerregistry/releases/download/v0.15.2/go-containerregistry_Linux_x86_64.tar.gz 83 tar -xzf go-containerregistry_Linux_x86_64.tar.gz crane 84 mv crane /usr/local/bin/ 85 86 wget https://github.com/oras-project/oras/releases/download/v1.0.0/oras_1.0.0_linux_amd64.tar.gz 87 tar -xzf oras_1.0.0_linux_amd64.tar.gz 88 mv oras /usr/local/bin/ 89 90 # Get signature metadata 91 DIGEST=$(crane digest "$IMAGE_TAG") 92 REPO=$(echo "$IMAGE_TAG" | cut -d: -f1) 93 REPO_PATH=${REPO#$REGISTRY/} 94 95 REFERRERS=$(curl -s "https://$REGISTRY/v2/$REPO_PATH/referrers/${DIGEST}?artifactType=application/vnd.atproto.signature.v1+json") 96 SIG_DIGEST=$(echo "$REFERRERS" | jq -r '.manifests[0].digest') 97 98 # Pull signature artifact 99 oras pull "${REPO}@${SIG_DIGEST}" -o /tmp/sig 100 101 # Extract DID 102 DID=$(jq -r '.atproto.did' /tmp/sig/atproto-signature.json) 103 echo "Signed by DID: $DID" 104 105 # Check against trusted DIDs (from CI/CD variables) 106 if [[ ",$TRUSTED_DIDS," == *",$DID,"* ]]; then 107 echo "✓ DID is trusted" 108 else 109 echo "❌ DID $DID is not in trusted list" 110 exit 1 111 fi 112 113deploy_production: 114 stage: deploy 115 image: bitnami/kubectl:latest 116 dependencies: 117 - verify_signature 118 - verify_full 119 - verify_trust 120 only: 121 - main 122 script: 123 - | 124 # Configure kubectl 125 echo "$KUBE_CONFIG" | base64 -d > /tmp/kubeconfig 126 export KUBECONFIG=/tmp/kubeconfig 127 128 # Deploy to production 129 kubectl set image deployment/myapp \ 130 myapp=$IMAGE_TAG \ 131 -n production 132 133 kubectl rollout status deployment/myapp -n production 134 135 # Verify deployment 136 kubectl get pods -n production -l app=myapp 137 138# Alternative: Manual approval before deploy 139deploy_production_manual: 140 stage: deploy 141 image: bitnami/kubectl:latest 142 dependencies: 143 - verify_signature 144 when: manual 145 only: 146 - main 147 script: 148 - | 149 echo "Deploying $IMAGE_TAG to production" 150 151 echo "$KUBE_CONFIG" | base64 -d > /tmp/kubeconfig 152 export KUBECONFIG=/tmp/kubeconfig 153 154 kubectl set image deployment/myapp \ 155 myapp=$IMAGE_TAG \ 156 -n production