Add a Docker build workflow that publishes to GHCR #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Build the container image and push it to GHCR. | |
| # | |
| # Build only. Deployment is a separate, manually triggered workflow, so a push | |
| # never changes what is running on a server. | |
| # | |
| # Upstream's pipeline.yml does the same job but triggers on `dev` and `preprod`, | |
| # branches this fork does not have, so it has never run here. Rather than edit a | |
| # tracked upstream file and inherit a conflict on every rebase, this workflow | |
| # sits alongside it and triggers on the branches this fork actually uses. | |
| # | |
| # Images land at ghcr.io/grnet/eudi-srv-web-issuing-eudiw-py, tagged by branch, | |
| # by commit SHA, and as `latest` on the default branch. The SHA tag is the one | |
| # worth deploying: it names exactly one build. | |
| name: Docker build | |
| on: | |
| push: | |
| branches: | |
| - local-deploy-snf-74864-1.2 | |
| - 'feat/**' | |
| paths-ignore: | |
| - '**.md' | |
| - '.gitignore' | |
| pull_request: | |
| paths-ignore: | |
| - '**.md' | |
| - '.gitignore' | |
| workflow_dispatch: | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| build: | |
| name: Build and push | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Check out code | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3.10.0 | |
| # Pull requests from forks cannot read secrets, and pushing an image from | |
| # unreviewed code is not something to do by default. Those builds run to | |
| # prove the Dockerfile still works, and stop short of publishing. | |
| - name: Log in to GitHub Container Registry | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@v3.4.0 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@v5.7.0 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=sha,format=long | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build and push | |
| uses: docker/build-push-action@v6.15.0 | |
| with: | |
| context: . | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| provenance: false | |
| # The image is only useful if it starts. The issuer needs TLS material, | |
| # its document-signing material, and a rendered config, so the smoke test | |
| # supplies exactly what compose does: a throwaway certificate, the output | |
| # of pki/bootstrap.sh, and the config template the entrypoint renders. | |
| - name: Smoke test the image | |
| if: github.event_name != 'pull_request' | |
| run: | | |
| set -euo pipefail | |
| IMAGE=$(printf '%s' "${{ steps.meta.outputs.tags }}" | head -1) | |
| echo "Testing $IMAGE" | |
| ./pki/bootstrap.sh | |
| mkdir -p /tmp/tls | |
| openssl req -x509 -newkey rsa:2048 -sha256 -days 1 -nodes \ | |
| -keyout /tmp/tls/issuer.key -out /tmp/tls/issuer.crt \ | |
| -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost" 2>/dev/null | |
| cp /tmp/tls/issuer.crt /tmp/tls/ca-bundle.pem | |
| chmod 644 /tmp/tls/* | |
| docker run -d --name smoke \ | |
| -e CONFIG_TEMPLATE=/tmp/config.yaml.template \ | |
| -e ISSUER_CONFIG_PATH=/config.yaml \ | |
| -e ISSUER_PUBLIC_URL=https://localhost:5600 \ | |
| -e OIDC_PUBLIC_URL=https://localhost:5601 \ | |
| -e OIDC_INTERNAL_URL=https://localhost:5601 \ | |
| -e FRONTEND_PUBLIC_URL=https://localhost:5602 \ | |
| -e STATUSLIST_PUBLIC_URL=https://localhost:5603 \ | |
| -e ISSUER_HOST=localhost \ | |
| -v /tmp/tls:/etc/eudiw/tls:ro \ | |
| -v "$PWD/pki/out/eudiw:/etc/eudiw/pid-issuer-dev:ro" \ | |
| -v "$PWD/docker/config.yaml.template:/tmp/config.yaml.template:ro" \ | |
| --entrypoint /usr/local/bin/entrypoint.sh \ | |
| "$IMAGE" \ | |
| flask --app app:create_app run --host=0.0.0.0 --port=5600 \ | |
| --cert=/etc/eudiw/tls/issuer.crt --key=/etc/eudiw/tls/issuer.key | |
| for i in $(seq 1 40); do | |
| if docker exec smoke python3 -c " | |
| import urllib.request, ssl | |
| ctx = ssl._create_unverified_context() | |
| urllib.request.urlopen('https://localhost:5600/.well-known/openid-credential-issuer', context=ctx, timeout=5) | |
| " 2>/dev/null; then | |
| echo "Service answered after ${i}s" | |
| docker rm -f smoke >/dev/null | |
| exit 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo "::error::the service did not answer within 40s" | |
| docker logs smoke | |
| docker rm -f smoke >/dev/null | |
| exit 1 |