Skip to content

Commit

Permalink
GR: Add simple test for package-lock.json writing (#891)
Browse files Browse the repository at this point in the history
Added a basic-ish lockfile write test, which needs the mock npm
registry.

Also, fixed a bug on an edge-case where if the new version has new
dependency types (e.g. newly added `optionalDependencies`) it wouldn't
get added to the newly-written lockfile. I had to change how I attempt
to preserve formatting to do that.
  • Loading branch information
michaelkedar authored Mar 28, 2024
1 parent 49223c7 commit 785b6c2
Show file tree
Hide file tree
Showing 8 changed files with 358 additions and 24 deletions.
4 changes: 3 additions & 1 deletion cmd/osv-scanner/__snapshots__/fix_test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ Warning: `fix` exists as both a subcommand of OSV-Scanner and as a file on the f
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.1.tgz",
"integrity": "sha512-gslSSJx03QKa59cIKqeJO9HQ/WZMotvYJCuaUULrLpjj8oG40kV2Z+gz82pVxlTkOADi4PJxQPPfhl1ELYrrXw==",
"engines": ["node >= 0.8"],
"engines": [
"node >= 0.8"
],
"dependencies": {
"inherits": "^2.0.3",
"typedarray": "^0.0.6",
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/pandatix/go-cvss v0.6.2
github.com/spdx/tools-golang v0.5.3
github.com/tidwall/gjson v1.17.1
github.com/tidwall/pretty v1.2.1
github.com/tidwall/sjson v1.2.5
github.com/urfave/cli/v2 v2.27.1
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
Expand Down Expand Up @@ -93,7 +94,6 @@ require (
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/spdx/gordf v0.0.0-20221230105357-b735bd5aac89 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/vbatts/tar-split v0.11.5 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
Expand Down
192 changes: 192 additions & 0 deletions internal/resolution/lockfile/__snapshots__/npm_test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@

[TestNpmWrite - 1]
{
"name": "r",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "r",
"version": "1.0.0",
"license": "ISC",
"workspaces": [
"W"
],
"dependencies": {
"@fake-registry/a": "^1.2.3",
"@fake-registry/b": "^1.0.1"
},
"devDependencies": {
"a-dev": "npm:@fake-registry/a@^2.3.4"
}
},
"node_modules/@fake-registry/a": {
"version": "1.2.4",
"resolved": "http://localhost:4873/@fake-registry%2fa/-/a-1.2.4.tgz",
"integrity": "sha512-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==",
"license": "OriginalLicenseDoNotSteal",
"dependencies": {
"@fake-registry/b": "^1.0.0",
"@fake-registry/e": "^1.0.0"
}
},
"node_modules/@fake-registry/b": {
"version": "1.0.1",
"resolved": "http://localhost:4873/@fake-registry%2fb/-/b-1.0.1.tgz",
"integrity": "sha512-uocjkNUbEPBa/oFFYNq+CkWkkr4My+gJQHnB1fFqIrIQtvjbQ/4dtp/6Kmfb5SFJ/bVfAGZ8mmC+c3Bz4JISYQ==",
"license": "ISC"
},
"node_modules/@fake-registry/c": {
"version": "1.1.1",
"resolved": "http://localhost:4873/@fake-registry%2fc/-/c-1.1.1.tgz",
"integrity": "sha512-bihWUzvU62dcwPN4TguhntQpC1zpj7H0fHAhffya6tl3BCrEdjqO4oEpNHF/jtU5PPvY0L60mJNUS6MbizEVrA==",
"dev": true,
"license": "BSD-2-Clause",
"peerDependencies": {
"@fake-registry/d": "^2.0.0"
}
},
"node_modules/@fake-registry/d": {
"version": "2.2.2",
"resolved": "http://localhost:4873/@fake-registry%2fd/-/d-2.2.2.tgz",
"integrity": "sha512-YLeJVbfOCJZcUizGgpvPesIVSY9TYmWz2HcF+7mWxSuXuvu13FABprnRSDGEhljBRM+QAaUD+nbUHWenq2vL4w==",
"dev": true,
"license": "ISC"
},
"node_modules/a-dev": {
"name": "@fake-registry/a",
"version": "2.3.5",
"resolved": "http://localhost:4873/@fake-registry%2fa/-/a-2.3.5.tgz",
"integrity": "none",
"dev": true,
"license": "Stolen",
"optionalDependencies": {
"@fake-registry/b": "*"
}
},
"node_modules/a-dev/node_modules/@fake-registry/b": {
"version": "2.0.0",
"resolved": "http://localhost:4873/@fake-registry%2fb/-/b-2.0.0.tgz",
"integrity": "sha512-ZYMUG0g+wowBRAVWuRMI9mV8/3IJ5tYw1i+Xedy5LjVo7RAQaOqJbhEWvdubBlkmaXSoI666cdnJIX/SI6FPpw==",
"dev": true,
"license": "ISC",
"dependencies": {
"@fake-registry/c": "^1.0.0",
"@fake-registry/d": "^2.0.0"
}
},
"node_modules/w": {
"resolved": "W",
"link": true
},
"W": {
"name": "w",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@fake-registry/a": "^2.3.4"
}
},
"W/node_modules/@fake-registry/a": {
"version": "2.3.5",
"resolved": "http://localhost:4873/@fake-registry%2fa/-/a-2.3.5.tgz",
"integrity": "none",
"dev": true,
"license": "Stolen",
"optionalDependencies": {
"@fake-registry/b": "*"
}
},
"W/node_modules/@fake-registry/b": {
"version": "2.0.0",
"resolved": "http://localhost:4873/@fake-registry%2fb/-/b-2.0.0.tgz",
"integrity": "sha512-ZYMUG0g+wowBRAVWuRMI9mV8/3IJ5tYw1i+Xedy5LjVo7RAQaOqJbhEWvdubBlkmaXSoI666cdnJIX/SI6FPpw==",
"dev": true,
"license": "ISC",
"dependencies": {
"@fake-registry/c": "^1.0.0",
"@fake-registry/d": "^2.0.0"
}
}
},
"dependencies": {
"@fake-registry/a": {
"version": "1.2.4",
"resolved": "http://localhost:4873/@fake-registry%2fa/-/a-1.2.4.tgz",
"integrity": "sha512-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==",
"requires": {
"@fake-registry/b": "^1.0.0",
"@fake-registry/e": "^1.0.0"
}
},
"@fake-registry/b": {
"version": "1.0.1",
"resolved": "http://localhost:4873/@fake-registry%2fb/-/b-1.0.1.tgz",
"integrity": "sha512-uocjkNUbEPBa/oFFYNq+CkWkkr4My+gJQHnB1fFqIrIQtvjbQ/4dtp/6Kmfb5SFJ/bVfAGZ8mmC+c3Bz4JISYQ=="
},
"@fake-registry/c": {
"version": "1.1.1",
"resolved": "http://localhost:4873/@fake-registry%2fc/-/c-1.1.1.tgz",
"integrity": "sha512-bihWUzvU62dcwPN4TguhntQpC1zpj7H0fHAhffya6tl3BCrEdjqO4oEpNHF/jtU5PPvY0L60mJNUS6MbizEVrA==",
"dev": true,
"requires": {}
},
"@fake-registry/d": {
"version": "2.2.2",
"resolved": "http://localhost:4873/@fake-registry%2fd/-/d-2.2.2.tgz",
"integrity": "sha512-YLeJVbfOCJZcUizGgpvPesIVSY9TYmWz2HcF+7mWxSuXuvu13FABprnRSDGEhljBRM+QAaUD+nbUHWenq2vL4w==",
"dev": true
},
"a-dev": {
"version": "npm:@fake-registry/[email protected]",
"resolved": "http://localhost:4873/@fake-registry%2fa/-/a-2.3.5.tgz",
"integrity": "none",
"dev": true,
"requires": {
"@fake-registry/b": "*"
},
"dependencies": {
"@fake-registry/b": {
"version": "2.0.0",
"resolved": "http://localhost:4873/@fake-registry%2fb/-/b-2.0.0.tgz",
"integrity": "sha512-ZYMUG0g+wowBRAVWuRMI9mV8/3IJ5tYw1i+Xedy5LjVo7RAQaOqJbhEWvdubBlkmaXSoI666cdnJIX/SI6FPpw==",
"dev": true,
"requires": {
"@fake-registry/c": "^1.0.0",
"@fake-registry/d": "^2.0.0"
}
}
}
},
"w": {
"version": "file:W",
"requires": {
"@fake-registry/a": "^2.3.4"
},
"dependencies": {
"@fake-registry/a": {
"version": "2.3.5",
"resolved": "http://localhost:4873/@fake-registry%2fa/-/a-2.3.5.tgz",
"integrity": "none",
"dev": true,
"requires": {
"@fake-registry/b": "*"
}
},
"@fake-registry/b": {
"version": "2.0.0",
"resolved": "http://localhost:4873/@fake-registry%2fb/-/b-2.0.0.tgz",
"integrity": "sha512-ZYMUG0g+wowBRAVWuRMI9mV8/3IJ5tYw1i+Xedy5LjVo7RAQaOqJbhEWvdubBlkmaXSoI666cdnJIX/SI6FPpw==",
"dev": true,
"requires": {
"@fake-registry/c": "^1.0.0",
"@fake-registry/d": "^2.0.0"
}
}
}
}
}
}

---
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@fake-registry/a",
"version": "1.2.4",
"description": "package a",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": {
"name": "a author"
},
"license": "OriginalLicenseDoNotSteal",
"dependencies": {
"@fake-registry/b": "^1.0.0",
"@fake-registry/e": "^1.0.0"
},
"_id": "@fake-registry/[email protected]",
"_nodeVersion": "10.24.1",
"_npmVersion": "7.24.2",
"dist": {
"integrity": "sha512-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==",
"shasum": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"tarball": "http://localhost:4873/@fake-registry%2fa/-/a-1.2.4.tgz"
},
"contributors": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@fake-registry/a",
"version": "2.3.5",
"description": "package a@2",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": {
"name": "a@2 author"
},
"license": "Stolen",
"optionalDependencies": {
"@fake-registry/b": "*"
},
"dependencies": {
"@fake-registry/b": "*"
},
"_id": "@fake-registry/[email protected]",
"_nodeVersion": "10.24.1",
"_npmVersion": "7.24.2",
"dist": {
"integrity": "none",
"shasum": "ffffffff",
"tarball": "http://localhost:4873/@fake-registry%2fa/-/a-2.3.5.tgz"
},
"contributors": []
}
65 changes: 65 additions & 0 deletions internal/resolution/lockfile/npm_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package lockfile_test

import (
"bytes"
"os"
"path/filepath"
"testing"

"deps.dev/util/resolve"
"deps.dev/util/resolve/dep"
"github.com/google/go-cmp/cmp"
"github.com/google/osv-scanner/internal/resolution/lockfile"
"github.com/google/osv-scanner/internal/testutility"
lf "github.com/google/osv-scanner/pkg/lockfile"
)

Expand Down Expand Up @@ -142,3 +146,64 @@ func TestNpmReadV1(t *testing.T) {
t.Errorf("npm lockfile mismatch (-want/+got):\n%s", diff)
}
}

func TestNpmWrite(t *testing.T) {
t.Parallel()

// Set up mock npm registry
srv := testutility.NewMockHTTPServer(t)
srv.SetResponseFromFile(t, "/@fake-registry%2Fa/1.2.4", "./fixtures/npm_registry/@fake-registry-a-1.2.4.json")
srv.SetResponseFromFile(t, "/@fake-registry%2Fa/2.3.5", "./fixtures/npm_registry/@fake-registry-a-2.3.5.json")

// Copy package-lock.json to temporary directory
dir := testutility.CreateTestDir(t)
b, err := os.ReadFile("./fixtures/npm_v2/package-lock.json")
if err != nil {
t.Fatalf("could not read test file: %v", err)
}
file := filepath.Join(dir, "package-lock.json")
if err := os.WriteFile(file, b, 0600); err != nil {
t.Fatalf("could not copy test file: %v", err)
}

// create an npmrc file in temp directory pointing to mock registry
npmrcFile, err := os.Create(filepath.Join(dir, ".npmrc"))
if err != nil {
t.Fatalf("could not create .npmrc file: %v", err)
}
if _, err := npmrcFile.WriteString("registry=" + srv.URL); err != nil {
t.Fatalf("failed writing npmrc file: %v", err)
}

patches := []lockfile.DependencyPatch{
{
Pkg: resolve.PackageKey{
System: resolve.NPM,
Name: "@fake-registry/a",
},
OrigVersion: "1.2.3",
NewVersion: "1.2.4",
},
{
Pkg: resolve.PackageKey{
System: resolve.NPM,
Name: "@fake-registry/a",
},
OrigVersion: "2.3.4",
NewVersion: "2.3.5",
},
}

df, err := lf.OpenLocalDepFile(file)
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
defer df.Close()

buf := new(bytes.Buffer)
npmIO := lockfile.NpmLockfileIO{}
if err := npmIO.Write(df, buf, patches); err != nil {
t.Fatalf("unable to update npm package-lock.json: %v", err)
}
testutility.NewSnapshot().WithCRLFReplacement().MatchText(t, buf.String())
}
2 changes: 1 addition & 1 deletion internal/resolution/lockfile/npm_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (rw NpmLockfileIO) modifyPackageLockDependencies(lockJSON string, patches m

func (rw NpmLockfileIO) modifyPackageLockDependenciesRecurse(lockJSON, path string, depth int, patches map[string]map[string]string, api *datasource.NpmRegistryAPIClient) (string, error) {
for pkg, data := range gjson.Get(lockJSON, path).Map() {
pkgPath := fmt.Sprintf("%s.%s", path, strings.ReplaceAll(pkg, ".", "\\."))
pkgPath := fmt.Sprintf("%s.%s", path, gjson.Escape(pkg))
if data.Get("dependencies").Exists() {
var err error
lockJSON, err = rw.modifyPackageLockDependenciesRecurse(lockJSON, pkgPath+".dependencies", depth+1, patches, api)
Expand Down
Loading

0 comments on commit 785b6c2

Please sign in to comment.