Files
portal/.github/workflows/f1-apply-via-superuser.yml
T
Дмитрий 8092bdb024 ops(incident): f1-apply-via-superuser workflow
ремонт: deploy.yml fail на F1 миграции — schema public требует postgres superuser, у crm_migrator нет прав на CREATE OR REPLACE FUNCTION

Applies F1 audit-chain advisory-lock migration via sudo -u postgres psql,
then INSERTs migration row so subsequent php artisan migrate skips it.
Workaround for prod deploy where crm_migrator can't modify public schema.
2026-05-29 13:03:05 +03:00

114 lines
3.9 KiB
YAML

name: Apply F1 audit-chain advisory-lock migration via postgres superuser
# Incident response: redeploy.yml fails on F1 migration because crm_migrator role
# lacks privilege to CREATE OR REPLACE FUNCTION в schema public.
# This workflow applies F1 migration SQL directly via sudo -u postgres psql,
# then INSERTs the migration row so subsequent `php artisan migrate` skips it.
#
# Ref: docs/superpowers/plans/2026-05-29-audit-chain-race-fix.md Task 2
# Migration file: app/database/migrations/2026_05_30_000001_add_advisory_lock_to_audit_chain_hash.php
on:
workflow_dispatch:
inputs:
confirm_apply:
description: 'Подтверждаю применение F1 миграции на проде'
required: true
default: 'false'
type: boolean
jobs:
apply:
runs-on: ubuntu-latest
timeout-minutes: 5
env:
LIDERRA_HOST: 111.88.246.137
LIDERRA_USER: ubuntu
CONFIRM: ${{ github.event.inputs.confirm_apply }}
steps:
- name: Guard
run: |
if [[ "$CONFIRM" != "true" ]]; then
echo "::error::confirm_apply=true required"
exit 1
fi
- name: Setup SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.LIDERRA_SSH_KEY }}" > ~/.ssh/liderra_deploy
chmod 600 ~/.ssh/liderra_deploy
ssh-keyscan -H ${{ env.LIDERRA_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
- name: Apply F1 SQL + register migration
run: |
ssh -i ~/.ssh/liderra_deploy ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }} \
"bash -s" <<'REMOTE' | tee /tmp/f1-apply.log
set +e
echo "=== 1. BEFORE: current audit_chain_hash function source ==="
sudo -u postgres psql -d liderra -c "\df+ public.audit_chain_hash" 2>&1 | head -20
echo
echo "=== 2. Apply F1 advisory-lock migration via sudo -u postgres ==="
sudo -u postgres psql -d liderra <<'SQL'
CREATE OR REPLACE FUNCTION public.audit_chain_hash() RETURNS trigger AS $$
DECLARE
prev_hash BYTEA;
lock_key BIGINT;
BEGIN
lock_key := ('x' || lpad(to_hex(TG_RELID::int), 16, '0'))::bit(64)::bigint;
PERFORM pg_advisory_xact_lock(lock_key);
EXECUTE format(
'SELECT log_hash FROM %I ORDER BY id DESC LIMIT 1',
TG_TABLE_NAME
) INTO prev_hash;
NEW.log_hash := digest(
COALESCE(prev_hash, ''::bytea) || NEW::text::bytea,
'sha256'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
SQL
APPLY_RC=$?
echo "Apply RC: $APPLY_RC"
echo
echo "=== 3. Verify function now contains pg_advisory_xact_lock ==="
sudo -u postgres psql -d liderra -c "SELECT pg_get_functiondef('public.audit_chain_hash'::regproc) LIKE '%pg_advisory_xact_lock%' AS has_lock"
echo
echo "=== 4. Register migration row (skip if already exists) ==="
sudo -u postgres psql -d liderra <<'SQL'
INSERT INTO migrations (migration, batch)
SELECT '2026_05_30_000001_add_advisory_lock_to_audit_chain_hash', COALESCE(MAX(batch),0)+1 FROM migrations
WHERE NOT EXISTS (
SELECT 1 FROM migrations WHERE migration = '2026_05_30_000001_add_advisory_lock_to_audit_chain_hash'
);
SELECT migration, batch FROM migrations WHERE migration LIKE '%advisory_lock%';
SQL
echo
echo "=== DONE ==="
REMOTE
- name: Print summary
if: always()
run: |
{
echo "## F1 migration apply"
echo
echo '```'
cat /tmp/f1-apply.log 2>/dev/null || echo "(no log)"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Cleanup SSH key
if: always()
run: rm -f ~/.ssh/liderra_deploy