Skip to content

sdds-infra: Avoid poison cache from fork#2812

Open
Yakutoc wants to merge 2 commits into
devfrom
ci-handle-cache-poison-issues
Open

sdds-infra: Avoid poison cache from fork#2812
Yakutoc wants to merge 2 commits into
devfrom
ci-handle-cache-poison-issues

Conversation

@Yakutoc
Copy link
Copy Markdown
Collaborator

@Yakutoc Yakutoc commented May 27, 2026

What/why changed

Postmortem: https://tanstack.com/blog/npm-supply-chain-compromise-postmortem.

В мае 2026 в TanStack произошёл supply chain attack: атакующий через fork PR с pull_request_target отравил GitHub Actions cache, который позже подтянул release.yml, выгрузил из памяти OIDC-токен раннера и опубликовал 84 малварных версии 42 пакетов в npm.

А что у нас?

У нас тот же паттерн, на пример в documentation-deploy-pr.yml ходит на pull_request_target и через цепочку change-detection / publish-common использует один и тот же prepare-environment, который писал в общий cache.

Fork PR мог положить туда подменённые tarball'ы под ключом hashFiles(package-lock.json), а следующий доверенный запуск (publish-canary, deploy с dev) подтянул бы их к себе. Этот PR закрывает вектор.

Что меняется?

prepare-environment/action.yml — основной фикс:

  • Trust-detection шаг. Если event_name == pull_request_target и head.repo != base.repo (fork) — контекст помечается untrusted=true.
  • Cache раздвоен по trust-контексту. В trusted — actions/cache (restore + post-save). В untrusted — actions/cache/restore (только чтение, без post-step save). Запись отрублена на уровне типа action'а, а не permissions: cache использует runner-internal token, permissions: его не ограничивает (как раз грабли TanStack).
  • Один namespace ключа для обоих режимов (npm-trusted-…). Fork PR'ы переиспользуют доверенный кэш.
  • Только exact-match ключ, без restore-keys. Partial-match по мутированному lockfile позволил бы подмешать чужие tarball'ы к проверенному кешу.
  • Убран node_modules cache. Это уже распакованные/исполнимые артефакты — отравленный node_modules исполняется на первой же команде. Кэшируем только ~/.npm (tarball'ы, валидируются по integrity из lockfile) и ~/.cache/Cypress (бинарь, дополнительно проверяется cypress verify).
  • Pin третьих action'ов на SHA (actions/setup-node, actions/cache) — рекомендация из postmortem, исключает скрытую подмену тэга.
  • npx cypress verify — доп. интегрити-проверка бинаря против установленного пакета (ловит рассинхрон/повреждение кэша).
📦 Published PR as canary version: Canary Versions

✨ Test out this PR locally via:

npm install @salutejs/plasma-asdk@0.377.1-canary.2812.26529554789.0
npm install @salutejs/plasma-b2c@1.619.1-canary.2812.26529554789.0
npm install @salutejs/plasma-core@1.227.1-canary.2812.26529554789.0
npm install @salutejs/plasma-giga@0.346.1-canary.2812.26529554789.0
npm install @salutejs/plasma-homeds@0.346.1-canary.2812.26529554789.0
npm install @salutejs/plasma-hope@1.373.1-canary.2812.26529554789.0
npm install @salutejs/plasma-icons@1.238.1-canary.2812.26529554789.0
npm install @salutejs/plasma-new-hope@0.363.1-canary.2812.26529554789.0
npm install @salutejs/plasma-tokens-b2b@1.55.1-canary.2812.26529554789.0
npm install @salutejs/plasma-tokens-b2c@0.66.1-canary.2812.26529554789.0
npm install @salutejs/plasma-tokens-web@1.70.1-canary.2812.26529554789.0
npm install @salutejs/plasma-tokens@1.139.1-canary.2812.26529554789.0
npm install @salutejs/plasma-typo@0.43.1-canary.2812.26529554789.0
npm install @salutejs/plasma-ui@1.349.1-canary.2812.26529554789.0
npm install @salutejs/plasma-web@1.621.1-canary.2812.26529554789.0
npm install @salutejs/sdds-bizcom@0.351.1-canary.2812.26529554789.0
npm install @salutejs/sdds-cs@0.355.1-canary.2812.26529554789.0
npm install @salutejs/sdds-dfa@0.349.1-canary.2812.26529554789.0
npm install @salutejs/sdds-finai@0.342.1-canary.2812.26529554789.0
npm install @salutejs/sdds-insol@0.346.1-canary.2812.26529554789.0
npm install @salutejs/sdds-netology@0.350.1-canary.2812.26529554789.0
npm install @salutejs/sdds-os@0.21.1-canary.2812.26529554789.0
npm install @salutejs/sdds-platform-ai@0.350.1-canary.2812.26529554789.0
npm install @salutejs/sdds-sbcom@0.351.1-canary.2812.26529554789.0
npm install @salutejs/sdds-scan@0.349.1-canary.2812.26529554789.0
npm install @salutejs/sdds-serv@0.350.1-canary.2812.26529554789.0
npm install @salutejs/core-themes@0.30.1-canary.2812.26529554789.0
npm install @salutejs/plasma-themes@0.51.1-canary.2812.26529554789.0
npm install @salutejs/sdds-themes@0.66.1-canary.2812.26529554789.0
npm install @salutejs/sdds-api-tests@0.8.1-canary.2812.26529554789.0
npm install @salutejs/plasma-cy-utils@0.157.1-canary.2812.26529554789.0
npm install @salutejs/plasma-sb-utils@0.227.1-canary.2812.26529554789.0
npm install @salutejs/plasma-tokens-utils@0.51.1-canary.2812.26529554789.0
# or 
yarn add @salutejs/plasma-asdk@0.377.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-b2c@1.619.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-core@1.227.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-giga@0.346.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-homeds@0.346.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-hope@1.373.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-icons@1.238.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-new-hope@0.363.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-tokens-b2b@1.55.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-tokens-b2c@0.66.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-tokens-web@1.70.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-tokens@1.139.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-typo@0.43.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-ui@1.349.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-web@1.621.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-bizcom@0.351.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-cs@0.355.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-dfa@0.349.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-finai@0.342.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-insol@0.346.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-netology@0.350.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-os@0.21.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-platform-ai@0.350.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-sbcom@0.351.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-scan@0.349.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-serv@0.350.1-canary.2812.26529554789.0
yarn add @salutejs/core-themes@0.30.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-themes@0.51.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-themes@0.66.1-canary.2812.26529554789.0
yarn add @salutejs/sdds-api-tests@0.8.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-cy-utils@0.157.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-sb-utils@0.227.1-canary.2812.26529554789.0
yarn add @salutejs/plasma-tokens-utils@0.51.1-canary.2812.26529554789.0

Summary by CodeRabbit

  • Chores
    • Enhanced CI/CD security for external pull requests with improved access controls on shared build actions
    • Optimized build caching strategy to improve workflow performance and reduce redundant installations
    • Standardized environment preparation across deployment and build workflows for consistency

Review Change Stack

@Yakutoc Yakutoc self-assigned this May 27, 2026
@Yakutoc Yakutoc added the changelog-skip Exclude pull request changes from changelog label May 27, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

📝 Walkthrough

Walkthrough

The prepare-environment composite action now detects fork trust context and gates npm and Cypress cache writes conditionally: trusted runs cache and restore, untrusted runs restore only. Dependencies install unconditionally, Cypress binaries verify before patching, and four workflows delegate to the remote action. Theme-builder switches from pull_request_target to pull_request triggering.

Changes

Cache Safety and Workflow Security Updates

Layer / File(s) Summary
Trust-context detection and npm cache gating
\.github/actions/prepare-environment/action\.yml
Trust detection for pull_request_target events from external forks gates npm cache to ~/.npm with deterministic lockfile-hash keys, using actions/cache (restore+save) for trusted runs and actions/cache/restore (restore-only) for untrusted runs.
Cypress binary cache safety
\.github/actions/prepare-environment/action\.yml
Cypress binary cache at ~/.cache/Cypress applies the same trusted/untrusted cache-write gating with lockfile-hash-based keys, preventing cache poisoning from external forks.
Install, verification, and patch sequence
\.github/actions/prepare-environment/action\.yml
npm ci --no-progress runs unconditionally without cache-hit conditions, npx cypress verify validates binaries before patching, and node_modules/.bin/patch-package replaces the prior npx patch-package invocation.
Workflow references to remote prepare-environment action
\.github/workflows/change-detection\.yml, \.github/workflows/documentation-deploy-common\.yml, \.github/workflows/documentation-deploy-pr\.yml, \.github/workflows/publish-common\.yml
All workflows switch from local ./.github/actions/prepare-environment to remote salute-developers/plasma/.github/actions/prepare-environment@dev, ensuring action execution uses trusted base branch security logic across pull_request_target chains.
Theme-builder workflow trigger adjustment
\.github/workflows/theme-builder-pr\.yml
Pull request trigger configuration changed to include dev alongside master, removing the prior pull_request_target trigger structure for dev, altering event activation conditions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hops through the forks with caution,
npm caches locked tight for trust,
Cypress verified, patches applied,
Remote actions keep the code just.
Security flows through each workflow strand. 🔒

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main security improvement: preventing cache poisoning attacks from forked pull requests, which is the central objective of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci-handle-cache-poison-issues

Comment @coderabbitai help to get the list of available commands and usage tips.

@Yakutoc Yakutoc changed the title ci(cache): handle poison cache sdds-infra: Handle poison cache from fork May 27, 2026
@Yakutoc Yakutoc changed the title sdds-infra: Handle poison cache from fork sdds-infra: Avoid poison cache from fork May 27, 2026
Comment thread .github/actions/prepare-environment/action.yml Fixed
@github-actions
Copy link
Copy Markdown
Contributor

Theme Builder app deployed!

https://plasma.sberdevices.ru/pr/plasma-theme-builder-pr-2812/

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as outdated.

pull_request:
branches:
- master
pull_request_target:
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[note]: Нет никого смысла запускать сборку builder для pr через fork

@Yakutoc Yakutoc force-pushed the ci-handle-cache-poison-issues branch from 05c5e1c to 1892548 Compare May 27, 2026 18:07
@Yakutoc Yakutoc marked this pull request as ready for review May 28, 2026 05:05
@github-actions github-actions Bot removed the request for review from Yeti-or May 28, 2026 05:06
coderabbitai[bot]

This comment was marked as low quality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog-skip Exclude pull request changes from changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants