99 lines
4.9 KiB
YAML

name: Build and verify web migration
on:
push:
branches: [main, 'codex/**']
tags: ['[0-9]+.[0-9]+.[0-9]+']
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
verify:
runs-on: ubuntu-latest
services:
mongo:
image: mongo:8.0
ports: ['27017:27017']
options: >-
--health-cmd "mongosh --quiet --eval 'db.adminCommand({ping:1}).ok'"
--health-interval 10s --health-timeout 5s --health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with: { dotnet-version: '10.0.x' }
- uses: actions/setup-node@v4
with: { node-version: '22', cache: npm, cache-dependency-path: web/package-lock.json }
- name: Build services
run: dotnet build src/GuestOps.Worker/GuestOps.Worker.csproj -c Release
- name: Verify backup validation and failure recovery
run: python3 -m unittest discover -s tests -p 'test_*.py'
- name: Build interface
working-directory: web
run: npm ci && npm run build
- name: Start isolated preview API
run: |
ASPNETCORE_ENVIRONMENT=Development Preview=true dotnet src/GuestOps.Api/bin/Release/net10.0/GuestOps.Api.dll --urls http://127.0.0.1:5180 > /tmp/guestops-api.log 2>&1 &
for i in $(seq 1 30); do curl -fsS http://127.0.0.1:5180/health && exit 0; sleep 1; done
cat /tmp/guestops-api.log
exit 1
- name: Verify MongoDB and HTTP boundaries
env:
MONGO_TEST_URI: mongodb://127.0.0.1:27017
TEST_API_URL: http://127.0.0.1:5180
run: dotnet run --project tests/GuestOps.Tests/GuestOps.Tests.csproj -c Release
- name: Build Linux images
run: |
docker build --target api -t guestops-api:${{ github.sha }} .
docker build --target worker -t guestops-worker:${{ github.sha }} .
- name: Package reviewed images
if: github.event_name != 'pull_request'
run: |
docker save guestops-api:${{ github.sha }} guestops-worker:${{ github.sha }} | gzip -n > guestops-images.tar.gz
python3 deploy/release_record.py \
--artifact guestops-images.tar.gz \
--commit '${{ github.sha }}' \
--api-image 'guestops-api:${{ github.sha }}' \
--api-id "$(docker image inspect --format '{{.Id}}' 'guestops-api:${{ github.sha }}')" \
--worker-image 'guestops-worker:${{ github.sha }}' \
--worker-id "$(docker image inspect --format '{{.Id}}' 'guestops-worker:${{ github.sha }}')" \
--output release-record.json
sha256sum --check <(python3 -c "import json; r=json.load(open('release-record.json')); print(r['artifact']['sha256'] + ' ' + r['artifact']['name'])")
- name: Smoke test production containers and restart persistence
env:
GUESTOPS_API_IMAGE: guestops-api:${{ github.sha }}
GUESTOPS_WORKER_IMAGE: guestops-worker:${{ github.sha }}
BOOTSTRAP_EMAIL: ci-owner@example.invalid
BOOTSTRAP_HOTEL: CI test hotel
run: |
export MONGO_ROOT_PASSWORD=$(openssl rand -hex 32)
export MONGO_APP_PASSWORD=$(openssl rand -hex 32)
export BOOTSTRAP_PASSWORD=$(openssl rand -hex 24)
trap 'docker compose down --volumes' EXIT
docker compose config --quiet
docker compose up -d --no-build
curl --retry 30 --retry-delay 2 --retry-all-errors --fail http://127.0.0.1:8080/health
docker compose run --rm --no-deps -e BOOTSTRAP_EMAIL -e BOOTSTRAP_HOTEL -e BOOTSTRAP_PASSWORD api --bootstrap
python3 tests/production_smoke.py
docker compose restart api worker
curl --retry 30 --retry-delay 2 --retry-all-errors --fail http://127.0.0.1:8080/health
python3 tests/production_smoke.py --read
install -m 600 /dev/null .env
python3 deploy/ops.py preflight --offline
mkdir -m 700 .guestops-test-keyring
export GNUPGHOME="$PWD/.guestops-test-keyring"
gpg --batch --pinentry-mode loopback --passphrase '' --quick-generate-key 'GuestOps CI <ci@example.invalid>' rsa2048 encr 1d
BACKUP_RECIPIENT=$(gpg --batch --with-colons --list-keys | awk -F: '$1=="fpr" {print $10; exit}')
backup_dir=$(mktemp -d)
python3 deploy/ops.py backup --recipient "$BACKUP_RECIPIENT" --output "$backup_dir/fixture.tar.gpg" --confirm-maintenance
python3 deploy/ops.py restore-drill "$backup_dir/fixture.tar.gpg" --api-image "$GUESTOPS_API_IMAGE"
curl --retry 30 --retry-delay 2 --retry-all-errors --fail http://127.0.0.1:8080/health/ready
python3 tests/production_smoke.py --read
- uses: actions/upload-artifact@v4
if: github.event_name != 'pull_request'
with:
name: guestops-linux-${{ github.run_number }}
path: |
guestops-images.tar.gz
release-record.json
retention-days: 90