Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

no-scripts

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

no-scripts - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

18

lib/cli.js

@@ -11,3 +11,4 @@ import yargs from "yargs";

.scriptName("no-scripts")
.command("$0 [projectDir]", "Checks all npm dependencies and fail if any of them define automatically executed npm lifecycle scripts", (yargs) => {
.command("$0 [projectDir]", "Check all installed npm dependencies of the current project and fail if any of them " +
"define automatically executed npm lifecycle scripts", (yargs) => {
yargs

@@ -19,5 +20,9 @@ .positional("projectDir", {

}, async (argv) => {
if (argv.includeLocal && !argv.online) {
console.log(`Parameter '--include-local' must only be used with '--online'`);
process.exit(1);
}
const cwd = argv.projectDir ? path.resolve(argv.projectDir) : process.cwd();
let lockfileResults;
if (!argv.offline) {
if (argv.online) {
lockfileResults = await analyzeLockfile({ cwd, ignorePackages: argv.ignore || [] });

@@ -28,3 +33,3 @@ writeResultsToConsole(lockfileResults);

let packageJsonResult;
if (argv.includeLocal || argv.offline) {
if (!argv.online || argv.includeLocal) {
packageJsonResult = await analyzePackageJson({ cwd, ignorePackages: argv.ignore || [] });

@@ -90,7 +95,8 @@ writeResultsToConsole(packageJsonResult);

.option("include-local", {
describe: "Extend check to include local dependencies",
describe: "Only relevant when using `--online`. Extend check to include local dependencies",
boolean: true,
})
.option("offline", {
describe: "Only scan local dependencies. Implies '--include-local'",
.option("online", {
describe: "Instead of analyzing local dependencies, " +
"fetch all dependencies independently from the registry as an extra level of safety",
boolean: true,

@@ -97,0 +103,0 @@ })

@@ -5,2 +5,3 @@ import path from "node:path";

import { getPackagesFromInstalledDependencies } from "./installedDepsHandler.js";
import mapWorkspaces from "@npmcli/map-workspaces";
import { getPackagesFromLockfile } from "./lockfileHandler.js";

@@ -25,3 +26,4 @@ import { analyzePackages } from "./analyzer.js";

}
console.log(`Analyzing using ${packageLock ? "package-lock.json" : "npm-shrinkwrap.json"} and registry`);
console.log(`Analyzing ${packageLock ? "package-lock.json" : "npm-shrinkwrap.json"} ` +
`of package "${rootPackageInfo.packageJson.name}" and fetching packages from the registry...`);
const packages = await getPackagesFromLockfile(rootPackageInfo, lockfile);

@@ -32,5 +34,26 @@ removeIgnoredPackages(packages, ignorePackages);

export async function analyzePackageJson({ cwd, ignorePackages }) {
console.log(`Analyzing using package.json and locally installed dependencies`);
const rootPackageInfo = await getRootPackage(cwd);
console.log(`Analyzing package.json of package "${rootPackageInfo.packageJson.name}" ` +
`and locally installed dependencies...`);
const packages = await getPackagesFromInstalledDependencies(rootPackageInfo);
// Check for workspace config
if (rootPackageInfo.packageJson.workspaces) {
const workspacePaths = await mapWorkspaces({
cwd,
pkg: rootPackageInfo.packageJson
});
if (workspacePaths.size) {
// Read packages in workspaces concurrently
const paths = Array.from(workspacePaths.values());
await Promise.all(paths.map(async (workspacePath) => {
const workspacePackageInfo = await getRootPackage(workspacePath);
const workspacePackages = await getPackagesFromInstalledDependencies(workspacePackageInfo);
workspacePackages.forEach((pkgInfo, modulePath) => {
if (!packages.has(modulePath)) {
packages.set(modulePath, pkgInfo);
}
});
}));
}
}
removeIgnoredPackages(packages, ignorePackages);

@@ -37,0 +60,0 @@ return await analyzePackages(packages);

@@ -6,2 +6,3 @@ import path from "node:path";

import { rimraf } from "rimraf";
import pThrottle from "p-throttle";
import { readPackageJson } from "./util.js";

@@ -37,3 +38,3 @@ async function retrieveTarball(url, targetPath, cacheDir, expectedIntegrity) {

if (![2, 3].includes(lockfile.lockfileVersion)) {
throw new Error(`This tool requires lockfile version '2' or '3'. ` +
throw new Error(`no-scripts requires lockfile version '2' or '3'. ` +
`For details, see https://docs.npmjs.com/cli/configuring-npm/package-lock-json#lockfileversion`);

@@ -76,4 +77,10 @@ }

console.log(`Fetching ${requests.size} tarballs...`);
// Slightly throttle the number of concurrent requests to 100 requests per 100 ms to hopefully prevent errors like:
// "Client network socket disconnected before secure TLS connection was established"
const throttle = pThrottle({
limit: 100,
interval: 100
});
await Promise.all(Array.from(requests.entries())
.map(async ([url, { integrity, packageLocation }]) => {
.map(throttle(async ([url, { integrity, packageLocation }]) => {
const targetRelPath = packageLocation.replace("node_modules/", "");

@@ -88,3 +95,3 @@ const targetPath = path.join(packagesDir, targetRelPath);

});
}));
})));
await rimraf(workDir);

@@ -91,0 +98,0 @@ return packages;

{
"name": "no-scripts",
"version": "0.1.0",
"version": "0.2.0",
"description": "",

@@ -29,3 +29,5 @@ "type": "module",

"dependencies": {
"@npmcli/map-workspaces": "^3.0.4",
"@npmcli/package-json": "^5.0.0",
"p-throttle": "^6.1.0",
"pacote": "^17.0.4",

@@ -39,2 +41,3 @@ "read-package-up": "^11.0.0",

"@types/node": "^20.8.10",
"@types/npmcli__map-workspaces": "^3.0.4",
"@types/pacote": "^11.1.8",

@@ -41,0 +44,0 @@ "@types/resolve": "^1.20.5",

@@ -11,7 +11,7 @@ # no-scripts

Also make sure to update your CI jobs to run `npm ci --ignore-scripts` and `npm publish --ignore-scripts` (as also suggested by [snyk](https://snyk.io/blog/github-actions-to-securely-publish-npm-packages/) for example)
Also make sure to update your CI jobs to run `npm ci --ignore-scripts` and `npm publish --ignore-scripts` (as also suggested [here](https://snyk.io/blog/github-actions-to-securely-publish-npm-packages/))
Note however that this disables **any** [pre- and post-scripts](https://docs.npmjs.com/cli/v10/using-npm/scripts#pre--post-scripts), such as for example the commonly used `pretest` script.
Also, in case one of your dependencies does need an install script to run, you will have to manually execute [`npm rebuild <package name>`](https://docs.npmjs.com/cli/v10/commands/npm-rebuild) to run those after install.
Also, in case one of your dependencies does need an install script to run, you will have to manually execute [`npm rebuild <package name>`](https://docs.npmjs.com/cli/v10/commands/npm-rebuild) to run those after install or manually reset the configuration option mentioned before.

@@ -21,3 +21,3 @@ ## Install

```sh
npm install --global no-scripts
npm i -g no-scripts
```

@@ -31,8 +31,8 @@

By default, no-scripts will start by fetching the tarballs of all dependencies listed in the project's [lockfile](https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json) from the corresponding npm registry. It then evaluates the `package.json` files of every package, applying normalization using [`@npmcli/package-json`](https://www.npmjs.com/package/@npmcli/package-json) in order to detect implicit install-scripts such as `node-gyp rebuild` which would be executed if a package contains `*.gyp` files.
By default, no-scripts will analyze all **locally installed dependencies** of the project in the current working directory. For this, it evaluates the `package.json` file of every package, applying normalization using [`@npmcli/package-json`](https://www.npmjs.com/package/@npmcli/package-json) in order to also detect _implicit_ install-scripts such as `node-gyp rebuild` which would be executed if a [package contains `*.gyp` files](https://docs.npmjs.com/cli/v9/using-npm/scripts#npm-install).
If any install-scripts have been found, the tools exit code will be set to `1`.
**If any install-scripts have been found, the tool's exit code will be set to `1` and a list of the affected packages is shown.**
**Note:** Local dependencies which are referenced via links or workspaces are not analyzed. You can use the [`--include-local`](#include-local-dependencies) option to additionally check those.
### Ignore Dependencies

@@ -46,15 +46,12 @@

### Include Local Dependencies
### Online Mode
```sh
no-scripts --include-local
no-scripts --online
```
This mode operates fully offline and is therefore rather fast. However, since a malicious package that has already been installed *could* have altered it's own package.json during the `postinstall` phase, this mode might be fooled into thinking that a package has no scripts even though they were already executed. I have not yet evaluated the feasability of such an attack though.
This mode operates fully online and is therefore a little slower. Instead of analyzing already installed dependencies, it starts by independently fetching the tarballs of all dependencies listed in the project's [lockfile](https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json) from the corresponding npm registry.
### Offline
```sh
no-scripts --offline
```
Since a malicious package that has already been installed *could* altered it's own package.json during the `postinstall` phase, this mode might add an extra level of safety, making it harder for such packages to fool `no-scripts` compared to the default, local scan. I have not yet evaluated the feasibility of such an attack though.
This option implies [`--include-local`](#include-local-dependencies) as it completely skips the default behavior of resolving the packages listed in the lockfile using a remote registry.
**Note:** Local dependencies which are referenced via links or workspaces are not analyzed in this mode. You can use the [`--include-local`](#include-local-dependencies) option to additionally check those.

@@ -61,0 +58,0 @@ ## Similar Projects

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc