diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index e38c925..3e98ec8 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -16,6 +16,8 @@ jobs: runs-on: ubuntu-latest permissions: contents: read + id-token: write + attestations: write env: # Optional repo variable. If unset, DOCKERHUB_USERNAME is used. @@ -70,6 +72,13 @@ jobs: context: ./backend file: ./backend/Dockerfile push: true + provenance: mode=max + sbom: true + labels: | + org.opencontainers.image.title=NexaPG Backend + org.opencontainers.image.vendor=Nesterovic IT-Services e.U. + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + org.opencontainers.image.version=${{ steps.ver.outputs.clean }} tags: | ${{ steps.ns.outputs.value }}/nexapg-backend:${{ steps.ver.outputs.clean }} ${{ steps.ns.outputs.value }}/nexapg-backend:latest @@ -82,8 +91,15 @@ jobs: context: ./frontend file: ./frontend/Dockerfile push: true + provenance: mode=max + sbom: true build-args: | VITE_API_URL=/api/v1 + labels: | + org.opencontainers.image.title=NexaPG Frontend + org.opencontainers.image.vendor=Nesterovic IT-Services e.U. + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + org.opencontainers.image.version=${{ steps.ver.outputs.clean }} tags: | ${{ steps.ns.outputs.value }}/nexapg-frontend:${{ steps.ver.outputs.clean }} ${{ steps.ns.outputs.value }}/nexapg-frontend:latest diff --git a/.github/workflows/pg-compat-matrix.yml b/.github/workflows/pg-compat-matrix.yml index ae28fa8..3dc9954 100644 --- a/.github/workflows/pg-compat-matrix.yml +++ b/.github/workflows/pg-compat-matrix.yml @@ -2,7 +2,7 @@ name: PostgreSQL Compatibility Matrix on: push: - branches: ["main", "master"] + branches: ["main", "master", "development"] pull_request: jobs: @@ -67,3 +67,65 @@ jobs: env: PG_DSN_CANDIDATES: postgresql://postgres:postgres@postgres:5432/compatdb?sslmode=disable,postgresql://postgres:postgres@127.0.0.1:5432/compatdb?sslmode=disable run: python backend/scripts/pg_compat_smoke.py + + backend-alpine-smoke: + name: Backend Alpine smoke (PG16) + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:16 + env: + POSTGRES_DB: compatdb + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U postgres -d compatdb" + --health-interval 5s + --health-timeout 5s + --health-retries 20 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Enable pg_stat_statements in service container + run: | + PG_CID="$(docker ps --filter "ancestor=postgres:16" --format "{{.ID}}" | head -n1)" + if [ -z "$PG_CID" ]; then + echo "Could not find postgres service container for version 16" + docker ps -a + exit 1 + fi + + echo "Using postgres container: $PG_CID" + docker exec "$PG_CID" psql -U postgres -d compatdb -c "ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';" + docker restart "$PG_CID" + + for i in $(seq 1 40); do + if docker exec "$PG_CID" pg_isready -U postgres -d compatdb; then + break + fi + sleep 2 + done + + docker exec "$PG_CID" psql -U postgres -d compatdb -c "CREATE EXTENSION IF NOT EXISTS pg_stat_statements;" + + - name: Build backend image with Alpine base + run: | + docker build \ + -f backend/Dockerfile \ + --build-arg PYTHON_BASE_IMAGE=python:3.13-alpine \ + -t nexapg-backend-alpine-smoke:ci \ + ./backend + + - name: Run smoke checks in backend Alpine image + env: + PG_DSN_CANDIDATES: postgresql://postgres:postgres@127.0.0.1:5432/compatdb?sslmode=disable + run: | + docker run --rm --network host \ + -e PG_DSN_CANDIDATES="${PG_DSN_CANDIDATES}" \ + nexapg-backend-alpine-smoke:ci \ + python /app/scripts/pg_compat_smoke.py diff --git a/backend/Dockerfile b/backend/Dockerfile index e3057c6..8104270 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,5 @@ -FROM python:3.13-slim AS base +ARG PYTHON_BASE_IMAGE=python:3.13-slim +FROM ${PYTHON_BASE_IMAGE} AS base ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 @@ -6,11 +7,17 @@ ENV PIP_NO_CACHE_DIR=1 WORKDIR /app -RUN apt-get update \ - && apt-get upgrade -y \ - && rm -rf /var/lib/apt/lists/* +RUN if command -v apt-get >/dev/null 2>&1; then \ + apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*; \ + elif command -v apk >/dev/null 2>&1; then \ + apk upgrade --no-cache; \ + fi -RUN addgroup --system app && adduser --system --ingroup app app +RUN if addgroup --help 2>&1 | grep -q -- '--system'; then \ + addgroup --system app && adduser --system --ingroup app app; \ + else \ + addgroup -S app && adduser -S -G app app; \ + fi COPY requirements.txt /app/requirements.txt RUN pip install --upgrade pip && pip install -r /app/requirements.txt