
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
Assert your published package actually works
Running your regular test suite (e.g., npm test) in CI will miss packaging-related issues, such as missing files and package exports.
There's no staging registry you can test with, so when something's published, it's published. If there's a problem with it, you have to issue a patch and publish again. We can't avoid the problem entirely, but packtester gets us closer.
This is kind of a pain to setup manually, so automating it might be nice, right?
$ npm install packtester --save-dev
TODO: via
initcommand; needs implementation
Add a pretest script to your scripts field in package.json:
{
"scripts": {
"pretest": "packtester",
"test": "my-regular-test-script"
}
}
It's recommended to also run
packtesterduringprepublishOnly, so it will check at the last minute before you publish.
Create a __pack_tests__ directory. All files (with .js, .cjs, and .mjs extensions, by default) in this directory will be run with your module installed as a dependency. Here's an example file:
// packtester.packtest.js
const assert = require('assert');
// remember, use your package like a consumer would
const pkg = require('packtester/package.json'); // yeah yeah I know
let packtester;
assert.doesNotThrow(() => {
packtester = require(pkg.name);
}, `could not require('${pkg.name}')`);
// packtester exports a function, `packTest`
assert.ok(
typeof packtester.packTest === 'function',
'did not export "packTest" function'
);
// ESM!
assert.doesNotReject(import(pkg.name), `could not import('${pkg.name}')`);
assert.doesNotThrow(() => {
require(`${pkg.name}/${pkg.main}`);
}, `could not require('${pkg.name}/${pkg.main}') directly`);
You do not need to add test files for packtester to your published package (unless you want to); in other words, they don't need to be in the files prop of package.json and/or can be added to .npmignore, if desired.
Run packtester as a job or step before the main test suite (e.g., npm test) as a "smoke test," and have subsequent steps wait for this to complete successfully.
Add a smoke-test script to package.json (remove the "pretest": "packtester" script, if present):
{
"scripts": {
"smoke-test": "packtester",
"test": "your-test-command"
}
}
And in your workflow file (e.g., .github/workflows/my-workflow.yml):
jobs:
smoke-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: bahmutov/npm-install@v1
- name: Smoke Test
run: npm run smoke-test
test:
runs-on: ubuntu-latest
needs: smoke-test
steps:
- uses: actions/checkout@v2
- uses: bahmutov/npm-install@v1
- name: Full Test Suite
run: npm test
By supplying positional arguments to packtester, you can point it at any directory, file, or glob. Example:
{
"scripts": {
"pretest": "packtester \"my-smoke-tests/**/*.js\"",
"test": "my-regular-test-script"
}
}
package.jsonpacktester needs the package.json of your package to run. Use the --package <package.json> command-line option to use a specific package.json file. This may be useful in a monorepo or workspace. Example:
{
"scripts": {
"pretest": "packtester --package=./packages/subpackage/package.json",
"test": "my-regular-test-script"
}
}
Run npx packtester --help to see more usage options.
packtester exports a single property, packTest, which is an async function.
packtester.packTest([opts]): Promise<void>Does everything the packtester CLI does.
opts is an options object and supports properties (all optional):
{string|string[]} target - One or more target files, dirs, globs. Defaults to __pack_tests__{string} cwd - Current working directory{PackageJson} pkg - A parsed package.json{string} npmPath - Path to npm executable{number} logLevel - Log level, 0-5, with 0 being "error" and 5 being "trace"The purpose of these tests is to make assertions about the state of your package's public API. The question you're trying to answer is this: is my package usable when installed via a package manager?
Remember: you won't have your devDependencies installed; this means no test frameworks, assertion libraries, etc. The built-in assert module works well for this use case.
TODO
packtester:
npm pack on your project to generate a tarball in a temporary directorynpm install against the tarball in the temp dirBy installing from a tarball created from npm pack, we simulate what would happen if you installed your project via a package manager, e.g., npm install my-package.
Copyright © 2020 Christopher Hiller. Licensed Apache-2.0
FAQs
Assert your published package actually works
We found that packtester demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.