name: Podman Rootless Demo on: [push, pull_request] jobs: test-backend: runs-on: [ci] if: false # Point all steps at the host's rootless Podman socket env: # Point the client at the mounted socket CONTAINER_HOST: unix:///run/user/1001/podman/podman.sock # Make sure podman looks in the correct runtime dir hierarchy XDG_RUNTIME_DIR: /tmp RUN_ID: ${{ github.run_id }} POSTGRES_IMG_DIGEST: ${{ secrets.POSTGRES_IMG_DIGEST }} RUST_IMG_DIGEST: ${{ secrets.RUST_IMG_DIGEST }} PREBUILT_BACKEND_TEST_IMAGE: ${{ secrets.REGISTRY_HOST }}/${{ github.repository }}/sharenet-test-rust CACHE_REPO: ${{ secrets.REGISTRY_HOST }}/${{ github.repository }}/sharenet-test-rust-cache steps: - name: Checkout code uses: actions/checkout@v4 - name: Verify socket visibility run: | set -euo pipefail id -u; id -g ls -ld /run/user/1001/podman ls -l /run/user/1001/podman/podman.sock test -S /run/user/1001/podman/podman.sock - name: Use host rootless Podman run: | set -euo pipefail podman --remote info --format '{{.Host.RemoteSocket.Path}} (remote={{.Host.RemoteSocket.Exists}})' podman --remote version podman --remote run --rm alpine:3.20 echo "Hello from host rootless Podman!" - name: Login to container registry with PAT run: | echo "${{ secrets.REGISTRY_TOKEN }}" | podman --remote login \ -u "${{ secrets.REGISTRY_USERNAME }}" \ --password-stdin \ "${{ secrets.REGISTRY_HOST }}" - name: Create network run: podman --remote network create integ-${{ env.RUN_ID }} - name: Generate cache key from lockfile id: cache-key run: | cd "$GITHUB_WORKSPACE/backend" LOCK_HASH=$(sha256sum Cargo.lock | cut -d' ' -f1) SHORT_HASH=$(echo "$LOCK_HASH" | cut -c1-12) echo "cache_key=$SHORT_HASH" >> $GITHUB_OUTPUT echo "Using cache key: $SHORT_HASH" - name: Build dependencies cache image run: | # Build deps stage with layer caching podman --remote build \ --layers \ --cache-to "$CACHE_REPO" \ --cache-from "$CACHE_REPO" \ --target deps \ -f Dockerfile.test-rust \ -t "$PREBUILT_BACKEND_TEST_IMAGE:deps-${{ steps.cache-key.outputs.cache_key }}" \ backend podman --remote push \ "$PREBUILT_BACKEND_TEST_IMAGE:deps-${{ steps.cache-key.outputs.cache_key }}" - name: Build full test image with cached dependencies run: | # Build final image using cached deps podman --remote build \ --layers \ --cache-from "$CACHE_REPO" \ --target runner \ -f Dockerfile.test-rust \ -t "$PREBUILT_BACKEND_TEST_IMAGE:test-${{ github.sha }}" \ backend - name: Start PostgreSQL run: | podman --remote run -d \ --name test-postgres-${{ env.RUN_ID }} \ --network integ-${{ env.RUN_ID }} \ -e POSTGRES_PASSWORD=password \ -e POSTGRES_USER=postgres \ -e POSTGRES_DB=sharenet_test \ "$POSTGRES_IMG_DIGEST" - name: Wait for PostgreSQL run: | timeout 60 bash -euc ' until podman --remote exec test-postgres-${{ env.RUN_ID }} \ pg_isready -h 127.0.0.1 -p 5432 -U postgres; do sleep 1 done ' - name: Ensure host Cargo cache directory exists run: | podman --remote run --rm \ -v /home/ci-service/.cache:/c \ alpine:3.20 sh -lc 'mkdir -p /c/cargo' - name: Run backend tests run: | # Run tests in the pre-built test image podman --remote run --rm \ --network integ-${{ env.RUN_ID }} \ -e DATABASE_URL=postgres://postgres:password@test-postgres-${{ env.RUN_ID }}:5432/sharenet_test \ "$PREBUILT_BACKEND_TEST_IMAGE:test-${{ github.sha }}" - name: Cleanup if: always() run: | podman --remote rm -f test-postgres-${{ env.RUN_ID }} 2>/dev/null || true podman --remote network rm integ-${{ env.RUN_ID }} 2>/dev/null || true - name: Debug DB (on failure) if: failure() run: podman --remote logs --tail=200 test-postgres-${{ env.RUN_ID }} || true test-frontend: runs-on: [ci] if: false #needs: test-backend steps: - name: Checkout code uses: actions/checkout@v4 - name: Pass-through (no frontend tests yet) run: echo "Frontend tests placeholder - no tests implemented yet" build-backend: runs-on: [ci] if: false #needs: [test-backend, test-frontend] needs: [test-frontend] env: CONTAINER_HOST: unix:///run/user/1001/podman/podman.sock XDG_RUNTIME_DIR: /tmp RUN_ID: ${{ github.run_id }} BACKEND_IMAGE: ${{ secrets.REGISTRY_HOST }}/${{ github.repository }}/sharenet-backend-api-postgres steps: - name: Checkout code uses: actions/checkout@v4 - name: Login to container registry with PAT run: | echo "${{ secrets.REGISTRY_TOKEN }}" | podman --remote login \ -u "${{ secrets.REGISTRY_USERNAME }}" \ --password-stdin \ "${{ secrets.REGISTRY_HOST }}" - name: Build backend container image run: | podman --remote build \ -f backend/Dockerfile \ -t "$BACKEND_IMAGE:${{ github.sha }}" \ -t "$BACKEND_IMAGE:latest" \ backend - name: Push backend container image run: | podman --remote push "$BACKEND_IMAGE:${{ github.sha }}" podman --remote push "$BACKEND_IMAGE:latest" build-frontend: runs-on: [ci] if: false #needs: [test-backend, test-frontend] needs: [test-frontend] env: CONTAINER_HOST: unix:///run/user/1001/podman/podman.sock XDG_RUNTIME_DIR: /tmp RUN_ID: ${{ github.run_id }} FRONTEND_IMAGE: ${{ secrets.REGISTRY_HOST }}/${{ github.repository }}/sharenet-frontend steps: - name: Checkout code uses: actions/checkout@v4 - name: Login to container registry with PAT run: | echo "${{ secrets.REGISTRY_TOKEN }}" | podman --remote login \ -u "${{ secrets.REGISTRY_USERNAME }}" \ --password-stdin \ "${{ secrets.REGISTRY_HOST }}" - name: Build frontend container image run: | podman --remote build \ -f frontend/Dockerfile \ -t "$FRONTEND_IMAGE:${{ github.sha }}" \ -t "$FRONTEND_IMAGE:latest" \ frontend - name: Push frontend container image run: | podman --remote push "$FRONTEND_IMAGE:${{ github.sha }}" podman --remote push "$FRONTEND_IMAGE:latest" deploy-prod: runs-on: [prod] #needs: [build-backend, build-frontend] env: CONTAINER_HOST: unix:///run/user/1001/podman/podman.sock XDG_RUNTIME_DIR: /tmp RUN_ID: ${{ github.run_id }} APP_NAME: ${{ github.repository }} REGISTRY_HOST: ${{ secrets.REGISTRY_HOST }} IMAGE_TAG: latest POSTGRES_DATABASE_NAME: ${{ secrets.PROD_DB_DATABASE_NAME }} POSTGRES_USERNAME: ${{ secrets.PROD_DB_USERNAME }} POSTGRES_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }} POSTGRES_PORT: ${{ secrets.PROD_DB_PORT }} PROD_BACKEND_PORT: ${{ secrets.PROD_BACKEND_PORT }} PROD_FRONTEND_PORT: ${{ secrets.PROD_FRONTEND_PORT }} PROD_BACKEND_HOST: ${{ secrets.PROD_BACKEND_HOST }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Login to container registry with PAT run: | echo "${{ secrets.REGISTRY_TOKEN }}" | podman --remote login \ -u "${{ secrets.REGISTRY_USERNAME }}" \ --password-stdin \ "${{ secrets.REGISTRY_HOST }}" - name: Pull production images run: | podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-backend-api-postgres:$IMAGE_TAG" podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-frontend:$IMAGE_TAG" - name: Prepare in-pod nginx config on host run: | set -euo pipefail # create dir on host (via user namespace) podman --remote unshare mkdir -p /opt/sharenet/nginx /opt/sharenet/volumes/nginx-cache # render temp config (inside the job container) apk add --no-cache gettext >/dev/null envsubst < nginx/nginx.conf > /tmp/nginx.conf # write it onto the host podman --remote unshare sh -c 'cat > /opt/sharenet/nginx/nginx.conf' < /tmp/nginx.conf # reasonable perms for rootless mount podman --remote unshare chown -R 1001:1001 /opt/sharenet podman --remote unshare chmod 0755 /opt/sharenet /opt/sharenet/nginx /opt/sharenet/volumes /opt/sharenet/volumes/nginx-cache podman --remote unshare chmod 0644 /opt/sharenet/nginx/nginx.conf || true - name: Install envsubst (Alpine) run: apk add --no-cache gettext - name: Deploy production pod run: | # Process the pod template with environment variables envsubst < deploy/prod-pod.yml | podman --remote kube play -