Skip to content

chore(deps): bump activestorage from 8.0.2.1 to 8.0.4.1 in /docker/pghero/app #277

chore(deps): bump activestorage from 8.0.2.1 to 8.0.4.1 in /docker/pghero/app

chore(deps): bump activestorage from 8.0.2.1 to 8.0.4.1 in /docker/pghero/app #277

Workflow file for this run

# SPDX-FileCopyrightText: 2025 Blackcat Informatics® Inc.
# SPDX-License-Identifier: MIT
name: CI
permissions:
contents: read
on:
push:
branches: [ main ]
pull_request:
jobs:
docker-build:
name: Validate Docker Build
runs-on: ubuntu-latest
outputs:
stack_tag: ${{ steps.stack-build.outputs.stack_tag }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Reset secrets directory
run: rm -rf ./secrets && mkdir -p ./secrets
- name: Generate .env and secrets
run: ./scripts/manage.sh create-env --non-interactive --force
- name: Export build env
run: |
set -a
source .env
set +a
{
echo "POSTGRES_UID=${POSTGRES_UID:-$(id -u)}"
echo "POSTGRES_GID=${POSTGRES_GID:-$(id -g)}"
echo "POSTGRES_RUNTIME_USER=${POSTGRES_RUNTIME_USER:-postgres}"
echo "POSTGRES_RUNTIME_GECOS=${POSTGRES_RUNTIME_GECOS:-Core Data PostgreSQL Administrator}"
echo "POSTGRES_RUNTIME_HOME=${POSTGRES_RUNTIME_HOME:-/home/postgres}"
echo "PG_VERSION=${PG_VERSION:-17}"
echo "AGE_VERSION=${AGE_VERSION:-master}"
} >> "$GITHUB_ENV"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build stack images
id: stack-build
env:
STACK_REGISTRY: ghcr.io/${{ github.repository }}
run: |
set -euo pipefail
STACK_TAG="${GITHUB_SHA}"
echo "stack_tag=${STACK_TAG}" >>"$GITHUB_OUTPUT"
SERVICES=("postgres" "valkey" "pgbouncer" "rabbitmq" "memcached" "pghero" "network-probe" "network-guard")
mkdir -p stack-images
for service in "${SERVICES[@]}"; do
case "${service}" in
postgres)
docker buildx build --load \
--platform linux/amd64 \
--file postgres/Dockerfile \
--build-arg CORE_UID="${POSTGRES_UID:-$(id -u)}" \
--build-arg CORE_GID="${POSTGRES_GID:-$(id -g)}" \
--build-arg CORE_USERNAME="${POSTGRES_RUNTIME_USER:-postgres}" \
--build-arg CORE_GECOS="${POSTGRES_RUNTIME_GECOS:-Core Data PostgreSQL Administrator}" \
--build-arg CORE_HOME="${POSTGRES_RUNTIME_HOME:-/home/postgres}" \
--build-arg PG_VERSION="${PG_VERSION:-17}" \
--build-arg AGE_VERSION="${AGE_VERSION:-master}" \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
valkey)
docker buildx build --load \
--platform linux/amd64 \
--file docker/valkey/Dockerfile \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
pgbouncer)
docker buildx build --load \
--platform linux/amd64 \
--file docker/pgbouncer/Dockerfile \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
rabbitmq)
docker buildx build --load \
--platform linux/amd64 \
--file docker/rabbitmq/Dockerfile \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
memcached)
docker buildx build --load \
--platform linux/amd64 \
--file docker/memcached/Dockerfile \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
pghero)
docker buildx build --load \
--platform linux/amd64 \
--file docker/pghero/Dockerfile \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
network-probe)
docker buildx build --load \
--platform linux/amd64 \
--file docker/network-probe/Dockerfile \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
network-guard)
docker buildx build --load \
--platform linux/amd64 \
--file docker/network-guard/Dockerfile \
--tag "${STACK_REGISTRY}/${service}:${STACK_TAG}" \
.
;;
esac
docker save "${STACK_REGISTRY}/${service}:${STACK_TAG}" -o "stack-images/${service}.tar"
done
{
echo "CORE_DATA_STACK_TAG=${STACK_TAG}"
echo "CORE_DATA_STACK_REGISTRY=${STACK_REGISTRY}"
echo "POSTGRES_IMAGE_NAME=${STACK_REGISTRY}/postgres"
echo "POSTGRES_IMAGE_TAG=${STACK_TAG}"
echo "CORE_DATA_IMAGE=${STACK_REGISTRY}/postgres"
echo "CORE_DATA_TAG=${STACK_TAG}"
echo "VALKEY_IMAGE=${STACK_REGISTRY}/valkey:${STACK_TAG}"
echo "PGBOUNCER_IMAGE=${STACK_REGISTRY}/pgbouncer:${STACK_TAG}"
echo "RABBITMQ_IMAGE=${STACK_REGISTRY}/rabbitmq:${STACK_TAG}"
echo "MEMCACHED_IMAGE=${STACK_REGISTRY}/memcached:${STACK_TAG}"
echo "PGHERO_IMAGE=${STACK_REGISTRY}/pghero:${STACK_TAG}"
echo "NETWORK_PROBE_IMAGE=${STACK_REGISTRY}/network-probe:${STACK_TAG}"
echo "NETWORK_GUARD_IMAGE=${STACK_REGISTRY}/network-guard:${STACK_TAG}"
} >>"$GITHUB_ENV"
- name: Smoke-test Docker image
env:
PGPASSWORD: thinice-test
run: |
set -euo pipefail
set -a
source .env
set +a
cleanup() { docker rm -f postgres-smoke >/dev/null 2>&1 || true; }
trap cleanup EXIT
image="${POSTGRES_IMAGE_NAME}:${POSTGRES_IMAGE_TAG}"
docker run -d --name postgres-smoke \
-e POSTGRES_USER=thinice-test \
-e POSTGRES_PASSWORD=thinice-test \
-e POSTGRES_DB=thinice-test \
-e CORE_DATA_SKIP_CONFIG_RENDER=1 \
"${image}"
tries=0
max_tries=150
until docker exec postgres-smoke pg_isready -h localhost -U thinice-test >/dev/null 2>&1; do
tries=$((tries + 1))
if ((tries >= max_tries)); then
echo "[smoke] postgres-smoke never became ready; printing logs."
docker logs postgres-smoke || true
exit 1
fi
sleep 2
done
docker exec postgres-smoke psql -U thinice-test -d thinice-test -c "SELECT 1" >/dev/null
- name: Stop Docker smoke container
if: always()
run: docker rm -f postgres-smoke >/dev/null 2>&1 || true
- name: Upload stack image artifacts
uses: actions/upload-artifact@v4
with:
name: stack-images
path: stack-images
- name: Collect diagnostics bundle
if: failure()
run: ./scripts/collect_diagnostics.sh --output diagnostics-docker-build
- name: Upload diagnostics bundle
if: failure()
uses: actions/upload-artifact@v4
with:
name: diagnostics-docker-build
path: diagnostics-docker-build
- name: Validate Dockerfile with hadolint
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: postgres/Dockerfile
config: .hadolint.yaml
smoke:
name: Smoke (${{ matrix.profile_name }})
runs-on: ubuntu-latest
needs:
- docker-build
strategy:
fail-fast: false
matrix:
include:
- profile_name: full
compose_profiles: "valkey,pgbouncer,memcached"
- profile_name: minimal
compose_profiles: ""
env:
TEST_COMPOSE_PROFILES: ${{ matrix.compose_profiles }}
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Reset secrets directory
run: rm -rf ./secrets && mkdir -p ./secrets
- name: Generate .env and secrets
run: ./scripts/manage.sh create-env --non-interactive --force
- name: Download stack images
uses: actions/download-artifact@v4
with:
name: stack-images
path: stack-images
- name: Load stack images
run: for image_tar in stack-images/*.tar; do docker load --input "$image_tar"; done
- name: Pin stack images
run: |
cat <<'EOF' >> .env
CORE_DATA_STACK_REGISTRY=ghcr.io/${{ github.repository }}
CORE_DATA_STACK_TAG=${{ needs.docker-build.outputs.stack_tag }}
POSTGRES_IMAGE_NAME=ghcr.io/${{ github.repository }}/postgres
POSTGRES_IMAGE_TAG=${{ needs.docker-build.outputs.stack_tag }}
CORE_DATA_IMAGE=ghcr.io/${{ github.repository }}/postgres
CORE_DATA_TAG=${{ needs.docker-build.outputs.stack_tag }}
VALKEY_IMAGE=ghcr.io/${{ github.repository }}/valkey:${{ needs.docker-build.outputs.stack_tag }}
PGBOUNCER_IMAGE=ghcr.io/${{ github.repository }}/pgbouncer:${{ needs.docker-build.outputs.stack_tag }}
RABBITMQ_IMAGE=ghcr.io/${{ github.repository }}/rabbitmq:${{ needs.docker-build.outputs.stack_tag }}
MEMCACHED_IMAGE=ghcr.io/${{ github.repository }}/memcached:${{ needs.docker-build.outputs.stack_tag }}
PGHERO_IMAGE=ghcr.io/${{ github.repository }}/pghero:${{ needs.docker-build.outputs.stack_tag }}
NETWORK_PROBE_IMAGE=ghcr.io/${{ github.repository }}/network-probe:${{ needs.docker-build.outputs.stack_tag }}
NETWORK_GUARD_IMAGE=ghcr.io/${{ github.repository }}/network-guard:${{ needs.docker-build.outputs.stack_tag }}
EOF
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Cache uv
uses: actions/cache@v4
with:
path: ~/.cache/uv
key: ${{ runner.os }}-uv-3.12-${{ hashFiles('pyproject.toml', 'uv.lock') }}
restore-keys: |
${{ runner.os }}-uv-3.12-
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Sync dependencies
run: uv sync --dev
- name: Preflight stack bring-up
id: bringup-smoke
run: |
set -euo pipefail
cleanup() { ./scripts/manage.sh down >/dev/null 2>&1 || true; }
trap cleanup EXIT
if ! ./scripts/manage.sh up; then
mkdir -p bringup-logs
docker compose logs postgres | tee bringup-logs/postgres.log || true
docker compose logs pgbouncer | tee bringup-logs/pgbouncer.log || true
docker compose logs valkey | tee bringup-logs/valkey.log || true
docker compose logs rabbitmq | tee bringup-logs/rabbitmq.log || true
exit 1
fi
- name: Run core_data smoke workflow
run: uv run python -m pytest -k full_workflow --junitxml=report-smoke-${{ matrix.profile_name }}.xml
- name: Collect docker diagnostics
if: always()
run: |
mkdir -p diagnostics-smoke-${{ matrix.profile_name }}
docker ps -a > diagnostics-smoke-${{ matrix.profile_name }}/docker-ps.txt
docker compose logs > diagnostics-smoke-${{ matrix.profile_name }}/docker-compose.log || true
./scripts/collect_diagnostics.sh --output diagnostics-smoke-${{ matrix.profile_name }}/bundle || true
- name: Upload diagnostics bundle
if: always()
uses: actions/upload-artifact@v4
with:
name: diagnostics-smoke-${{ matrix.profile_name }}
path: diagnostics-smoke-${{ matrix.profile_name }}
- name: Upload generated backups
if: always()
uses: actions/upload-artifact@v4
with:
name: backups-${{ matrix.profile_name }}
path: backups
if-no-files-found: ignore
- name: Upload smoke JUnit report
if: always()
uses: actions/upload-artifact@v4
with:
name: report-smoke-${{ matrix.profile_name }}
path: report-smoke-${{ matrix.profile_name }}.xml
- name: Publish smoke summary
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const profile = process.env.MATRIX_PROFILE;
const reportPath = `report-smoke-${profile}.xml`;
if (!fs.existsSync(reportPath)) {
core.warning(`JUnit report not found at ${reportPath}`);
} else {
const report = fs.readFileSync(reportPath, 'utf8');
core.summary
.addHeading(`Smoke (${profile})`)
.addCodeBlock(report, 'xml')
.write();
}
env:
MATRIX_PROFILE: ${{ matrix.profile_name }}
- name: Upload bring-up logs
if: failure() && steps.bringup-smoke.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: bringup-logs-${{ matrix.profile_name }}
path: bringup-logs
markers:
name: Marker (${{ matrix.marker }})
runs-on: ubuntu-latest
needs:
- docker-build
strategy:
fail-fast: false
matrix:
marker: [security, backup, extensions, pool, pool_heavy, lint, config, ci]
env:
TEST_COMPOSE_PROFILES: "valkey,pgbouncer,memcached"
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Reset secrets directory
run: rm -rf ./secrets && mkdir -p ./secrets
- name: Generate .env and secrets
run: ./scripts/manage.sh create-env --non-interactive --force
- name: Download stack images
uses: actions/download-artifact@v4
with:
name: stack-images
path: stack-images
- name: Load stack images
run: for image_tar in stack-images/*.tar; do docker load --input "$image_tar"; done
- name: Pin stack images
run: |
cat <<'EOF' >> .env
CORE_DATA_STACK_REGISTRY=ghcr.io/${{ github.repository }}
CORE_DATA_STACK_TAG=${{ needs.docker-build.outputs.stack_tag }}
POSTGRES_IMAGE_NAME=ghcr.io/${{ github.repository }}/postgres
POSTGRES_IMAGE_TAG=${{ needs.docker-build.outputs.stack_tag }}
CORE_DATA_IMAGE=ghcr.io/${{ github.repository }}/postgres
CORE_DATA_TAG=${{ needs.docker-build.outputs.stack_tag }}
VALKEY_IMAGE=ghcr.io/${{ github.repository }}/valkey:${{ needs.docker-build.outputs.stack_tag }}
PGBOUNCER_IMAGE=ghcr.io/${{ github.repository }}/pgbouncer:${{ needs.docker-build.outputs.stack_tag }}
RABBITMQ_IMAGE=ghcr.io/${{ github.repository }}/rabbitmq:${{ needs.docker-build.outputs.stack_tag }}
MEMCACHED_IMAGE=ghcr.io/${{ github.repository }}/memcached:${{ needs.docker-build.outputs.stack_tag }}
PGHERO_IMAGE=ghcr.io/${{ github.repository }}/pghero:${{ needs.docker-build.outputs.stack_tag }}
NETWORK_PROBE_IMAGE=ghcr.io/${{ github.repository }}/network-probe:${{ needs.docker-build.outputs.stack_tag }}
NETWORK_GUARD_IMAGE=ghcr.io/${{ github.repository }}/network-guard:${{ needs.docker-build.outputs.stack_tag }}
EOF
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Cache uv
uses: actions/cache@v4
with:
path: ~/.cache/uv
key: ${{ runner.os }}-uv-3.12-${{ hashFiles('pyproject.toml', 'uv.lock') }}
restore-keys: |
${{ runner.os }}-uv-3.12-
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Install shellcheck
if: matrix.marker == 'lint'
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
- name: Sync dependencies
run: uv sync --dev
- name: Preflight stack bring-up
if: matrix.marker != 'ci'
id: bringup-marker
run: |
set -euo pipefail
cleanup() { ./scripts/manage.sh down >/dev/null 2>&1 || true; }
trap cleanup EXIT
if ! ./scripts/manage.sh up; then
mkdir -p bringup-logs
docker compose logs postgres | tee bringup-logs/postgres.log || true
docker compose logs pgbouncer | tee bringup-logs/pgbouncer.log || true
docker compose logs valkey | tee bringup-logs/valkey.log || true
docker compose logs rabbitmq | tee bringup-logs/rabbitmq.log || true
exit 1
fi
- name: Run marker tests
run: uv run python -m pytest -m ${{ matrix.marker }} --junitxml=report-marker-${{ matrix.marker }}.xml
- name: Collect docker diagnostics
if: matrix.marker != 'ci'
run: |
mkdir -p diagnostics-marker-${{ matrix.marker }}
docker ps -a > diagnostics-marker-${{ matrix.marker }}/docker-ps.txt
docker compose logs > diagnostics-marker-${{ matrix.marker }}/docker-compose.log || true
./scripts/collect_diagnostics.sh --output diagnostics-marker-${{ matrix.marker }}/bundle || true
- name: Upload diagnostics bundle
if: matrix.marker != 'ci'
uses: actions/upload-artifact@v4
with:
name: diagnostics-marker-${{ matrix.marker }}
path: diagnostics-marker-${{ matrix.marker }}
- name: Upload bring-up logs
if: matrix.marker != 'ci' && failure() && steps.bringup-marker.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: bringup-logs-${{ matrix.marker }}
path: bringup-logs
- name: Upload marker JUnit report
if: always()
uses: actions/upload-artifact@v4
with:
name: report-marker-${{ matrix.marker }}
path: report-marker-${{ matrix.marker }}.xml
- name: Publish marker summary
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const reportPath = `report-marker-${process.env.MATRIX_MARKER}.xml`;
if (!fs.existsSync(reportPath)) {
core.warning(`JUnit report not found at ${reportPath}`);
} else {
const report = fs.readFileSync(reportPath, 'utf8');
core.summary
.addHeading(`Marker (${process.env.MATRIX_MARKER})`)
.addCodeBlock(report, 'xml')
.write();
}
env:
MATRIX_MARKER: ${{ matrix.marker }}