NPM Audit Fix: The Complete Guide to How It Works - Part 2
Tags: node, npm, javascript
Published: 2020-06-09 20:12:42


In my earlier post, I dived into [how NPM Audit works](https://dev.to/s3cube/npm-audit-a-complete-guide-to-how-it-works-under-the-hood-part-1-56dg). In this concluding post, I talk specifically about how the fix flag works in `npm audit fix`.

To do a quick re-cap if you haven't read the [earlier article](https://dev.to/s3cube/npm-audit-a-complete-guide-to-how-it-works-under-the-hood-part-1-56dg), NPM will use your `package.json` and `package-lock.json` files to create an object consisting of your dependencies. These dependencies are then sent over to your registry(typically NPM) to check for any reported vulnerabilities. Once it receives a response from the registry, NPM begins the process of fixing those vulnerabilities.

The response from NPM outlines the actions to be taken regarding vulnerabilities in your dependencies. The response body looks something like this:

```javascript

"actions": [
        {
            "isMajor": false,
            "action": "install",
            "resolves": [
                {
                    "id": 1486,
                    "path": "http-proxy",
                    "dev": false,
                    "optional": false,
                    "bundled": false
                }
            ],
            "module": "http-proxy",
            "target": "1.18.1"
        }
    ],
```

There may (and probably will) be multiple objects in this actions object returned from the registry.

The first job for NPM is to segregate these individual objects based on their importance and type. It uses a reducer for this, and begins with the object below as the original value. If you aren't very familiar with reducers, check out this Mozilla Developer Network(MDN) link on [how the reduce function works in Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce).

```javascript
{
    install: new Set(),
    installFixes: new Set(),
    update: new Set(),
    updateFixes: new Set(),
    major: new Set(),
    majorFixes: new Set(),
    review: new Set()
}


```
 

#### Alright, so how exactly does audit.js act on this actions array?

To begin with, the actions array seen in the previous snippet is run through a reducer.

In this reducer, each action is passed to a filter function called [filterEnv](https://github.com/npm/cli/blob/abdf52879fcf0e0f534ad977931f6935f5d1dce3/lib/audit.js#L133). This function returns a new object with only the relevant dependencies. The relevant dependencies are identified basis the environment you're building in - essentially dev and production.

There are four buckets a fix may fall into
- install
- update
- major
- review


Using the `isMajor` field and the `action` field seen in each of the objects from  the sample response body above, the sets seen earlier are populated. Depending on the set, information regarding the module, target, id and path of the vulnerability fix is added. You can see this in the [npm audit.js file](https://github.com/npm/cli/blob/abdf52879fcf0e0f534ad977931f6935f5d1dce3/lib/audit.js#L217) here.

Since the sample response is of action type install, the `install` Set would be populated with the module and target. It would look something like:
```javascript
(http-proxy::1.18.1, ... )
```
Meanwhile, the `installFixes` Set would be populated with the id and path. It would look something like:

```javascript
(1486::http-proxy, ... )
```
Similarly, the other sets are also filled depending on the type of vulnerability you're dealing with.

Finally, NPM will install these dependencies by passing the contents of these sets to an instance of the [Auditor Class](https://github.com/npm/cli/blob/abdf52879fcf0e0f534ad977931f6935f5d1dce3/lib/audit.js#L58}) which extends the [Installer Class](https://github.com/npm/cli/blob/abdf52879fcf0e0f534ad977931f6935f5d1dce3/node_modules/libcipm/index.js#L41). The `run()` method is called on this instance which actually runs the installation.


#### Does NPM Audit Fix handle every vulnerability?
Nope. If a particular object has the action key with value `review`, it is added to the review set. These items require manual review by the developer and are not updated automatically.

#### But, I heard about a --force flag?
Correct! But that's primarily for what are considered as "major changes". 

You can identify if a change is a major one through the `isMajor` flag. These are essentially actions that that involve potentially breaking changes. If the `--force` flag is provided, NPM will go ahead and fix the vulnerability - albeit with the inherent risk that something may break.

For other cases where the flag is not specified, NPM will produce a log asking you to fix these manually or use `npm audit fix --force`.



I referred to a couple of resources while writing this article. Here they are:

- https://github.com/npm/cli/blob/latest/lib/audit.js
- https://www.npmjs.com/package/npm-audit-report

Did you like this article? Let me know on <a href="https://twitter.com/SatejSawant">Twitter</a> at <a href="https://twitter.com/SatejSawant">@SatejSawant</a>. If you spot something incorrect, please write to me at satejs93[at]gmail[dot]com. You can also find me on [LinkedIn](https://www.linkedin.com/in/satejsawant).