Skip to content

Commit 0317493

Browse files
committed
Initial version 1.0.0
1 parent a05bdfa commit 0317493

13 files changed

Lines changed: 6938 additions & 1 deletion

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
dist/

README.md

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,153 @@
1-
# npm-no-scripts
1+
# npm-no-scripts GitHub Action
2+
3+
This action checks all installed NPM dependencies for lifecycle scripts (like
4+
`postinstall`) that would be run on installation. If any such script is found,
5+
the action fails with a list of offenders.
6+
7+
## Inputs
8+
9+
| Input Name | Description | Required | Default |
10+
| -------------- | --------------------------------------------------- | -------- | ------- |
11+
| `ignore` | List of packages to ignore (JSON) | No | `""` |
12+
| `ignoreNative` | Whether to ignore the default node-gyp install step | No | `false` |
13+
14+
#### `ignore`
15+
16+
You can specify dependencies you would like to ignore when scanning for
17+
lifecycle scripts (ideally because you manually vetted them and consider them to
18+
be secure). This can be helpful if you have dependencies that need a
19+
`postinstall` script to be run.
20+
21+
This parameter expects a JSON array of package names or an object as string.
22+
23+
```json
24+
"PKGNAME": {
25+
"version": VERSION_LIST,
26+
"script": SCRIPT_LIST,
27+
"native": IGNORE_NATIVE,
28+
}
29+
```
30+
31+
- `PKGNAME`: the name of the package to ignore
32+
- `VERSION_LIST`: a version string or array of version strings (combined via
33+
logical or) in the semver format. Only packages that match this version will
34+
be ignored. NPM rules apply (e.g. `^1.2.3` also matches `1.2.5` and `1.3.0`
35+
but not `1.2.2` or `2.0.0`, use `=1.2.3` for fixed versions).
36+
- `SCRIPT_LIST`: a string or array of strings of specific scripts to ignore.
37+
Possible values are `prepare`, `preinstall`, `install`, and `postinstall`
38+
- `IGNORE_NATIVE`: when `true`, ignore implicit runs of `node-gyp` for packages
39+
that generate native bindings
40+
41+
If `"script"` is present without `"version"`, the specified script(s) will be
42+
ignored in all versions. If only `"version"` is present, everything will be
43+
ignored for the specified version.
44+
45+
_Example: Ignore `esbuild`_
46+
47+
```yaml
48+
- name: Validate step
49+
uses: cryptool-org/npm-no-scripts@v1
50+
with:
51+
ignore: |
52+
["esbuild"]
53+
```
54+
55+
or
56+
57+
```yaml
58+
- name: Validate step
59+
uses: cryptool-org/npm-no-scripts@v1
60+
with:
61+
ignore: |
62+
{"esbuild": true}
63+
```
64+
65+
_Example: Ignore only `postinstall` script for `esbuild`_
66+
67+
```yaml
68+
- name: Validate step
69+
uses: cryptool-org/npm-no-scripts@v1
70+
with:
71+
ignore: |
72+
{
73+
"esbuild": {
74+
"script": "postinstall"
75+
}
76+
}
77+
```
78+
79+
_Example: Ignore all scripts in version '0.22.3' of `esbuild`_
80+
81+
```yaml
82+
- name: Validate step
83+
uses: cryptool-org/npm-no-scripts@v1
84+
with:
85+
ignore: |
86+
{
87+
"esbuild": {
88+
"version": "=0.22.3"
89+
}
90+
}
91+
```
92+
93+
_Example: Ignore `preinstall` script in version '0.22.3' and patch releases of
94+
`esbuild`_
95+
96+
```yaml
97+
- name: Validate step
98+
uses: cryptool-org/npm-no-scripts@v1
99+
with:
100+
ignore: |
101+
{
102+
"esbuild": {
103+
"version": "~0.22.3",
104+
"script": "preinstall"
105+
}
106+
}
107+
```
108+
109+
## Outputs
110+
111+
This action does not produce outputs. It will only succeed if no lifecycle
112+
script is found.
113+
114+
## Usage
115+
116+
1. Install your dependencies _without_ running any potential scripts:
117+
118+
```yaml
119+
- name: Install dependencies
120+
run: npm ci --ignore-scripts
121+
```
122+
123+
2. Run this action to verify no scripts would have been run:
124+
125+
```yaml
126+
- name: Validate step
127+
uses: cryptool-org/npm-no-scripts@v1
128+
```
129+
130+
3. (optional) Run all scripts (in your package and the ignored ones):
131+
132+
```yaml
133+
- name: Configure dependencies
134+
run: npm rebuild
135+
```
136+
137+
## Security Notes
138+
139+
To limit trivial supply-chain attacks, _never_ run untrusted scripts. Use
140+
`npm clean-install --ignore-scripts` when installing the dependencies. This will
141+
use the lockfile with pinned versions and not execute any lifecycle scripts.
142+
143+
If any of your dependencies needs such a script (like `postinstall`) to function
144+
properly, you can explicitly run them using `npm rebuild <PACKAGE>`.
145+
146+
Please note that `--ignore-scripts` wont execute any of your own scripts defined
147+
in `package.json` either. You either have to run them manually with
148+
`npm run <SCRIPTNAME>` or -- only if you are certain no malicious scripts exist
149+
in your dependencies -- with `npm rebuild`.
150+
151+
## License
152+
153+
This GitHub Action is available under the [MIT License](LICENSE)

action.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: "npm-no-scripts"
2+
description: "Verify NPM dependencies don't have lifecycle scripts"
3+
inputs:
4+
ignore:
5+
required: false
6+
default: ""
7+
description: "Packages to ignore, a JSON object or array"
8+
runs:
9+
using: "node24"
10+
main: "dist/index.js"

dist/index.js

Lines changed: 259 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eslint.config.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import eslintConfigPrettier from "eslint-config-prettier/flat"
2+
import { defineConfig } from "eslint/config"
3+
import neostandard from "neostandard"
4+
5+
export default defineConfig([
6+
...neostandard({
7+
ts: true,
8+
files: ["**/*.{js,jsx}", "**/*.mjs"],
9+
filesTs: ["**/*.{ts,tsx}"],
10+
ignores: ["**/node_modules/**", "dist/**"],
11+
}),
12+
eslintConfigPrettier,
13+
{ linterOptions: { reportUnusedDisableDirectives: "warn" } },
14+
])

0 commit comments

Comments
 (0)