Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions .github/actions/use-npmrc/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: 'Use .npmrc'
description: 'Writes the given .npmrc content to ~/.npmrc'
description: 'Writes the given .npmrc content to ~/.npmrc and warns about lockfile entries outside the cplace npm proxy'
inputs:
dot-npmrc:
description: 'Content of the .npmrc file'
Expand All @@ -11,4 +11,37 @@ runs:
shell: bash
env:
DOT_NPMRC: ${{ inputs.dot-npmrc }}
run: echo "$DOT_NPMRC" > ~/.npmrc
run: |
echo "$DOT_NPMRC" > ~/.npmrc
# PFM-ISSUE-34453 mitigation. npm's default `replace-registry-host=npmjs`
# rewrites a lockfile's registry.npmjs.org URLs onto the configured
# registry. npm 10.2.4 does that correctly and the entry resolves through
# the proxy; npm 11.3.0 DROPS that registry's path prefix, producing an
# E404 masked as *** because the prefix is the JFROG_URL secret. Measured
# 2026-08-14 on a runner and locally with the same one-package fixture.
#
# `never` makes npm fetch each `resolved` URL verbatim, which survives
# both versions - at a cost: an entry still on npmjs is then fetched FROM
# npmjs, outside the proxy. This line buys npm-11 compatibility and
# spends proxy routing; normalizing the lockfile buys both.
#
# This is a no-op on a lockfile that already resolves entirely through
# the proxy, so it is safe to leave in place, and it is removable once
# the warning below stops firing anywhere.
echo 'replace-registry-host=never' >> ~/.npmrc

- name: Warn on lockfile entries outside the cplace npm proxy
shell: bash
# Advisory only - never fails the build. The warnings are the inventory of
# lockfiles that still need normalizing; when none report, the mitigation
# above can be dropped.
#
# Invoked as `bash "<path>" || true`, not as a bare path. The script's own
# "every precondition is a silent success" contract cannot cover NOT BEING
# REACHABLE - a missing exec bit after checkout, a path containing spaces,
# or a runner where action_path is a backslashed Windows path. That is an
# exit 127 from the shell rather than from the script, and it would fail
# the consumer's job before `npm ci` in all seven workflows using this
# action. `continue-on-error:` is not honoured on composite steps, so
# `|| true` is the mechanism that actually works here.
run: bash "$GITHUB_ACTION_PATH/../../../tools/scripts/lockfile/warn-foreign-registry.sh" || true
61 changes: 61 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: PR Checks

# This repository's first `on: pull_request` workflow. Everything under
# .github/workflows/ is otherwise `workflow_call`-only, and the `pull_request`
# trigger lives in .github/workflow-templates/fe/fe-pr.yml, which GitHub never
# executes.
#
# No `paths:` filter on purpose: a path-filtered workflow reports as pending
# rather than success, and would permanently block merges once it becomes a
# required check.
on:
pull_request:
branches:
- '**'

permissions:
contents: read

jobs:
lockfile:
name: Lockfile registry invariant
runs-on: ${{ vars.SMALL_RUNNER || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

# --prefix-only, NOT a baseline comparison. The ongoing guard must answer
# only "does every entry resolve via the proxy?" - a pull request has to
# stay free to add, remove or update dependencies.
#
# Comparing against the base branch would fail every legitimate dependency
# change, and would then advise running the normalizer, which cannot fix a
# graph difference. Graph invariance belongs to verifying a normalization
# commit (`--baseline HEAD~1`), not to everyday pull requests.
#
# With no baseline there is nothing to fetch, so the default shallow
# checkout is enough. jq is pre-installed on GitHub-hosted ubuntu runners,
# and this job runs no node and no `npm ci` - the guard has to be
# trustworthy precisely when the lockfile is broken.
- name: Check package-lock.json resolved URLs
run: ./tools/scripts/lockfile/check-lockfile.sh --prefix-only

scripts:
name: Shell scripts
runs-on: ${{ vars.SMALL_RUNNER || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

# Never npm devDependencies: adding them would mutate package-lock.json on
# all seven branches and break the invariant this workflow exists to guard.
# shellcheck ships in the ubuntu image, but is installed here anyway so the
# job does not silently depend on image contents.
- name: Install bats and shellcheck
run: |
sudo apt-get update
sudo apt-get install -y bats shellcheck

- name: shellcheck
run: shellcheck tools/scripts/lockfile/*.sh tools/scripts/lockfile/test-helper.bash

- name: bats
run: bats tools/scripts/lockfile/
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
.idea
package-lock.json
Loading