SilverElixir commited on
Commit
6d81643
·
1 Parent(s): b33ab22

Pin CI actions by SHA and harden backup and deploy workflows

Browse files
.github/workflows/ci.yml CHANGED
@@ -22,10 +22,13 @@ on:
22
  jobs:
23
  test:
24
  runs-on: ubuntu-latest
 
25
  steps:
26
- - uses: actions/checkout@v7
 
 
27
 
28
- - uses: actions/setup-python@v7
29
  with:
30
  python-version: "3.13"
31
 
@@ -38,7 +41,7 @@ jobs:
38
  - run: pytest -q
39
 
40
  # Deno-тесты прокси (proxy/proxy_test.ts — без внешних импортов, офлайн).
41
- - uses: denoland/setup-deno@v2
42
  with:
43
  deno-version: v2.x
44
 
 
22
  jobs:
23
  test:
24
  runs-on: ubuntu-latest
25
+ timeout-minutes: 30
26
  steps:
27
+ # Пины по SHA (аудит 06.10.2026): теги двигаются, SHA нет. Коммит справа —
28
+ # текущий Snapchat тега на дату пина.
29
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
30
 
31
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
32
  with:
33
  python-version: "3.13"
34
 
 
41
  - run: pytest -q
42
 
43
  # Deno-тесты прокси (proxy/proxy_test.ts — без внешних импортов, офлайн).
44
+ - uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2
45
  with:
46
  deno-version: v2.x
47
 
.github/workflows/deploy-proxy.yml CHANGED
@@ -38,8 +38,9 @@ jobs:
38
  && github.event.workflow_run.event == 'push'
39
  && github.event.workflow_run.head_repository.full_name == github.repository)
40
  runs-on: ubuntu-latest
 
41
  steps:
42
- - uses: actions/checkout@v7
43
  with:
44
  # Тот коммит, что проверялся CI (см. sync-to-hf.yml); при ручном
45
  # запуске — текущий main.
@@ -56,8 +57,14 @@ jobs:
56
  id: proxy_changed_ci
57
  if: github.event_name != 'workflow_dispatch'
58
  run: |
59
- # Мержи в main — merge-коммиты: дифф с первым родителем показывает весь PR.
60
- if git diff --name-only HEAD~1 HEAD | grep -q '^proxy/'; then
 
 
 
 
 
 
61
  echo "changed=true" >> "$GITHUB_OUTPUT"
62
  else
63
  echo "changed=false" >> "$GITHUB_OUTPUT"
@@ -65,14 +72,14 @@ jobs:
65
 
66
  - name: Deploy to primary proxy
67
  if: steps.proxy_changed.outputs.changed == 'true' || steps.proxy_changed_ci.outputs.changed == 'true'
68
- uses: denoland/deployctl@v1
69
  with:
70
  project: ${{ secrets.DENO_PROXY_PROJECT }}
71
  entrypoint: proxy/proxy.ts
72
 
73
  - name: Deploy to fallback proxy
74
  if: steps.proxy_changed.outputs.changed == 'true' || steps.proxy_changed_ci.outputs.changed == 'true'
75
- uses: denoland/deployctl@v1
76
  with:
77
  project: ${{ secrets.DENO_PROXY_PROJECT_FALLBACK }}
78
  entrypoint: proxy/proxy.ts
 
38
  && github.event.workflow_run.event == 'push'
39
  && github.event.workflow_run.head_repository.full_name == github.repository)
40
  runs-on: ubuntu-latest
41
+ timeout-minutes: 10
42
  steps:
43
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
44
  with:
45
  # Тот коммит, что проверялся CI (см. sync-to-hf.yml); при ручном
46
  # запуске — текущий main.
 
57
  id: proxy_changed_ci
58
  if: github.event_name != 'workflow_dispatch'
59
  run: |
60
+ # Мержи — по базе слияния, а не HEAD~1: иначе мультикоммитные пуши
61
+ # в main проверяли бы только последний коммит.
62
+ if git rev-parse --verify HEAD^2 >/dev/null 2>&1; then
63
+ base="$(git merge-base HEAD^1 HEAD^2)"
64
+ else
65
+ base="HEAD~1"
66
+ fi
67
+ if git diff --name-only "$base" HEAD | grep -q '^proxy/'; then
68
  echo "changed=true" >> "$GITHUB_OUTPUT"
69
  else
70
  echo "changed=false" >> "$GITHUB_OUTPUT"
 
72
 
73
  - name: Deploy to primary proxy
74
  if: steps.proxy_changed.outputs.changed == 'true' || steps.proxy_changed_ci.outputs.changed == 'true'
75
+ uses: denoland/deployctl@35381c73621e1731268f80e51b54718d086f1e64 # v1
76
  with:
77
  project: ${{ secrets.DENO_PROXY_PROJECT }}
78
  entrypoint: proxy/proxy.ts
79
 
80
  - name: Deploy to fallback proxy
81
  if: steps.proxy_changed.outputs.changed == 'true' || steps.proxy_changed_ci.outputs.changed == 'true'
82
+ uses: denoland/deployctl@35381c73621e1731268f80e51b54718d086f1e64 # v1
83
  with:
84
  project: ${{ secrets.DENO_PROXY_PROJECT_FALLBACK }}
85
  entrypoint: proxy/proxy.ts
.github/workflows/state-backup.yml CHANGED
@@ -29,6 +29,7 @@ concurrency:
29
  jobs:
30
  backup:
31
  runs-on: ubuntu-latest
 
32
  steps:
33
  - name: Fetch /export_state
34
  run: |
@@ -42,9 +43,18 @@ jobs:
42
  STATE_BACKUP_TOKEN: ${{ secrets.STATE_BACKUP_TOKEN }}
43
  STATE_BACKUP_REPO: ${{ secrets.STATE_BACKUP_REPO }}
44
  run: |
 
 
 
 
 
 
 
45
  git config --global user.name "lumen-backup"
46
  git config --global user.email "lumen-backup@local"
47
- git clone "https://x-access-token:${STATE_BACKUP_TOKEN}@github.com/${STATE_BACKUP_REPO}.git" backup-repo
 
 
48
  cp export_state.json backup-repo/export_state.json
49
  cd backup-repo
50
  git add export_state.json
 
29
  jobs:
30
  backup:
31
  runs-on: ubuntu-latest
32
+ timeout-minutes: 15
33
  steps:
34
  - name: Fetch /export_state
35
  run: |
 
43
  STATE_BACKUP_TOKEN: ${{ secrets.STATE_BACKUP_TOKEN }}
44
  STATE_BACKUP_REPO: ${{ secrets.STATE_BACKUP_REPO }}
45
  run: |
46
+ set -euo pipefail
47
+ # Приватность: бэкап только в приватный репозиторий, иначе стоп.
48
+ visibility="$(GH_TOKEN="${STATE_BACKUP_TOKEN}" gh repo view "${STATE_BACKUP_REPO}" --json visibility -q .visibility)"
49
+ if [ "${visibility}" != "PRIVATE" ]; then
50
+ echo "Refusing backup: ${STATE_BACKUP_REPO} is not PRIVATE (got: ${visibility})" >&2
51
+ exit 1
52
+ fi
53
  git config --global user.name "lumen-backup"
54
  git config --global user.email "lumen-backup@local"
55
+ # PAT не в URL клона, а в extraheader: иначе светится в remote -v и логах.
56
+ git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic $(printf 'x-access-token:%s' "${STATE_BACKUP_TOKEN}" | base64 -w0)" \
57
+ clone "https://github.com/${STATE_BACKUP_REPO}.git" backup-repo
58
  cp export_state.json backup-repo/export_state.json
59
  cd backup-repo
60
  git add export_state.json
.github/workflows/sync-to-hf.yml CHANGED
@@ -30,8 +30,9 @@ jobs:
30
  && github.event.workflow_run.event == 'push'
31
  && github.event.workflow_run.head_repository.full_name == github.repository
32
  runs-on: ubuntu-latest
 
33
  steps:
34
- - uses: actions/checkout@v7
35
  with:
36
  # Явно берём тот коммит, что проверялся CI (workflow_run сам по себе
37
  # не чекаутит его) — иначе можно было бы задеплоить более поздний,
 
30
  && github.event.workflow_run.event == 'push'
31
  && github.event.workflow_run.head_repository.full_name == github.repository
32
  runs-on: ubuntu-latest
33
+ timeout-minutes: 10
34
  steps:
35
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
36
  with:
37
  # Явно берём тот коммит, что проверялся CI (workflow_run сам по себе
38
  # не чекаутит его) — иначе можно было бы задеплоить более поздний,