From 6f05f9d5ad0ca4686e796147123a10af8fc2c997 Mon Sep 17 00:00:00 2001 From: hsjobeki Date: Fri, 13 Oct 2023 10:19:51 +0200 Subject: [PATCH] add more unit tests for catching invalid lockfiles early --- lib/internal/nodejsLockUtils.nix | 36 ++-------- .../nodejs-package-lock-v3/default.nix | 1 + .../nix-unit/test_nodejs_lock_v3/default.nix | 16 ++--- .../test_nodejs_lockutils/default.nix | 68 ++++++++++++++++++- 4 files changed, 78 insertions(+), 43 deletions(-) diff --git a/lib/internal/nodejsLockUtils.nix b/lib/internal/nodejsLockUtils.nix index f6cdb09303..f2b8606d9e 100644 --- a/lib/internal/nodejsLockUtils.nix +++ b/lib/internal/nodejsLockUtils.nix @@ -9,13 +9,13 @@ sanitizeLockfile = lock: # Every project MUST have a name - assert lock ? name; + if ! lock ? name then throw "Invalid lockfile: Every project MUST have a name" else # Every project MUST have a version - assert lock ? version; + if ! lock ? version then throw "Invalid lockfile: Every project MUST have a version" else # This lockfile module only supports lockfileVersion 2 and 3 - assert !lock ? lockfileVersion || lock.lockfileVersion >= 2; + if ! lock ? lockfileVersion || lock.lockfileVersion <= 1 then throw "This lockfile module only supports lockfileVersion 2 and 3" else # The Lockfile must contain a 'packages' attribute. - assert lock ? packages; + if ! lock ? packages then throw "Invalid lockfile: The Lockfile must contain 'packages' attribute." else lock; findEntry = @@ -35,32 +35,6 @@ then throw "${search} not found in package-lock.json." else findEntry packageLock (stripPath currentPath) search; - # Returns the names of all "bundledDependencies". - # People depend on different types and different names. Unfortunatly those fields are not part of the offical npm documentation. - # Which may also be the reason for the mess. - # - # TODO: define unit tests. - # Adopted from https://github.com/aakropotkin/floco/blob/708c4ffa0c05033c29fe6886a238cb20c3ba3fb4/modules/plock/implementation.nix#L139 - # - # getBundledDependencies :: Pent -> {} - getBundledDependencies = pent: let - # b :: bool | [] - b = pent.bundledDependencies or pent.bundleDependencies or []; - in - # The following asserts is the XOR logic. - # "bundle" and "bundled" dependencies are both valid but invalid if both or none keys exist - assert ( pent ? bundledDependencies ) -> - ( ! ( pent ? bundleDependencies ) ); - assert ( pent ? bundleDependencies ) -> - ( ! ( pent ? bundledDependencies ) ); - if b == [] then {} else - if builtins.isList b then { bundledDependencies = b; } else - if ! b then {} else { - # b :: true - bundledDependencies = builtins.attrNames ( - ( pent.dependencies or {} ) // ( pent.requires or {} ) - ); - }; in { - inherit findEntry stripPath getBundledDependencies sanitizeLockfile; + inherit findEntry stripPath sanitizeLockfile; } diff --git a/modules/dream2nix/nodejs-package-lock-v3/default.nix b/modules/dream2nix/nodejs-package-lock-v3/default.nix index 1541bb09f3..5406eb4354 100644 --- a/modules/dream2nix/nodejs-package-lock-v3/default.nix +++ b/modules/dream2nix/nodejs-package-lock-v3/default.nix @@ -24,6 +24,7 @@ Pent :: { See: https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#packages } + > We should mention that docs are imcomplete on npmjs.com pent is one entry of 'packages' */ parseSource = pent: diff --git a/tests/nix-unit/test_nodejs_lock_v3/default.nix b/tests/nix-unit/test_nodejs_lock_v3/default.nix index f10307b93f..f51976e7cd 100644 --- a/tests/nix-unit/test_nodejs_lock_v3/default.nix +++ b/tests/nix-unit/test_nodejs_lock_v3/default.nix @@ -297,18 +297,16 @@ in { imports = [ dream2nix.modules.dream2nix.nodejs-package-lock-v3 ]; - nodejs-package-lock-v3.packageLock = lib.mkForce { - # Example content of lockfile - # "lockfileVersion" = 1; - }; + nodejs-package-lock-v3.packageLock = + lib.mkForce { + }; }; config = evaled.config; in { - expr = builtins.tryEval (config.nodejs-package-lock-v3.pdefs); - expected = { - success = false; - value = false; + expr = config.nodejs-package-lock-v3.pdefs; + expectedError = { + type = "ThrownError"; + msg = "Invalid lockfile"; }; }; - } diff --git a/tests/nix-unit/test_nodejs_lockutils/default.nix b/tests/nix-unit/test_nodejs_lockutils/default.nix index 4fc5cd3787..3e38cf006e 100644 --- a/tests/nix-unit/test_nodejs_lockutils/default.nix +++ b/tests/nix-unit/test_nodejs_lockutils/default.nix @@ -74,8 +74,8 @@ expr = path; expected = "node_modules/underscore"; }; - - # test the lock + + # test the lock test_nodejsLockUtils_lockfile_v3 = let plock = { name = "foo"; @@ -110,7 +110,69 @@ }; in { expr = nodejsLockUtils.sanitizeLockfile plock; - expectedError = plock; + expectedError = { + type = "ThrownError"; + msg = "This lockfile module only supports lockfileVersion 2 and 3"; + }; }; + test_nodejsLockUtils_lockfile_missing_name = let + plock = { + # name = "foo"; + version = "1.0.0"; + lockfileVersion = 3; + packages = {}; + }; + in { + expr = nodejsLockUtils.sanitizeLockfile plock; + expectedError = { + type = "ThrownError"; + msg = "MUST have a name"; + }; + }; + + test_nodejsLockUtils_lockfile_missing_version = let + plock = { + name = "foo"; + # version = "1.0.0"; + lockfileVersion = 3; + packages = {}; + }; + in { + expr = nodejsLockUtils.sanitizeLockfile plock; + expectedError = { + type = "ThrownError"; + msg = "MUST have a version"; + }; + }; + + test_nodejsLockUtils_lockfile_missing_lockfileVersion = let + plock = { + name = "foo"; + version = "1.0.0"; + # lockfileVersion = 3; + packages = {}; + }; + in { + expr = nodejsLockUtils.sanitizeLockfile plock; + expectedError = { + type = "ThrownError"; + msg = "lockfileVersion"; + }; + }; + + test_nodejsLockUtils_lockfile_missing_packages = let + plock = { + name = "foo"; + version = "1.0.0"; + lockfileVersion = 3; + # packages = {}; + }; + in { + expr = nodejsLockUtils.sanitizeLockfile plock; + expectedError = { + type = "ThrownError"; + msg = "must contain 'packages'"; + }; + }; }