Skip to content

ci: monitor npm install scripts#3882

Open
marksvc wants to merge 3 commits into
masterfrom
task/npm-inst
Open

ci: monitor npm install scripts#3882
marksvc wants to merge 3 commits into
masterfrom
task/npm-inst

Conversation

@marksvc
Copy link
Copy Markdown
Collaborator

@marksvc marksvc commented May 14, 2026

This patch adds a workflow which looks to see if a PR changes package-lock.json files such that a dependency newly has an install script that didn't before. Or if there is a new dependency added that has an install script. I read that this can be a suspicious sign of possible trouble to pay attention to.

I apologize that the script is so long.

I suggest that the workflow just comment on our PRs for now without blocking them.

Some example findings can be seen below, as run from repo root.

No finding:

$ FINDINGS_PATH=$(mktemp) && COMMENT_PATH=$(mktemp) && deno run --allow-run=git --allow-write="$FINDINGS_PATH" --allow-write="$COMMENT_PATH" "$SF_REPO"/scripts/monitor-npm-has-install-script.mts --base-sha HEAD --head-sha HEAD --findings-path "$FINDINGS_PATH" --comment-path "$COMMENT_PATH" && wc --lines "$FINDINGS_PATH" && cat "$COMMENT_PATH"
0 /tmp/tmp.SntKHNuqUN
<!-- monitor-npm-hasInstallScript -->
No new npm install scripts detected.

Introduced package with install script:

$ INTRO_SHA=b0021d233a5768c2b2f8b7fc008b15156e2a4232 && BASE_SHA=$(git rev-parse "${INTRO_SHA}^")  && FINDINGS_PATH=$(mktemp) && COMMENT_PATH=$(mktemp) && deno run --allow-run=git --allow-write="$FINDINGS_PATH" --allow-write="$COMMENT_PATH"  "$SF_REPO"/scripts/monitor-npm-has-install-script.mts --base-sha "$BASE_SHA" --head-sha "$INTRO_SHA" --findings-path "$FINDINGS_PATH" --comment-path "$COMMENT_PATH" && wc --lines "$FINDINGS_PATH" &&cat "$FINDINGS_PATH" && cat "$COMMENT_PATH"1 /tmp/tmp.iobKPeNNAo
src/SIL.XForge.Scripture/ClientApp/package-lock.json    introduced      fsevents   1.2.13   node_modules/watchpack-chokidar2/node_modules/fsevents, node_modules/webpack-dev-server/node_modules/fsevents
<!-- monitor-npm-hasInstallScript -->
**Warning:** New npm install script detected.

Detected packages:
- **src/SIL.XForge.Scripture/ClientApp/package-lock.json**
  - Introduced package with install script:
    - fsevents (1.2.13) (node_modules/watchpack-chokidar2/node_modules/fsevents, node_modules/webpack-dev-server/node_modules/fsevents)

Existing package starts to have an install script:

$ BASE_SHA=539d963a5e0cee1362f6a87f493515c28cb910d1 && HEAD_SHA=d09db8e106215e3905fd81c9f893d14dceb61eef && FINDINGS_PATH=$(mktemp) && COMMENT_PATH=$(mktemp) && deno run --allow-run=git --allow-write="$FINDINGS_PATH" --allow-write="$COMMENT_PATH" "$SF_REPO/scripts/monitor-npm-has-install-script.mts" --base-sha "$BASE_SHA" --head-sha "$HEAD_SHA" --findings-path "$FINDINGS_PATH" --comment-path "$COMMENT_PATH" && cat "$FINDINGS_PATH" && cat "$COMMENT_PATH"src/SIL.XForge.Scripture/ClientApp/package-lock.json    existing_new_script     @angular/cli        10.2.3  node_modules/@angular/cli
<!-- monitor-npm-hasInstallScript -->
**Warning:** New npm install script detected.

Detected packages:
- **src/SIL.XForge.Scripture/ClientApp/package-lock.json**
  - Existing package now has install script:
    - @angular/cli (10.2.3) (node_modules/@angular/cli)

Relevant package.json diff snippets:

<details><summary>src/SIL.XForge.Scripture/ClientApp/package.json</summary>

```diff
diff --git a/src/SIL.XForge.Scripture/ClientApp/package.json b/src/SIL.XForge.Scripture/ClientApp/package.json
index dc083037c..3ae756d5e 100644
--- a/src/SIL.XForge.Scripture/ClientApp/package.json
+++ b/src/SIL.XForge.Scripture/ClientApp/package.json
@@ -24,21 +24,21 @@
   "private": true,
   "dependencies": {
     "@angular-mdc/web": "^5.1.1",
-    "@angular/animations": "^10.2.4",
+    "@angular/animations": "^10.2.5",
     "@angular/cdk": "^10.2.7",
-    "@angular/common": "^10.2.4",
-    "@angular/core": "^10.2.4",
+    "@angular/common": "^10.2.5",
+    "@angular/core": "^10.2.5",
     "@angular/flex-layout": "^10.0.0-beta.32",
-    "@angular/forms": "^10.2.4",
+    "@angular/forms": "^10.2.5",
     "@angular/material": "^10.2.7",
-    "@angular/platform-browser": "^10.2.4",
-    "@angular/platform-browser-dynamic": "^10.2.4",
-    "@angular/pwa": "^0.1002.2",
-    "@angular/router": "^10.2.4",
-    "@angular/service-worker": "^10.2.4",
+    "@angular/platform-browser": "^10.2.5",
+    "@angular/platform-browser-dynamic": "^10.2.5",
+    "@angular/pwa": "^0.1002.3",
+    "@angular/router": "^10.2.5",
+    "@angular/service-worker": "^10.2.5",
     "@bugsnag/js": "^7.8.0",
... (truncated)
```

</details>

A finding where there are RTS existing dependencies that now have an install script, and ClientApp existing packages that now have an insall script, and ClientApp has new dependencies that have install scripts. This example was made by using a large range of commits, which would presumably not be the normal situation.

$ BASE_SHA=d09db8e106215e3905fd81c9f893d14dceb61eef~1 && HEAD_SHA=0b0bae61df40d1fe68bb820d892da7ddd1bf0581 && FINDINGS_PATH=$(mktemp) && COMMENT_PATH=$(mktemp) && deno run --allow-run=git --allow-write="$FINDINGS_PATH" --allow-write="$COMMENT_PATH" "$SF_REPO/scripts/monitor-npm-has-install-script.mts" --base-sha "$BASE_SHA" --head-sha "$HEAD_SHA" --findings-path "$FINDINGS_PATH" --comment-path "$COMMENT_PATH" && cat "$FINDINGS_PATH" && cat "$COMMENT_PATH"                            src/RealtimeServer/package-lock.json    existing_new_script     fsevents        2.3.3       node_modules/fsevents
src/SIL.XForge.Scripture/ClientApp/package-lock.json    introduced      @compodoc/compodoc  1.1.25  node_modules/@compodoc/compodoc
src/SIL.XForge.Scripture/ClientApp/package-lock.json    introduced      @parcel/watcher     2.5.1   node_modules/@parcel/watcher
src/SIL.XForge.Scripture/ClientApp/package-lock.json    introduced      @swc/core  1.7.35   node_modules/@swc/core
src/SIL.XForge.Scripture/ClientApp/package-lock.json    introduced      esbuild 0.25.4      node_modules/esbuild
src/SIL.XForge.Scripture/ClientApp/package-lock.json    introduced      lmdb    3.2.6       node_modules/lmdb
src/SIL.XForge.Scripture/ClientApp/package-lock.json    introduced      msgpackr-extract    3.0.3   node_modules/msgpackr-extract
src/SIL.XForge.Scripture/ClientApp/package-lock.json    existing_new_script     sil.xforge.scripture        4.7.1
<!-- monitor-npm-hasInstallScript -->
**Warning:** New npm install script detected.

Detected packages:
- **src/RealtimeServer/package-lock.json**
  - Existing package now has install script:
    - fsevents (2.3.3) (node_modules/fsevents)

- **src/SIL.XForge.Scripture/ClientApp/package-lock.json**
  - Introduced package with install script:
    - @compodoc/compodoc (1.1.25) (node_modules/@compodoc/compodoc)
    - @parcel/watcher (2.5.1) (node_modules/@parcel/watcher)
    - @swc/core (1.7.35) (node_modules/@swc/core)
    - esbuild (0.25.4) (node_modules/esbuild)
    - lmdb (3.2.6) (node_modules/lmdb)
    - msgpackr-extract (3.0.3) (node_modules/msgpackr-extract)
  - Existing package now has install script:
    - sil.xforge.scripture (4.7.1) ()

Relevant package.json diff snippets:

<details><summary>src/RealtimeServer/package.json</summary>

```diff
diff --git a/src/RealtimeServer/package.json b/src/RealtimeServer/package.json
index 55b14fa39..5b5696c56 100644
--- a/src/RealtimeServer/package.json
+++ b/src/RealtimeServer/package.json
@@ -1,47 +1,71 @@
 {
   "name": "realtime-server",
-  "version": "2.0.0",
+  "version": "2.1.0",
   "description": "Real-time Server",
   "license": "MIT",
   "scripts": {
     "test": "jest",
-    "build": "tsc -b tsconfig.build.json",
-    "clean": "tsc -b tsconfig.build.json --clean",
-    "prepare": "npm run build"
+    "test:tc": "npm run test:ci",
+    "test:ci": "jest --ci --coverage --reporters=jest-junit",
+    "build": "tsc -b tsconfig.build.json && tsc -b tsconfig.build-esm.json",
+    "clean": "tsc -b tsconfig.build.json --clean && tsc -b tsconfig.build-esm.json --clean",
+    "lint": "eslint .",
+    "prepare": "npm run build",
+    "prettier": "prettier --write \"**/*.{ts,js,json,css,scss,less,html,md,yml}\"",
+    "prettier:tc": "npm run prettier:ci",
+    "prettier:ci": "prettier --list-different \"**/*.{ts,js,json,css,scss,less,html,md,yml}\""
   },
   "author": "SIL",
   "repository": "github:sillsdev/web-xforge",
-  "main": "lib/common/index.js",
-  "types": "lib/common/index.d.ts",
... (truncated)
```

</details>

<details><summary>src/SIL.XForge.Scripture/ClientApp/package.json</summary>

```diff
diff --git a/src/SIL.XForge.Scripture/ClientApp/package.json b/src/SIL.XForge.Scripture/ClientApp/package.json
index dc083037c..e31f91ed2 100644
--- a/src/SIL.XForge.Scripture/ClientApp/package.json
+++ b/src/SIL.XForge.Scripture/ClientApp/package.json
@@ -1,122 +1,167 @@
 {
   "name": "sil.xforge.scripture",
-  "version": "2.0.0",
+  "version": "4.7.1",
   "description": "SIL.XForge.Scripture - Scripture Forge",
   "license": "MIT",
   "scripts": {
     "ng": "ng",
-    "start": "ng serve",
-    "startBeta": "ng serve --configuration=developmentBeta",
-    "start:no-progress": "ng serve --progress=false",
+    "start": "echo \"open your browser on http://localhost:4200/ \" && ng serve",
     "start:no-reload": "ng serve --liveReload=false",
     "build": "ng build",
-    "test": "ng test --sourceMap=true",
-    "test:tc": "ng test --browsers xForgeChromiumHeadless --watch false --code-coverage",
+    "test": "ng test --source-map",
+    "test:firefox": "mkdir tmp & ng test --browsers xForgeFirefox --source-map",
+    "test:firefox-headless": "mkdir tmp & echo;export KARMA_REPORTERS=mocha && set KARMA_REPORTERS=mocha&& ng test --browsers xForgeFirefoxHeadless --source-map",
+    "test:safari": "ng test --browsers Safari --source-map",
+    "test:parallel": "echo;export KARMA_PARALLEL=true && set KARMA_PARALLEL=true&& npm test ",
+    "test:tc": "ng test --browsers xForgeChromiumHeadless --watch false --code-coverage --source-map",
+    "test:gha": "KARMA_REPORTERS=mocha,coverage-istanbul,junit ng test --browsers xForgeChromiumHeadless --watch false --code-coverage --source-map",
+    "//": "The environment variable is set in a way compatible with both sh and cmd. There is no space before '&& ng'.",
+    "test:headless": "echo;export KARMA_REPORTERS=mocha && set KARMA_REPORTERS=mocha&& ng test --browsers xForgeChromiumHeadless --source-map",
... (truncated)
```

</details>

This change is Reviewable

@marksvc marksvc requested a review from Copilot May 14, 2026 20:59
@marksvc marksvc added the e2e Run e2e tests for this pull request label May 14, 2026
@marksvc marksvc marked this pull request as draft May 14, 2026 21:00
@github-actions
Copy link
Copy Markdown
Contributor

No new npm install scripts detected.

Comment thread .github/workflows/monitor-npm-hasInstallScript.yml Fixed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a CI workflow and Deno script that detect when a PR introduces npm dependencies with hasInstallScript: true (or causes existing dependencies to start declaring install scripts), and posts a summary comment on the PR.

Changes:

  • New Deno/TypeScript script scripts/monitor-npm-has-install-script.mts that diffs package-lock.json snapshots between the merge-base and PR head, classifying findings as introduced or existing_new_script, and emits a TSV findings file plus a Markdown comment.
  • New workflow .github/workflows/monitor-npm-hasInstallScript.yml that runs on pull_request, executes the script with restricted Deno permissions, appends the result to the workflow summary, and creates/updates a marker-tagged PR comment via actions/github-script.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
scripts/monitor-npm-has-install-script.mts Core detection logic: parses lockfiles at base/head SHAs, identifies new install-script usage, and renders findings + package.json diff snippets.
.github/workflows/monitor-npm-hasInstallScript.yml CI wiring: checks out repo, sets up Deno, runs the detection script, and posts/updates a PR comment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- name: Add result to workflow summary
run: cat "${{ steps.detect.outputs.comment_path }}" >> "${GITHUB_STEP_SUMMARY}"

- name: Create or update PR comment
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.

I want it to add a "No problems found" comment so I know it's working :). Maybe it could be quieted later if desired.

Comment on lines +4 to +6
on:
pull_request:
types: [opened, synchronize, reopened]
Comment on lines +71 to +74
const value: string | undefined = args[i + 1];
if (value == null || value.startsWith('--')) {
fail(`Missing value for --${key}`);
}
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.

If the input is in this format, fail will exit the program. I don't think it's important right now to account for paths beginning with --.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.03%. Comparing base (34fab18) to head (6d605d6).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #3882   +/-   ##
=======================================
  Coverage   81.03%   81.03%           
=======================================
  Files         630      630           
  Lines       40684    40684           
  Branches     6602     6597    -5     
=======================================
  Hits        32967    32967           
  Misses       6681     6681           
  Partials     1036     1036           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@marksvc marksvc marked this pull request as ready for review May 14, 2026 21:42
@marksvc marksvc temporarily deployed to screenshot_diff May 14, 2026 21:48 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e2e Run e2e tests for this pull request testing not required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants