167 lines
5.4 KiB
YAML
167 lines
5.4 KiB
YAML
# GitHub Actions workflow for verifying ATProto signatures
|
|
|
|
name: Verify and Deploy
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
env:
|
|
REGISTRY: atcr.io
|
|
IMAGE_NAME: ${{ github.repository }}
|
|
|
|
jobs:
|
|
verify-signature:
|
|
name: Verify Image Signature
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up image tag
|
|
id: vars
|
|
run: |
|
|
echo "IMAGE_TAG=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Install verification tools
|
|
run: |
|
|
# Install ORAS
|
|
curl -LO 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
|
|
sudo mv oras /usr/local/bin/
|
|
|
|
# Install crane
|
|
curl -sL "https://github.com/google/go-containerregistry/releases/download/v0.15.2/go-containerregistry_Linux_x86_64.tar.gz" > crane.tar.gz
|
|
tar -xzf crane.tar.gz
|
|
sudo mv crane /usr/local/bin/
|
|
|
|
# Install atcr-verify (when available)
|
|
# curl -LO https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify
|
|
# chmod +x atcr-verify
|
|
# sudo mv atcr-verify /usr/local/bin/
|
|
|
|
- name: Check for signature
|
|
id: check_signature
|
|
run: |
|
|
IMAGE="${{ steps.vars.outputs.IMAGE_TAG }}"
|
|
echo "Checking signature for $IMAGE"
|
|
|
|
# Get image digest
|
|
DIGEST=$(crane digest "$IMAGE")
|
|
echo "Image digest: $DIGEST"
|
|
|
|
# Check for ATProto signature using ORAS
|
|
REPO=$(echo "$IMAGE" | cut -d: -f1)
|
|
REFERRERS=$(curl -s "https://${{ env.REGISTRY }}/v2/${REPO#${{ env.REGISTRY }}/}/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"
|
|
echo "has_signature=false" >> $GITHUB_OUTPUT
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ Found $SIG_COUNT signature(s)"
|
|
echo "has_signature=true" >> $GITHUB_OUTPUT
|
|
|
|
- name: Verify signature (full verification)
|
|
if: steps.check_signature.outputs.has_signature == 'true'
|
|
run: |
|
|
IMAGE="${{ steps.vars.outputs.IMAGE_TAG }}"
|
|
|
|
# Option 1: Use atcr-verify CLI (when available)
|
|
# atcr-verify "$IMAGE" --policy .atcr/trust-policy.yaml
|
|
|
|
# Option 2: Use shell script
|
|
chmod +x examples/verification/atcr-verify.sh
|
|
./examples/verification/atcr-verify.sh "$IMAGE"
|
|
|
|
echo "✓ Signature verified successfully"
|
|
|
|
- name: Verify signer DID
|
|
if: steps.check_signature.outputs.has_signature == 'true'
|
|
run: |
|
|
IMAGE="${{ steps.vars.outputs.IMAGE_TAG }}"
|
|
|
|
# Get signature metadata
|
|
DIGEST=$(crane digest "$IMAGE")
|
|
REPO=$(echo "$IMAGE" | cut -d: -f1)
|
|
|
|
REFERRERS=$(curl -s "https://${{ env.REGISTRY }}/v2/${REPO#${{ env.REGISTRY }}/}/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
|
|
TRUSTED_DIDS="${{ secrets.TRUSTED_DIDS }}" # e.g., "did:plc:alice123,did:plc:bob456"
|
|
|
|
if [[ ",$TRUSTED_DIDS," == *",$DID,"* ]]; then
|
|
echo "✓ DID is trusted"
|
|
else
|
|
echo "❌ DID $DID is not in trusted list"
|
|
exit 1
|
|
fi
|
|
|
|
deploy:
|
|
name: Deploy to Kubernetes
|
|
needs: verify-signature
|
|
runs-on: ubuntu-latest
|
|
if: github.ref == 'refs/heads/main'
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up image tag
|
|
id: vars
|
|
run: |
|
|
echo "IMAGE_TAG=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Set up kubectl
|
|
uses: azure/setup-kubectl@v3
|
|
|
|
- name: Configure kubectl
|
|
run: |
|
|
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > /tmp/kubeconfig
|
|
export KUBECONFIG=/tmp/kubeconfig
|
|
|
|
- name: Deploy to production
|
|
run: |
|
|
kubectl set image deployment/myapp \
|
|
myapp=${{ steps.vars.outputs.IMAGE_TAG }} \
|
|
-n production
|
|
|
|
kubectl rollout status deployment/myapp -n production
|
|
|
|
- name: Verify deployment
|
|
run: |
|
|
kubectl get pods -n production -l app=myapp
|
|
|
|
# Wait for rollout to complete
|
|
kubectl wait --for=condition=available --timeout=300s \
|
|
deployment/myapp -n production
|
|
|
|
# Alternative: Use atcr-verify action (when available)
|
|
verify-with-action:
|
|
name: Verify with ATCR Action
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Verify image signature
|
|
# uses: atcr-io/atcr-verify-action@v1
|
|
# with:
|
|
# image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
|
# policy: .atcr/trust-policy.yaml
|
|
# fail-on-error: true
|
|
run: |
|
|
echo "TODO: Use official atcr-verify GitHub Action"
|