diff --git a/.github/workflows/artisan-run.yml b/.github/workflows/artisan-run.yml new file mode 100644 index 00000000..4c787c1a --- /dev/null +++ b/.github/workflows/artisan-run.yml @@ -0,0 +1,117 @@ +name: Run artisan command on liderra.ru + +# Universal artisan-runner для прод-команд пока прямой SSH с dev-машины +# заблокирован YC backbone-фильтром. Заказчик пишет команду строкой в +# workflow_dispatch input, workflow проверяет её по whitelist, выполняет на +# проде под sudo -u www-data, выводит результат в job summary. +# +# Whitelist охватывает read-only / dry-run / status команды без подтверждения +# плюс несколько mutating команд с обязательным confirm_apply=true. +# +# Любая команда вне whitelist'а → fail before SSH. +# +# Использует тот же LIDERRA_SSH_KEY что и deploy.yml/ssh-diagnose.yml. + +on: + workflow_dispatch: + inputs: + command: + description: 'artisan-команда (например: supplier:rekey-orphans --dry-run)' + required: true + type: string + confirm_apply: + description: 'Подтверждаю выполнение mutating-команды (обязательно true для команд без --dry-run)' + required: false + default: false + type: boolean + +jobs: + run: + name: ${{ github.event.inputs.command }} + runs-on: ubuntu-latest + timeout-minutes: 15 + + env: + LIDERRA_HOST: 111.88.246.137 + LIDERRA_USER: ubuntu + CMD: ${{ github.event.inputs.command }} + CONFIRM: ${{ github.event.inputs.confirm_apply }} + + steps: + - name: Whitelist check + run: | + set -euo pipefail + CMD_TRIM=$(echo "$CMD" | sed 's/^ *//;s/ *$//') + echo "Requested: '$CMD_TRIM'" + + # Group 1 — read-only / dry-run / inspection: всегда разрешены + READ_ONLY_RE='^(migrate:status|route:list|schedule:list|queue:listen --help|about|env:show|config:show|cache:table|view:cache|optimize:status|snapshot:backfill( --date=20[2-9][0-9]-[0-1][0-9]-[0-3][0-9])?|scheduler:check-heartbeats|incidents:watch-failures( --threshold-spike=[0-9]+)?( --threshold-daily=[0-9]+)?( --persistent-hours=[0-9]+)?|supplier:rekey-orphans --dry-run|audit:verify-chains|partitions:list)( *)$' + + # Group 2 — mutating: требуют confirm_apply=true + MUTATING_RE='^(supplier:rekey-orphans|cache:clear|view:clear|config:clear|route:clear|optimize:clear|optimize|queue:restart|partitions:create-months( --months=[0-9]+)?|partitions:drop-old)( *)$' + + if [[ "$CMD_TRIM" =~ $READ_ONLY_RE ]]; then + echo "::notice::Command in read-only whitelist — proceeding." + exit 0 + fi + + if [[ "$CMD_TRIM" =~ $MUTATING_RE ]]; then + if [[ "$CONFIRM" != "true" ]]; then + echo "::error::Mutating command '$CMD_TRIM' requires confirm_apply=true. Re-run with confirm_apply checked." + exit 1 + fi + echo "::warning::Mutating command authorized via confirm_apply=true." + exit 0 + fi + + echo "::error::Command '$CMD_TRIM' is NOT in whitelist. Allowed read-only patterns: $READ_ONLY_RE. Allowed mutating: $MUTATING_RE. Add to whitelist if needed." + 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 artisan on prod + run: | + set -o pipefail + ssh -i ~/.ssh/liderra_deploy ${{ env.LIDERRA_USER }}@${{ env.LIDERRA_HOST }} \ + "CMD=$(printf '%q' \"$CMD\") bash -s" <<'REMOTE' | tee /tmp/artisan-output.log + set +e + cd /var/www/liderra/app + echo "=== Running: php artisan $CMD on $(hostname) at $(date -u) ===" + sudo -u www-data php artisan $CMD 2>&1 + RC=$? + echo + echo "=== Exit code: $RC ===" + exit $RC + REMOTE + + - name: Print summary + if: always() + run: | + { + echo "## artisan \`$CMD\`" + echo + echo "- Host: $LIDERRA_HOST" + echo "- Confirm: $CONFIRM" + echo "- Triggered by: ${{ github.actor }}" + echo + echo '```' + cat /tmp/artisan-output.log 2>/dev/null || echo "(no output captured)" + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + - name: Upload output as artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: artisan-output + path: /tmp/artisan-output.log + retention-days: 30 + + - name: Cleanup SSH key + if: always() + run: rm -f ~/.ssh/liderra_deploy diff --git a/docs/observer/STATUS.md b/docs/observer/STATUS.md index d58146ae..d58b87e6 100644 --- a/docs/observer/STATUS.md +++ b/docs/observer/STATUS.md @@ -1,6 +1,6 @@ # Brain Status (auto-generated) -Last updated: 2026-05-29T01:47:17.763Z +Last updated: 2026-05-29T02:06:45.148Z | Контролёр | Состояние | Детали | |---|---|---| @@ -8,13 +8,13 @@ Last updated: 2026-05-29T01:47:17.763Z | C2 Cross-ref consistency | ✅ | [cross-ref-checker] OK — 0 drift in 4 files | | C3 Observer-of-observer | ✅ | [observer-of-observer] OK — last read 0 week(s) ago | | C4 Сигнальный статус | ✅ | This file (self-reference) | -| C5 Observer-coverage | ⚠️ | 645 episode(s) this month · Stop-hook + post-commit OK · 20 missed activation(s) — see /brain-retro | +| C5 Observer-coverage | ⚠️ | 652 episode(s) this month · Stop-hook + post-commit OK · 20 missed activation(s) — see /brain-retro | | C6 Chain map sync | ✅ | [chain-map-checker] OK — 16 chains in sync | ## Метрики (информационные, не алерты) -- Observer evidence: 645 episodes this month, 0 observer_error markers, 128 PII matches before filter -- Legacy v1 episodes (not in factor analysis): 506 +- Observer evidence: 652 episodes this month, 0 observer_error markers, 130 PII matches before filter +- Legacy v1 episodes (not in factor analysis): 513 - Last /brain-retro: 2 day(s) ago - Использование узлов: см. `/brain-retro` (раз в спринт). missed_activations: 20. **Неиспользованные узлы — не алерт, если профильной задачи не было** (Pravila §16.4 v1.36; capability-readiness; см. memory `feedback_brain_unused_tools_not_problem` — outside-repo memory store). @@ -24,16 +24,16 @@ Baseline дисциплины роутера (этап 2 router discipline overh | Тип задачи | Эпизодов | % с триггер-матчем | % через скил | |---|---|---|---| -| analysis | 28 | 28.6% | 14.3% | +| analysis | 29 | 27.6% | 13.8% | | bugfix | 18 | 22.2% | 27.8% | | planning | 16 | 18.8% | 18.8% | -| feature | 15 | 13.3% | 0.0% | +| feature | 16 | 12.5% | 0.0% | | cleanup | 6 | 0.0% | 0.0% | | refactor | 1 | 0.0% | 0.0% | -Router step distribution: 1: 284, 2: 231, 3: 61, 5: 60 +Router step distribution: 1: 286, 2: 235, 3: 62, 5: 60 -Boundaries applied (ADR / границы): 73 of 636 эпизодов (11.5%). +Boundaries applied (ADR / границы): 74 of 643 эпизодов (11.5%). ## Активные многоэтапные проекты @@ -51,10 +51,10 @@ Boundaries applied (ADR / границы): 73 of 636 эпизодов (11.5%). | Компонент | Токены (in/out) | USD | |---|---|---| -| Classifier (Sonnet 4.6) | 3077/39149 | $0.60 | +| Classifier (Sonnet 4.6) | 3378/43086 | $0.66 | | Self-assessment (Sonnet 4.6) | 0/0 | $0.00 | | Reviewer (Opus 4.7 + fallback) | 0/0 | $0.00 | -| **Итого** | | **$0.60** | +| **Итого** | | **$0.66** | ## Аномалии классификатора @@ -67,7 +67,7 @@ Episodes since last run: 542 / threshold: 10 ## Reviewer: субагент vs fallback -0 эпизодов проверено из 645. +0 эпизодов проверено из 652. ## Reviewer findings @@ -110,7 +110,7 @@ Episodes since last run: 542 / threshold: 10 | Фраза | За всё время | За сегодня | |---|---|---| | `recovery` | 901 | 4 | -| `ремонт инфраструктуры` | 192 | 7 ⚠️ | +| `ремонт инфраструктуры` | 199 | 14 ⚠️ | | `без скилов` | 185 | 7 ⚠️ | | `срочно` | 93 | 0 | | `memory dump` | 17 | 0 |