Files
SkyMoney/.gitea/workflows/deploy.yml
Ricearoni1245 47bc092da1
All checks were successful
Deploy / deploy (push) Successful in 1m29s
Security Tests / security-non-db (push) Successful in 23s
Security Tests / security-db (push) Successful in 33s
first attempt at fixing over-allocation bug; fix npm audit block for deploy
2026-04-02 22:06:35 -05:00

116 lines
4.1 KiB
YAML

name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: vps-host
steps:
- uses: actions/checkout@v4.2.2
- name: Supply chain checks (production dependencies)
run: |
set -euo pipefail
cd api
npm ci
npm audit --omit=dev --audit-level=high --json > /tmp/skymoney-api-audit.json || true
node -e '
const fs = require("fs");
const report = JSON.parse(fs.readFileSync("/tmp/skymoney-api-audit.json", "utf8"));
const vulnerabilities = report.vulnerabilities || {};
const allowlisted = new Set(["fast-jwt", "@fastify/jwt"]);
const blockers = [];
for (const [name, vuln] of Object.entries(vulnerabilities)) {
const severity = String(vuln?.severity || "").toLowerCase();
if (severity !== "high" && severity !== "critical") continue;
if (allowlisted.has(name)) continue;
blockers.push({ name, severity });
}
if (blockers.length > 0) {
console.error("Blocking high/critical vulnerabilities found:");
for (const blocker of blockers) {
console.error(` - ${blocker.name} (${blocker.severity})`);
}
process.exit(1);
}
const allowedPresent = Object.keys(vulnerabilities).filter((name) => allowlisted.has(name));
if (allowedPresent.length > 0) {
console.warn("Allowed advisory exception(s) present:", allowedPresent.join(", "));
} else {
console.log("No allowlisted API advisories present.");
}
'
cd ../web
npm ci
npm audit --omit=dev --audit-level=high
- name: Build Web
run: |
cd web
npm run build
- name: Deploy with Docker Compose
run: |
set -euo pipefail
# Fail fast if sudo requires interactive password in runner context
sudo -n docker ps >/dev/null
# Deploy directory
APP_DIR=/opt/skymoney
mkdir -p $APP_DIR
# Sync repo to server (excluding node_modules, dist, etc)
rsync -a --delete \
--exclude=node_modules \
--exclude=dist \
--exclude=.git \
--exclude=.gitea \
--exclude=backups \
--exclude=forensics \
--exclude=exporting \
./ $APP_DIR/
# Copy built web to shared volume
mkdir -p /var/www/skymoney/dist
cp -r web/dist/* /var/www/skymoney/dist/
cd $APP_DIR
# Validate migration target before touching containers
export EXPECTED_PROD_DB_HOST="${EXPECTED_PROD_DB_HOST:-postgres}"
export EXPECTED_PROD_DB_NAME="${EXPECTED_PROD_DB_NAME:-skymoney}"
chmod +x ./scripts/validate-prod-db-target.sh ./scripts/guard-prod-volume.sh ./scripts/backup.sh
bash ./scripts/validate-prod-db-target.sh
PROD_DB_VOLUME_NAME="${PROD_DB_VOLUME_NAME:-skymoney_pgdata}" \
ALLOW_EMPTY_PROD_VOLUME="${ALLOW_EMPTY_PROD_VOLUME:-0}" \
PROD_VOLUME_GUARD_TIMEOUT_SEC="${PROD_VOLUME_GUARD_TIMEOUT_SEC:-20}" \
DOCKER_CMD="sudo -n docker" \
bash ./scripts/guard-prod-volume.sh
# Build and start all services
sudo -n docker-compose -p skymoney up -d --build
# Wait for database to be ready
sleep 10
# Mandatory pre-migration backup
export EXPECTED_BACKUP_DB_HOST="${EXPECTED_BACKUP_DB_HOST:-127.0.0.1}"
export EXPECTED_BACKUP_DB_NAME="${EXPECTED_BACKUP_DB_NAME:-skymoney}"
BACKUP_ENFORCE_TARGET_CHECK=1 \
EXPECTED_BACKUP_DB_HOST="$EXPECTED_BACKUP_DB_HOST" \
EXPECTED_BACKUP_DB_NAME="$EXPECTED_BACKUP_DB_NAME" \
BACKUP_DIR=/opt/skymoney/backups \
bash ./scripts/backup.sh
# Run Prisma migrations inside the API container
sudo -n docker-compose -p skymoney exec -T api npx prisma migrate deploy
- name: Reload Nginx
run: sudo systemctl reload nginx