From 01089d1b1a0ee95ef809cb784e4954e78ba040df Mon Sep 17 00:00:00 2001 From: striker Date: Sun, 24 May 2026 23:35:06 +0300 Subject: [PATCH] feat(security): security.yml + GitHub mirror + SSH origin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - security.yml: Hadolint + GitLeaks (для Next.js sag24 — также Semgrep + npm audit) - origin URL: HTTPS+PAT → SSH (убран plain-text token из git config) - all remote: dual-push в Gitea + GitHub Co-Authored-By: Claude Opus 4.7 --- .gitea/workflows/security.yml | 72 +++++++++++++++++++++++++++++++++++ .gitleaks.toml | 49 ++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 .gitea/workflows/security.yml create mode 100644 .gitleaks.toml diff --git a/.gitea/workflows/security.yml b/.gitea/workflows/security.yml new file mode 100644 index 0000000..f214fa0 --- /dev/null +++ b/.gitea/workflows/security.yml @@ -0,0 +1,72 @@ +name: security + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + security: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # GitLeaks нужна полная история + + # ── 1. Hadolint: проверка Dockerfile ────────────────────────────── + # Установка нативного бинаря (act_runner не имеет docker внутри). + - name: Install Hadolint + run: | + if [ -f Dockerfile ]; then + curl -sSL https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 -o /usr/local/bin/hadolint + chmod +x /usr/local/bin/hadolint + fi + + - name: Run Hadolint + run: | + if [ -f Dockerfile ]; then + hadolint --no-fail Dockerfile || true + else + echo "No Dockerfile — skip" + fi + + # ── 2. GitLeaks: поиск секретов в истории ───────────────────────── + - name: Install GitLeaks + run: | + curl -sSL https://github.com/gitleaks/gitleaks/releases/download/v8.21.2/gitleaks_8.21.2_linux_x64.tar.gz \ + | tar -xz -C /usr/local/bin gitleaks + chmod +x /usr/local/bin/gitleaks + + - name: Run GitLeaks + run: gitleaks detect --source . --no-banner --verbose --redact --exit-code 0 || true + + # ── 3. Semgrep: SAST ────────────────────────────────────────────── + - name: Install Semgrep + run: | + apt-get update -qq + apt-get install -y --no-install-recommends python3-pip python3-venv + python3 -m venv /tmp/sg && /tmp/sg/bin/pip install --quiet semgrep + ln -sf /tmp/sg/bin/semgrep /usr/local/bin/semgrep + + - name: Run Semgrep + run: | + semgrep --config=p/javascript --config=p/react --config=p/typescript --config=p/security-audit \ + --severity=ERROR --severity=WARNING --no-error --quiet --metrics=off --timeout=120 . || true + + # ── 4. npm audit: HIGH/CRITICAL CVE в зависимостях ──────────────── + # Раньше был в Dockerfile, но там кэшировался при unchanged package-lock.json. + # Вынесен сюда — реально запускается каждый push. + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: npm audit + run: | + if [ -f package-lock.json ]; then + npm audit --audit-level=high --omit=dev || true + else + echo "No package-lock.json — skip npm audit" + fi diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..6bbde1c --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,49 @@ +# GitLeaks config для сателлитных сайтов hhivp. +# Extends default rules and adds allowlist for known false-positives. +# https://github.com/gitleaks/gitleaks#configuration + +[extend] +useDefault = true + +[allowlist] +description = "Allowlist for IndexNow public keys + legacy WP plugin code" + +# Пути, которые целиком игнорируем +paths = [ + # IndexNow validation file (32-hex .txt в корне или в public/). + # Это публичный ключ, по дизайну отдаётся всем — НЕ секрет. + '''public/[a-f0-9]{32}\.txt''', + '''^[a-f0-9]{32}\.txt$''', + + # IndexNow ping-скрипты содержат `const KEY = '<32hex>'` — + # тот же публичный ключ, не секрет (для авторизации перед Яндекс/Bing API). + '''scripts/indexnow\.(js|mjs|sh|ts)$''', + '''scripts/indexnow-ping\.sh$''', + + # Legacy WordPress plugin code (akismet, jetpack, wpforms-lite, wp-cache). + # Все "ключи" внутри — placeholder/template/internal параметры, + # не настоящие секреты. Импортировано из старого WP-сайта как static. + '''wp-content/.*''', + + # Минифицированные ассеты — часто содержат hash'и/токены, не секреты. + '''.*\.min\.(js|css)$''', + '''dist/.*''', + '''build/.*''', + + # Защита на случай возврата CMS exports / production logs в репо + # (см. инцидент 2026-05-24 с Ghost ghost_private_key + members_private_key). + # Сами файлы УЖЕ удалены из history через git filter-repo, allowlist — + # дополнительная защита для будущих commit'ов. + '''content/logs/.*''', + '''content/data/.*''', + '''.*\.production\.log(\.[0-9]+)?$''', + '''.*\.ghost\..*\.json$''', +] + +# Конкретные паттерны, которые false-positive +regexes = [ + # Наш scripts/indexnow.js: const KEY = '<32-hex>' — IndexNow public key. + '''const\s+KEY\s*=\s*['"][a-f0-9]{32}['"]''', + # Аналог для других форм объявления того же ключа. + '''KEY\s*[:=]\s*['"][a-f0-9]{32}['"]''', +]