Repository: lirantal/lockfile-lint
Pull request #188 (2024-02-10 16:31:14)

Add option to exclude packages from the `--validate-integrity` check
<!--- Provide a general summary of your changes in the Title above -->

## Description

Add a new option available on the CLI as --integrity-exclude which allows user to disable the --validate-integrity check for specific packages.

Also, format the table in the lockfile-lint package's README. Some more formatting happened as a result of commit hooks.

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Related Issue

#187

## Motivation and Context

I have a project where I use a dependency available only on the GitLab npm registry. This registry only provides SHA1 integrity values and so dependency installed from there are rejected when using the `--validate-integrity` option. As a result I can't use `--validate-integrity` to at least enforce strong integrity values for dependencies from other registries.

## How Has This Been Tested?

Unit testing: updated the tests and ran `npm run test`. I was using Node.js v20.9.0 while working on this.

## Screenshots (if appropriate):

n/a

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] I have updated the documentation (if required).
- [x] I have read the **CONTRIBUTING** document.
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.
- [x] I added a picture of a cute animal cause it's fun

![cute animal](https://github.com/lirantal/lockfile-lint/assets/3742559/f30c6afe-c912-41b5-8615-ef8e00f7ba95)


codecov-commenter: ## [Codecov](https://app.codecov.io/gh/lirantal/lockfile-lint/pull/188?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Liran+Tal) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`7958b39`)](https://app.codecov.io/gh/lirantal/lockfile-lint/commit/7958b394339c9af12d319956373de75fe5599189?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Liran+Tal) 97.98% compared to head [(`afcefd9`)](https://app.codecov.io/gh/lirantal/lockfile-lint/pull/188?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Liran+Tal) 98.01%.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #188      +/-   ##
==========================================
+ Coverage   97.98%   98.01%   +0.02%     
==========================================
  Files          13       13              
  Lines         398      403       +5     
  Branches       93       96       +3     
==========================================
+ Hits          390      395       +5     
  Misses          8        8              
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/lirantal/lockfile-lint/pull/188?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Liran+Tal).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Liran+Tal).

lirantal: Superb. Thank you Eric!

Patch:
diff --git a/packages/lockfile-lint-api/src/validators/ValidateIntegrity.js b/packages/lockfile-lint-api/src/validators/ValidateIntegrity.js
index 9ea616f..f539683 100644
--- a/packages/lockfile-lint-api/src/validators/ValidateIntegrity.js
+++ b/packages/lockfile-lint-api/src/validators/ValidateIntegrity.js
@@ -13,7 +13,12 @@ module.exports = class ValidateIntegrity {
     this.packages = packages
   }
 
-  validate () {
+  validate (options) {
+    const excludedPackages = options && options.integrityExclude ? options.integrityExclude : []
+    if (!Array.isArray(excludedPackages)) {
+      throw new Error('excluded packages must be an array')
+    }
+
     const validationResult = {
       type: 'success',
       errors: []
@@ -24,12 +29,14 @@ module.exports = class ValidateIntegrity {
         continue
       }
 
+      if (excludedPackages.includes(packageName)) {
+        continue
+      }
+
       try {
         if (!isSha512(packageMetadata)) {
           validationResult.errors.push({
-            message: `detected invalid integrity hash type for package: ${packageName}\n    expected: sha512\n    actual: ${
-              packageMetadata.integrity
-            }\n`,
+            message: `detected invalid integrity hash type for package: ${packageName}\n    expected: sha512\n    actual: ${packageMetadata.integrity}\n`,
             package: packageName
           })
         }
diff --git a/packages/lockfile-lint/README.md b/packages/lockfile-lint/README.md
index c54ab8c..4d6ce48 100644
--- a/packages/lockfile-lint/README.md
+++ b/packages/lockfile-lint/README.md
@@ -78,17 +78,18 @@ lockfile-lint --path yarn.lock --allowed-hosts yarn --allowed-urls https://githu
 
 | command line argument            | description                                                                                                                                                                                                                                                                           | implemented   |
 |----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
-| `--path`, `-p`                   | path to the lockfile but you can also provide a glob matching pattern as long as it isn't expanded by a shell like bash or zsh. If that's the case, you can provide it as a string, for example: `-p '/Users/lirantal/repos/**/package-lock.json'` to match multiple lockfiles                                                                                                                                                                                                                                                                  | ✅             |
-| `--type`, `-t`                   | lockfile type, options are `npm` or `yarn`                                                                                                                                                                                                                                            | ✅             |
-| `--format`, `-f`                 | sets what type of report output is desired, one of [ `pretty`, `plain` ] with `plain` removing colors & status symbols from output                                                                                                                                                    | ✅             |
-| `--validate-https`, `-s`         | validates the use of HTTPS as protocol schema for all resources in the lockfile                                                                                                                                                                                                       | ✅             |
-| `--allowed-hosts`, `-a`          | validates a list of allowed hosts to be used for all resources in the lockfile. Supported short-hands aliases are `npm`, `yarn`, and `verdaccio` which will match URLs `https://registry.npmjs.org`, `https://registry.yarnpkg.com` and `https://registry.verdaccio.org` respectively | ✅             |
-| `--allowed-schemes`, `-o`        | allowed [URI schemes](https://tools.ietf.org/html/rfc2396#section-3.1) such as "https:", "http", "git+ssh:", or "git+https:"                                                                                                                                                          | ✅             |
-| `--allowed-urls`, `-u`           | allowed URLs (e.g. `https://github.com/some-org/some-repo#some-hash`)                                                                                                                                                                                                                 | ✅             |
-| `--empty-hostname`, `-e`         | allow empty hostnames, or set to false if you wish for a stricter policy                                                                                                                                                                                                              | ✅             |
-| `--validate-package-names`, `-n` | validates that the resolved URL matches the package name                                                                                                                                                                                                                              | ✅             |
-| `--validate-integrity`, `-i`     | validates the integrity field is a sha512 hash                                                                                                                                                                                                                                        | ✅             |
-| `--allowed-package-name-aliases`, `-l`     | allow package name aliases to be used by specifying package name and their alias as pairs (e.g: `string-width-cjs:string-width`)                                                                                                                                                                                                                                        | ✅             |
+| `--path`, `-p`                   | path to the lockfile but you can also provide a glob matching pattern as long as it isn't expanded by a shell like bash or zsh. If that's the case, you can provide it as a string, for example: `-p '/Users/lirantal/repos/**/package-lock.json'` to match multiple lockfiles        | ✅            |
+| `--type`, `-t`                   | lockfile type, options are `npm` or `yarn`                                                                                                                                                                                                                                            | ✅            |
+| `--format`, `-f`                 | sets what type of report output is desired, one of [ `pretty`, `plain` ] with `plain` removing colors & status symbols from output                                                                                                                                                    | ✅            |
+| `--validate-https`, `-s`         | validates the use of HTTPS as protocol schema for all resources in the lockfile                                                                                                                                                                                                       | ✅            |
+| `--allowed-hosts`, `-a`          | validates a list of allowed hosts to be used for all resources in the lockfile. Supported short-hands aliases are `npm`, `yarn`, and `verdaccio` which will match URLs `https://registry.npmjs.org`, `https://registry.yarnpkg.com` and `https://registry.verdaccio.org` respectively | ✅            |
+| `--allowed-schemes`, `-o`        | allowed [URI schemes](https://tools.ietf.org/html/rfc2396#section-3.1) such as "https:", "http", "git+ssh:", or "git+https:"                                                                                                                                                          | ✅            |
+| `--allowed-urls`, `-u`           | allowed URLs (e.g. `https://github.com/some-org/some-repo#some-hash`)                                                                                                                                                                                                                 | ✅            |
+| `--empty-hostname`, `-e`         | allow empty hostnames, or set to false if you wish for a stricter policy                                                                                                                                                                                                              | ✅            |
+| `--validate-package-names`, `-n` | validates that the resolved URL matches the package name                                                                                                                                                                                                                              | ✅            |
+| `--validate-integrity`, `-i`     | validates the integrity field is a sha512 hash                                                                                                                                                                                                                                        | ✅            |
+| `--allowed-package-name-aliases`, `-l` | allow package name aliases to be used by specifying package name and their alias as pairs (e.g: `string-width-cjs:string-width`)                                                                                                                                                | ✅            |
+| `--integrity-exclude`            | exclude packages from the `--validate-integrity` check                                                                                                                                                                                                                                | ✅            |
 
 # File-Based Configuration
 
diff --git a/packages/lockfile-lint/bin/lockfile-lint.js b/packages/lockfile-lint/bin/lockfile-lint.js
index dfdec9b..b183236 100755
--- a/packages/lockfile-lint/bin/lockfile-lint.js
+++ b/packages/lockfile-lint/bin/lockfile-lint.js
@@ -81,7 +81,8 @@ for (const lockfilePath of lockfilesList) {
           emptyHostname: config['empty-hostname'],
           allowedHosts: config['allowed-hosts'],
           allowedUrls: config['allowed-urls'],
-          allowedPackageNameAliases: config['allowed-package-name-aliases']
+          allowedPackageNameAliases: config['allowed-package-name-aliases'],
+          integrityExclude: config['integrity-exclude']
         }
       })
     }
diff --git a/packages/lockfile-lint/src/config.js b/packages/lockfile-lint/src/config.js
index ccadc0e..ce26c52 100644
--- a/packages/lockfile-lint/src/config.js
+++ b/packages/lockfile-lint/src/config.js
@@ -85,6 +85,10 @@ module.exports = (argv, exitProcess = false, searchFrom = process.cwd()) => {
         type: 'array',
         describe: 'validates an alias of package names to be used for resources in the lockfile'
       },
+      'integrity-exclude': {
+        type: 'array',
+        describe: 'do not validate integrity for these package'
+      },
       format: {
         alias: ['f'],
         type: 'string',
diff --git a/packages/lockfile-lint/src/validators/index.js b/packages/lockfile-lint/src/validators/index.js
index 2d5f7e6..ff780de 100644
--- a/packages/lockfile-lint/src/validators/index.js
+++ b/packages/lockfile-lint/src/validators/index.js
@@ -134,5 +134,5 @@ function ValidateIntegrityManager ({path, type, validatorValues, validatorOption
   const lockfile = parser.parseSync()
   const validator = new ValidateIntegrity({packages: lockfile.object})
 
-  return validator.validate()
+  return validator.validate(validatorOptions)
 }


Test patch:
diff --git a/packages/lockfile-lint-api/__tests__/validators.integrityHashType.test.js b/packages/lockfile-lint-api/__tests__/validators.integrityHashType.test.js
index fe3dc9b..dde6c51 100644
--- a/packages/lockfile-lint-api/__tests__/validators.integrityHashType.test.js
+++ b/packages/lockfile-lint-api/__tests__/validators.integrityHashType.test.js
@@ -17,6 +17,15 @@ describe('Validator: Integrity', () => {
     expect(() => new ValidateIntegrity()).toThrowError()
   })
 
+  it('validator should throw an error when excludedPackages is not an array', () => {
+    const options = {
+      integrityExclude: 'not-an-array'
+    }
+
+    const validator = new ValidateIntegrity({packages: {}})
+    expect(() => validator.validate(options)).toThrowError()
+  })
+
   it('validator should fail if not allowed hash type is used for a resource', () => {
     const mockedPackages = {
       bolt11: {
@@ -29,7 +38,8 @@ describe('Validator: Integrity', () => {
       type: 'error',
       errors: [
         {
-          message: 'detected invalid integrity hash type for package: bolt11\n    expected: sha512\n    actual: sha1-1ZNEUixLxGSmWnMKxpUAf9tm3Yg=\n',
+          message:
+            'detected invalid integrity hash type for package: bolt11\n    expected: sha512\n    actual: sha1-1ZNEUixLxGSmWnMKxpUAf9tm3Yg=\n',
           package: 'bolt11'
         }
       ]
@@ -71,6 +81,23 @@ describe('Validator: Integrity', () => {
     })
   })
 
+  it('validator should not fail if an excluded package has an invalid integrity hash type', () => {
+    const mockedPackages = {
+      typescript: {
+        integrity: 'sha1-1ZNEUixLxGSmWnMKxpUAf9tm3Yg='
+      }
+    }
+    const options = {
+      integrityExclude: ['typescript']
+    }
+
+    const validator = new ValidateIntegrity({packages: mockedPackages})
+    expect(validator.validate(options)).toEqual({
+      type: 'success',
+      errors: []
+    })
+  })
+
   it('validator should return true for a single package with a valid URL', () => {
     const mockedPackages = {
       typescript: {