-
Notifications
You must be signed in to change notification settings - Fork 3
VCST-5054: Node dependencies actualization #241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
AndrewEhlo
wants to merge
20
commits into
master
Choose a base branch
from
VCST-5054
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
5c376b4
VCST-5054: Automate npm dependency updates and verify dist/ on every PR
AndrewEhlo c73acc2
VCST-5054: Automate npm dependency updates and verify dist/ on every PR
AndrewEhlo 173bccb
Add missing package-lock files
AndrewEhlo 53abcd7
Merge remote-tracking branch 'origin/master' into VCST-5054
AndrewEhlo 94926dc
VCST-5054: Make check-dist reproducible and auto-rebuild self-completing
AndrewEhlo 05f5fd1
VCST-5054: rebuild docker-install-modules/dist with clean axios metad…
AndrewEhlo 99ae622
Fix review issues
AndrewEhlo e6498be
Fix gitattributes
AndrewEhlo 108fb83
Test missed rebuild case
AndrewEhlo 71c3210
Test missed rebuild case
AndrewEhlo 75dd99e
Test: rebuild dist
AndrewEhlo 872cfcd
Revert test rebuild
AndrewEhlo 9eb3075
Bump third party workflow versions
AndrewEhlo 97e6ef8
Fix TOCTOU vulnerability: checkout uses mutable branch ref
AndrewEhlo 0132962
Fix spoofable github.actor check
AndrewEhlo 648fffb
Set condition for remove-file workflow
AndrewEhlo 50722df
Add missing build scripts and rebuild
AndrewEhlo d3589cc
Fix publish-nuget package.json; rebuild sonar-scanner-end with @actio…
AndrewEhlo dcb6c21
Precreate folder for vc-build
AndrewEhlo 68535a0
Pre-create directories for vc-build in script
AndrewEhlo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
The diff you're trying to view is too large. We only load the first 3000 changed files.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Bundled action distributions: emitted by ncc as LF on every platform. | ||
| # Forcing LF here prevents Windows checkouts from producing phantom diffs | ||
| # against the committed bundles and keeps the check-dist guard reliable. | ||
| # | ||
| # Scope is intentionally narrow: `*/dist/**` matches only `<action>/dist/**` | ||
| # (single path segment + /dist/), not nested `<action>/node_modules/<pkg>/dist/**`. | ||
| # The wider `**/dist/**` would reach into committed node_modules trees of | ||
| # the 9 legacy unbundled actions, where the explicit `text` attribute | ||
| # would override git's binary auto-detection and risk corrupting any | ||
| # binary content (e.g. .node native modules) shipped in upstream dist dirs. | ||
| */dist/** text eol=lf |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| name: check-dist | ||
|
|
||
| # Verifies that each Node action's committed dist/ matches what ncc would | ||
| # emit from its current src/ + package-lock.json. Fails the PR if the bundle | ||
| # is stale, so contributors cannot ship a src/ change without rebuilding. | ||
|
|
||
| on: | ||
| pull_request: | ||
| paths: | ||
| - "*/src/**" | ||
| - "*/index.js" # actions like changelog-generator that bundle a root index.js | ||
| - "*/package.json" | ||
| - "*/package-lock.json" | ||
| - "*/tsconfig.json" | ||
| - ".github/workflows/check-dist.yml" | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| detect: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| actions: ${{ steps.changed.outputs.actions }} | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - id: changed | ||
| name: List action directories with relevant changes | ||
| # Route GHA-context values through env: so they cannot be expanded | ||
| # into shell as code (defense-in-depth; see GitHub Actions | ||
| # hardening guide on script-injection risks). | ||
| env: | ||
| BASE_REF: ${{ github.base_ref }} | ||
| run: | | ||
| dirs=$(git diff --name-only \ | ||
| "origin/${BASE_REF}...HEAD" \ | ||
| -- '*/src/**' '*/index.js' '*/package.json' '*/package-lock.json' '*/tsconfig.json' \ | ||
| | awk -F/ '$1 != "" && $1 != ".github" {print $1}' \ | ||
| | sort -u \ | ||
| | jq -R . | jq -sc .) | ||
| echo "actions=$dirs" >> "$GITHUB_OUTPUT" | ||
| echo "Detected: $dirs" | ||
|
|
||
| build-and-diff: | ||
| needs: detect | ||
| if: needs.detect.outputs.actions != '[]' | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| action: ${{ fromJson(needs.detect.outputs.actions) }} | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
|
|
||
| # Gate runs before setup-node so legacy / partial actions (no | ||
| # package.json, no lockfile, or no build script) short-circuit | ||
| # cleanly. setup-node with cache-dependency-path pointing at a | ||
| # missing lockfile would fail before the gate could fire. | ||
| - name: Skip actions that aren't bundled with npm | ||
| id: gate | ||
| working-directory: ${{ matrix.action }} | ||
| env: | ||
| ACTION: ${{ matrix.action }} | ||
| run: | | ||
| if [ ! -f package.json ]; then | ||
| echo "::notice::$ACTION has no package.json; skipping." | ||
| echo "skip=true" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
| if [ ! -f package-lock.json ]; then | ||
| echo "::notice::$ACTION has no package-lock.json; skipping." | ||
| echo "skip=true" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
| if ! jq -e '.scripts.build' package.json >/dev/null; then | ||
| echo "::notice::$ACTION has no build script; skipping." | ||
| echo "skip=true" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
|
|
||
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | ||
| if: steps.gate.outputs.skip != 'true' | ||
| with: | ||
| node-version: 24 | ||
| cache: npm | ||
| cache-dependency-path: ${{ matrix.action }}/package-lock.json | ||
|
|
||
| - name: Install dependencies | ||
| if: steps.gate.outputs.skip != 'true' | ||
| working-directory: ${{ matrix.action }} | ||
| run: npm ci --no-audit --no-fund | ||
|
|
||
| - name: Rebuild dist/ | ||
| if: steps.gate.outputs.skip != 'true' | ||
| working-directory: ${{ matrix.action }} | ||
| run: npm run build | ||
|
|
||
| - name: Smoke-load the bundle | ||
| if: steps.gate.outputs.skip != 'true' | ||
| working-directory: ${{ matrix.action }} | ||
| run: | | ||
| # node --check only parses. require() runs module init, so a | ||
| # structurally broken bundle (missing internal require, | ||
| # undefined identifier, malformed export) surfaces here. | ||
| # | ||
| # Discriminate by error class: | ||
| # - SyntaxError / ReferenceError / "Cannot find module" | ||
| # => bundle is broken, exit 2 (step fails). | ||
| # - Anything else (TypeError from missing env, action's own | ||
| # thrown Error on missing GITHUB_TOKEN / event payload, etc.) | ||
| # => bundle loaded fine, the action just can't run without | ||
| # a real GHA runtime. Tolerate. | ||
| # process.exit(0) at the end so process.exitCode set by the | ||
| # bundle's run().catch(core.setFailed) doesn't fail the step. | ||
| node --check dist/index.js | ||
| node -e " | ||
| try { require('./dist/index.js'); } | ||
| catch (e) { | ||
| const broken = | ||
| e instanceof SyntaxError || | ||
| e instanceof ReferenceError || | ||
| (e && e.code === 'MODULE_NOT_FOUND') || | ||
| /Cannot find module/i.test(e && e.message || ''); | ||
| if (broken) { | ||
| console.error('Bundle load failure:', e && e.stack || e); | ||
| process.exit(2); | ||
| } | ||
| // Otherwise: the action threw on a runtime precondition | ||
| // (missing env / token / payload). Bundle is fine. | ||
| } | ||
| process.exit(0); | ||
| " | ||
|
|
||
| - name: Verify committed dist/ matches rebuild | ||
| if: steps.gate.outputs.skip != 'true' | ||
| working-directory: ${{ matrix.action }} | ||
| env: | ||
| ACTION: ${{ matrix.action }} | ||
| run: | | ||
| # Only the runtime bundle (dist/index.js) and the licenses file | ||
| # are gated — those must be reproducible across platforms. The | ||
| # sourcemap (dist/index.js.map) and the sourcemap-register shim | ||
| # are intentionally excluded: ncc inlines upstream source files | ||
| # whose CRLF/LF endings differ between Windows-committed and | ||
| # Linux-CI-rebuilt copies, producing a benign byte diff that | ||
| # doesn't affect runtime behaviour. | ||
| # | ||
| # Stage with `git add` before diffing --cached so a brand-new | ||
| # untracked dist/index.js (e.g. a PR adding an action without | ||
| # committing the bundle) is caught -- plain `git diff` is blind | ||
| # to untracked files. Same pattern as dependabot-rebuild.yml. | ||
| paths=(dist/index.js) | ||
| [ -f dist/licenses.txt ] && paths+=(dist/licenses.txt) | ||
| [ -f dist/LICENSES ] && paths+=(dist/LICENSES) | ||
| git add -- "${paths[@]}" | ||
| if ! git diff --cached --quiet -- "${paths[@]}"; then | ||
| echo "::error::dist/ in $ACTION is missing or stale. Run 'npm ci && npm run build' inside that directory and commit the result." | ||
| git --no-pager diff --cached --stat -- "${paths[@]}" | ||
| exit 1 | ||
| fi | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| name: dependabot-rebuild | ||
|
|
||
| # When Dependabot opens an npm PR, rebuild dist/ for the affected action | ||
| # and push the result back to the PR branch. Without this, every Dependabot | ||
| # npm PR fails check-dist (the bundle is stale by construction), forcing a | ||
| # maintainer to rebuild locally before merge. | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, synchronize] | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: read | ||
|
|
||
| jobs: | ||
| rebuild: | ||
| # Gate on the immutable PR author, not `github.actor` (which reflects | ||
| # the current event triggerer and is spoofable: a `@dependabot | ||
| # recreate` style command on an attacker's PR can cause | ||
| # github.actor to surface as dependabot[bot] on the resulting | ||
| # synchronize event, even though the PR itself was authored by | ||
| # someone else (CWE-290). pull_request.user.login is set when the | ||
| # PR is created and cannot change. | ||
| if: github.event.pull_request.user.login == 'dependabot[bot]' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| with: | ||
| # Pin to the immutable head SHA, not the mutable branch ref, | ||
| # to close the TOCTOU window where someone with push access | ||
| # could race a malicious commit onto the Dependabot branch | ||
| # between event dispatch and checkout. The actor guard above | ||
| # checks the *event*-time actor (dependabot[bot]), but the | ||
| # branch tip could have moved since then. Pinning to head.sha | ||
| # ensures we build the exact commit the event fired for. | ||
| ref: ${{ github.event.pull_request.head.sha }} | ||
| repository: ${{ github.event.pull_request.head.repo.full_name }} | ||
| # REPO_TOKEN (org-level PAT) is required so the dist/ rebuild | ||
| # push re-triggers check-dist on the PR. The default | ||
| # GITHUB_TOKEN is suppressed from triggering workflows to | ||
| # prevent recursion (see GitHub docs on | ||
| # GITHUB_TOKEN-triggered events), which would leave the PR | ||
| # stuck with a stale check-dist failure. | ||
| token: ${{ secrets.REPO_TOKEN }} | ||
| fetch-depth: 0 | ||
|
|
||
| - id: changed | ||
| name: List action directories with package.json/lock changes | ||
| # Route GHA-context values through env: so they cannot be expanded | ||
| # into shell as code (defense-in-depth for pull_request_target | ||
| # workflows; see GitHub Actions hardening guide). | ||
| env: | ||
| BASE_REF: ${{ github.event.pull_request.base.ref }} | ||
| run: | | ||
| dirs=$(git diff --name-only \ | ||
| "origin/${BASE_REF}...HEAD" \ | ||
| -- '*/package.json' '*/package-lock.json' \ | ||
| | awk -F/ '$1 != "" && $1 != ".github" {print $1}' \ | ||
| | sort -u) | ||
| { | ||
| echo "actions<<EOF" | ||
| echo "$dirs" | ||
| echo "EOF" | ||
| } >> "$GITHUB_OUTPUT" | ||
| echo "Detected: $dirs" | ||
|
|
||
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | ||
| if: steps.changed.outputs.actions != '' | ||
| with: | ||
| node-version: 24 | ||
|
|
||
| - name: Rebuild dist/ for each changed action | ||
| if: steps.changed.outputs.actions != '' | ||
| env: | ||
| ACTIONS: ${{ steps.changed.outputs.actions }} | ||
| run: | | ||
| while IFS= read -r action; do | ||
| [ -z "$action" ] && continue | ||
| if [ ! -f "$action/package.json" ]; then | ||
| echo "::notice::Skipping $action (no package.json)" | ||
| continue | ||
| fi | ||
| if [ ! -f "$action/package-lock.json" ]; then | ||
| echo "::notice::Skipping $action (no package-lock.json)" | ||
| continue | ||
| fi | ||
| if ! jq -e '.scripts.build' "$action/package.json" >/dev/null; then | ||
| echo "::notice::Skipping $action (no build script)" | ||
| continue | ||
| fi | ||
| echo "::group::Rebuilding $action" | ||
| (cd "$action" && npm ci --no-audit --no-fund && npm run build) | ||
| git add "$action/dist/" | ||
| echo "::endgroup::" | ||
| done <<< "$ACTIONS" | ||
|
|
||
| - name: Commit rebuilt dist/ if changed | ||
| # head.ref is mutable, but we only consult it AFTER the build | ||
| # has run against the pinned head.sha; using it as the push | ||
| # destination (not as a build input) is safe. Routed via env | ||
| # for the same reason every other dynamic value in this file | ||
| # is: it never reaches the shell as code. | ||
| env: | ||
| BRANCH_NAME: ${{ github.event.pull_request.head.ref }} | ||
| run: | | ||
| if git diff --cached --quiet; then | ||
| echo "No dist/ changes to commit." | ||
| exit 0 | ||
| fi | ||
| git config user.name "dependabot[bot]" | ||
| git config user.email "49699333+dependabot[bot]@users.noreply.github.com" | ||
| git commit -m "chore: rebuild dist/ after dependency update" | ||
| # We checked out a detached HEAD at head.sha. Push the new | ||
| # commit back to the branch by name. If the branch has moved | ||
| # since checkout (concurrent Dependabot rebase, or the TOCTOU | ||
| # attacker scenario the SHA pin guards against), the push is | ||
| # rejected non-fast-forward and the step fails -- correct: we | ||
| # don't want to overwrite work we never validated. | ||
| git push origin "HEAD:$BRANCH_NAME" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.