002b8c4c35
.github/workflows/sql-runner.yml — универсальный SQL-runner для прод-операций через GitHub Actions (workflow_dispatch). Whitelist: SELECT/WITH/EXPLAIN (read-only) + targeted UPDATE/DELETE на 5 таблицах при confirm_mutating=true. docs/ops/2026-05-29-stage5-stuck-leads-cleanup.md — шаблон rollback log + инструкции для cleanup 2 застрявших supplier_leads (id=1110, 1157, ~256k failed_webhook_jobs). Root cause: поставщик crm.bp-gr.ru шлёт B1+SMS combo, constraint chk_supplier_projects_b1_not_for_sms запрещает (Finding 2 Stage 5). Task 1 plan 2026-05-29-supplier-webhook-fast-fail-and-stuck-cleanup.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
97 lines
3.0 KiB
YAML
97 lines
3.0 KiB
YAML
name: Run whitelisted SQL on liderra.ru
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
sql:
|
|
description: 'SQL query (SELECT only by default; UPDATE/DELETE need confirm_mutating=true)'
|
|
required: true
|
|
type: string
|
|
confirm_mutating:
|
|
description: 'Подтверждаю UPDATE/DELETE на проде'
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
jobs:
|
|
run:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
env:
|
|
LIDERRA_HOST: 111.88.246.137
|
|
LIDERRA_USER: ubuntu
|
|
SQL: ${{ github.event.inputs.sql }}
|
|
CONFIRM_MUT: ${{ github.event.inputs.confirm_mutating }}
|
|
|
|
steps:
|
|
- name: Whitelist check
|
|
run: |
|
|
set -euo pipefail
|
|
SQL_LOWER=$(echo "$SQL" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
|
|
# Allow: SELECT / WITH (CTE) / \d / EXPLAIN
|
|
READ_RE='^(select |with |explain |\\d|\\df|\\di|\\dt)'
|
|
|
|
# Mutating allowed if confirm=true: targeted UPDATE/DELETE on specific tables
|
|
MUTATING_RE='^(update supplier_leads|update failed_webhook_jobs|update scheduler_heartbeats|delete from failed_webhook_jobs|delete from incidents_log) '
|
|
|
|
if [[ "$SQL_LOWER" =~ $READ_RE ]]; then
|
|
echo "::notice::SELECT/read-only — allowed."
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$SQL_LOWER" =~ $MUTATING_RE ]]; then
|
|
if [[ "$CONFIRM_MUT" != "true" ]]; then
|
|
echo "::error::Mutating SQL requires confirm_mutating=true."
|
|
exit 1
|
|
fi
|
|
echo "::warning::Mutating SQL authorized."
|
|
exit 0
|
|
fi
|
|
|
|
echo "::error::SQL not in whitelist: $SQL_LOWER"
|
|
exit 1
|
|
|
|
- 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: Run on prod
|
|
run: |
|
|
set -o pipefail
|
|
SQL_B64=$(printf '%s' "$SQL" | base64 -w0)
|
|
ssh -i ~/.ssh/liderra_deploy ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }} \
|
|
"SQL_B64='$SQL_B64' bash -s" <<'REMOTE' | tee /tmp/sql.log
|
|
SQL=$(echo "$SQL_B64" | base64 -d)
|
|
echo "=== Running on $(hostname) at $(date -u) ==="
|
|
echo "SQL: $SQL"
|
|
echo
|
|
sudo -u postgres psql -d liderra -c "$SQL"
|
|
RC=$?
|
|
echo
|
|
echo "=== Exit code: $RC ==="
|
|
exit $RC
|
|
REMOTE
|
|
|
|
- name: Summary
|
|
if: always()
|
|
run: |
|
|
{
|
|
echo "## SQL on prod"
|
|
echo
|
|
echo '```sql'
|
|
echo "$SQL"
|
|
echo '```'
|
|
echo
|
|
echo '```'
|
|
cat /tmp/sql.log 2>/dev/null
|
|
echo '```'
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
- name: Cleanup
|
|
if: always()
|
|
run: rm -f ~/.ssh/liderra_deploy
|