Зачіпка
pnpm 11.1.3 змінив не лише момент нового resolution. Тепер pnpm install повторно перевіряє вже готовий pnpm-lock.yaml проти активних policy перед тим, як завантажити будь-який tarball.
Це важливо для команд, які вже поставили minimumReleaseAge або trustPolicy: no-downgrade і вважали, що install-flow захищений. Якщо lockfile приїхав зі старішого середовища, CI cache або чужого branch, pnpm може зупинити pipeline саме тепер.
Проблема / Контекст
До цього зміна policy часто виглядала простіше, ніж була насправді. Команда могла додати в pnpm-workspace.yaml:
minimumReleaseAge: 1440
trustPolicy: no-downgrade
Після цього нові резолви справді ставали обережнішими. Але старий lockfile міг уже містити версію, яку нова policy не пропустила б під час чесного resolution. Або lockfile був створений у середовищі без цих правил, потім потрапив у репозиторій, а CI просто виконав pnpm install —frozen-lockfile.
У pnpm 11.1.3 цей розрив закрили. Перед завантаженням package tarball pnpm перевіряє записи в lockfile проти поточних minimumReleaseAge і trustPolicy: no-downgrade. Якщо запис порушує правила, install падає з одним із ERR-кодів:
ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION;ERR_PNPM_TRUST_DOWNGRADE;ERR_PNPM_LOCKFILE_RESOLUTION_VERIFICATION, якщо одночасно спрацювали обидві перевірки;ERR_PNPM_NO_MATURE_MATCHING_VERSION, коли strict mode не знаходить достатньо старої версії.
Гарна новина тут не в тому, що CI може почати падати. Гарна новина в тому, що падіння показує реальну діру між вашим policy і фактичним lockfile. Це краще, ніж тихо встановити підозріло свіжий або trust-downgraded пакет.
Чому це важливо
Supply-chain захист працює тільки тоді, коли він стоїть на реальному шляху встановлення залежностей. Якщо policy перевіряється лише під час нового resolution, але не перевіряє lockfile перед install, команда має красивий конфіг і неідеальний захист.
Типові місця, де це болить:
- CI відновлює старий lockfile або pnpm store з cache;
- Renovate або Dependabot створює PR з дуже свіжою версією пакета;
- розробник локально має іншу версію pnpm і пушить lockfile;
- монорепо частково оновлює dependencies в одному workspace;
- release pipeline запускає
—frozen-lockfileі не очікує, що policy може перевірити вже зафіксований lockfile; - приватний registry або mirror має неповні metadata.
Для маленького pet project це може бути просто червоний install. Для команди з release window це вже операційний ризик: dependency policy починає працювати в найгірший момент, бо її не перевірили контрольовано.
Як це зробити
1. Зафіксуйте версію pnpm
Спочатку перевірте, що локальна розробка й CI запускають однакову major-версію:
pnpm -v
corepack pnpm -v
Якщо у вас packageManager у package.json, переконайтеся, що Corepack справді бере очікувану версію:
{
"packageManager": "pnpm@11.1.3"
}
Не обов’язково всім миттєво бігти на 11.1.3, але rollout policy треба тестувати на тій версії, яка потім піде в CI. Інакше ви перевіряєте не майбутню поведінку, а приємну ілюзію.
2. Подивіться на поточний policy
Відкрийте pnpm-workspace.yaml:
minimumReleaseAge: 1440
minimumReleaseAgeStrict: true
trustPolicy: no-downgrade
minimumReleaseAge задає паузу після публікації пакета. У pnpm 11 built-in default уже 1440 хвилин, але важлива різниця в strict behavior. Якщо ви явно прописали minimumReleaseAge, minimumReleaseAgeStrict за замовчуванням стає strict. Якщо залишили тільки built-in default, поведінка м’якша для сумісності.
Практична рекомендація проста:
- для release-critical CI краще strict behavior;
- для локального developer bootstrap можна почати з loose behavior, якщо команда ще не готова до жорсткого rollout;
- для монорепо не змішуйте policy без документації: люди мають розуміти, чому CI суворіший за локальну машину.
3. Проганяйте clean frozen install
Мінімальний smoke test:
rm -rf node_modules
pnpm store prune
pnpm install --frozen-lockfile
У CI краще зробити окремий manual job без агресивного cache restore. Якщо він падає, ви хочете бачити справжню причину, а не сперечатися з кешем:
name: pnpm-policy-smoke
on:
workflow_dispatch:
jobs:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- run: corepack enable
- run: pnpm install --frozen-lockfile
Якщо policy справді активна, цей job перевірить не тільки майбутні dependency updates, а й поточний lockfile. Саме це змінилося в pnpm 11.1.3.
4. Розберіть помилки без паніки
ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION означає, що lockfile вказує на пакет, який ще не пройшов вашу age policy. Це не завжди атака. Це може бути дуже свіжий release, який автоматичний бот оновив занадто рано.
ERR_PNPM_TRUST_DOWNGRADE означає, що у пакета знизився trust evidence порівняно з раніше опублікованими версіями. Тут не варто одразу тиснути “ігнорувати”. Спочатку перевірте release, publisher, changelog і чи справді ця версія потрібна зараз.
ERR_PNPM_NO_MATURE_MATCHING_VERSION у strict mode зазвичай означає, що requested range не має версії, яка одночасно підходить за semver і достатньо стара. Тут варіанти такі: почекати, розширити range, тимчасово зафіксувати старішу версію або зробити точковий виняток.
5. Винятки робіть маленькими
pnpm підтримує minimumReleaseAgeExclude і trustPolicyExclude. Це нормальний інструмент, якщо пакет справді треба пропустити:
minimumReleaseAge: 1440
minimumReleaseAgeStrict: true
minimumReleaseAgeExclude:
- "@your-org/*"
- "vite@8.0.1"
trustPolicy: no-downgrade
trustPolicyExclude:
- "internal-tool@2.4.0"
Правило для винятків: пакет, причина, власник, дата перегляду. Якщо ви додаєте цілий scope, напишіть чому. Якщо додаєте точну версію, заплануйте видалення винятку після наступного стабільного release.
Не робіть виняток першим рефлексом. Якщо новий пакет не може пройти age policy, часто найкраще рішення - просто почекати добу. Якщо trustPolicy спрацювала, краще витратити 10 хвилин на перевірку, ніж навчити CI обходити захист.
6. Узгодьте Renovate, Dependabot і кеші
Автоматичні dependency PR тепер мають проходити через той самий policy. Для Renovate або Dependabot це означає:
- не мерджити dependency update одразу після публікації, якщо
minimumReleaseAgeмає чекати; - запускати
pnpm install —frozen-lockfileна PR; - не кешувати так агресивно, щоб policy smoke test нічого не перевіряв;
- у release branches фіксувати pnpm version і Node version.
Окремо перевірте, чи не створює ваш бот lockfile старішою pnpm. Ідеальний варіант - одна версія package manager для локальної розробки, ботів і CI.
Антипатерни
- додати
minimumReleaseAgeу конфіг і не прогнати існуючий lockfile; - вимкнути strict mode тільки тому, що перший CI run став червоним;
- додати
@scope/*у винятки без власника й дедлайну; - вважати
—frozen-lockfileповною гарантією безпеки; - кешувати pnpm store так, що policy smoke test не ловить реальний install-flow;
- ігнорувати
ERR_PNPM_TRUST_DOWNGRADE, бо “це ж популярний пакет”; - оновлювати pnpm у CI без маленького manual rollout.
Висновок / План дій
pnpm 11.1.3 робить dependency policy чеснішою: тепер перевіряється не тільки новий resolution, а й уже готовий pnpm-lock.yaml. Це може зламати CI, але саме так команда дізнається, що старий lockfile не відповідає поточним правилам.
Практичний план на 30 хвилин:
- зафіксуйте pnpm version у
packageManager; - перевірте
minimumReleaseAge,minimumReleaseAgeStrictіtrustPolicy; - проганяйте clean
pnpm install —frozen-lockfile; - розберіть ERR-коди по суті, а не через загальне вимкнення policy;
- додавайте тільки точкові винятки;
- синхронізуйте Renovate, Dependabot, CI cache і release branches.
Якщо у вас уже є minimumReleaseAge або trustPolicy: no-downgrade, не чекайте першого випадкового падіння. Запустіть smoke test самі й перетворіть червоний install на контрольований rollout.
Офіційні джерела:
Короткий чеклист
- Перевірити, яка версія pnpm запускається локально і в CI.
- Відкрити pnpm-workspace.yaml і знайти minimumReleaseAge, minimumReleaseAgeStrict, trustPolicy та винятки.
- Прогнати чистий pnpm install --frozen-lockfile без залежності від старого CI cache.
- Окремо перевірити lockfile, створений старішою версією pnpm або іншим середовищем.
- Додавати винятки тільки точково й з власником.
- Задокументувати rollback для типових ERR-кодів pnpm.
Prompt Pack: rollout pnpm lockfile policy у CI
Допоможи безпечно розгорнути pnpm supply-chain policy у нашому Node.js/TypeScript проєкті. Вхідні дані: - поточна версія pnpm у локальній розробці та CI; - фрагмент pnpm-workspace.yaml; - чи є minimumReleaseAge, minimumReleaseAgeStrict, minimumReleaseAgeExclude, trustPolicy або trustPolicyExclude; - як запускається CI install; - чи використовується --frozen-lockfile; - чи кешуються pnpm-lock.yaml, store або node_modules; - які пакети оновлюються автоматично через Renovate, Dependabot або власні скрипти. Поверни: 1. короткий висновок: policy уже реально захищає install-flow чи лише виглядає налаштованою; 2. список ризиків для поточного pnpm-lock.yaml; 3. рекомендований pnpm-workspace.yaml для strict або loose режиму; 4. які пакети можна додати в minimumReleaseAgeExclude або trustPolicyExclude, а які краще не виключати; 5. один CI smoke test з pnpm install --frozen-lockfile; 6. rollback-план на випадок ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION, ERR_PNPM_TRUST_DOWNGRADE або ERR_PNPM_NO_MATURE_MATCHING_VERSION. Формат відповіді: діагноз, diff конфігу, CI-команда, список винятків із поясненням, план rollout на 30 хвилин.