From 5ec65d910957d7c34cb4a9274c267c5d7c457844 Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 13 May 2026 08:41:08 -0500 Subject: [PATCH 1/6] PackageLockJsonTest update to add "npm:react-is@" aliases to ALLOWED_NONSTANDARD_VERSIONS --- src/org/labkey/test/tests/PackageLockJsonTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/tests/PackageLockJsonTest.java b/src/org/labkey/test/tests/PackageLockJsonTest.java index b9b040957b..350efcf74e 100644 --- a/src/org/labkey/test/tests/PackageLockJsonTest.java +++ b/src/org/labkey/test/tests/PackageLockJsonTest.java @@ -29,7 +29,7 @@ public class PackageLockJsonTest { private static final Set ALLOWED_DEPENDENCY_HOSTS = Set.of("registry.npmjs.org", "labkey.jfrog.io"); // Allow-list of '@isaacs/cliui' dependencies - private static final Set ALLOWED_NONSTANDARD_VERSIONS = Set.of("npm:string-width@^4.2.0", "npm:strip-ansi@^6.0.1", "npm:wrap-ansi@^7.0.0"); + private static final Set ALLOWED_NONSTANDARD_VERSIONS = Set.of("npm:string-width@^4.2.0", "npm:strip-ansi@^6.0.1", "npm:wrap-ansi@^7.0.0", "npm:react-is@^18.3.1", "npm:react-is@^19.2.5"); private final List errors = new ArrayList<>(); private final File moduleDir; From f91d907d90944135130f27990d3d0a1cdd679383 Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 13 May 2026 08:57:33 -0500 Subject: [PATCH 2/6] comment update --- src/org/labkey/test/tests/PackageLockJsonTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/tests/PackageLockJsonTest.java b/src/org/labkey/test/tests/PackageLockJsonTest.java index 350efcf74e..00e0a5eec0 100644 --- a/src/org/labkey/test/tests/PackageLockJsonTest.java +++ b/src/org/labkey/test/tests/PackageLockJsonTest.java @@ -28,7 +28,7 @@ public class PackageLockJsonTest { private static final Set ALLOWED_DEPENDENCY_HOSTS = Set.of("registry.npmjs.org", "labkey.jfrog.io"); - // Allow-list of '@isaacs/cliui' dependencies + // Allow-list of alias names for transitive dependencies (including '@isaacs/cliui' dependencies) private static final Set ALLOWED_NONSTANDARD_VERSIONS = Set.of("npm:string-width@^4.2.0", "npm:strip-ansi@^6.0.1", "npm:wrap-ansi@^7.0.0", "npm:react-is@^18.3.1", "npm:react-is@^19.2.5"); private final List errors = new ArrayList<>(); From 023c122296839c6e24025eaa5d1ad8a7526a6f72 Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 13 May 2026 09:14:50 -0500 Subject: [PATCH 3/6] revert ALLOWED_NONSTANDARD_VERSIONS change (taking another approach) --- src/org/labkey/test/tests/PackageLockJsonTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/labkey/test/tests/PackageLockJsonTest.java b/src/org/labkey/test/tests/PackageLockJsonTest.java index 00e0a5eec0..b9b040957b 100644 --- a/src/org/labkey/test/tests/PackageLockJsonTest.java +++ b/src/org/labkey/test/tests/PackageLockJsonTest.java @@ -28,8 +28,8 @@ public class PackageLockJsonTest { private static final Set ALLOWED_DEPENDENCY_HOSTS = Set.of("registry.npmjs.org", "labkey.jfrog.io"); - // Allow-list of alias names for transitive dependencies (including '@isaacs/cliui' dependencies) - private static final Set ALLOWED_NONSTANDARD_VERSIONS = Set.of("npm:string-width@^4.2.0", "npm:strip-ansi@^6.0.1", "npm:wrap-ansi@^7.0.0", "npm:react-is@^18.3.1", "npm:react-is@^19.2.5"); + // Allow-list of '@isaacs/cliui' dependencies + private static final Set ALLOWED_NONSTANDARD_VERSIONS = Set.of("npm:string-width@^4.2.0", "npm:strip-ansi@^6.0.1", "npm:wrap-ansi@^7.0.0"); private final List errors = new ArrayList<>(); private final File moduleDir; From 9a41ae86ce668d531f6842428b76a9e3bcff2d1d Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 13 May 2026 09:34:06 -0500 Subject: [PATCH 4/6] PackageLockJsonTest update to allow for transitive dependencies with "npm:" alias prefix --- src/org/labkey/test/tests/PackageLockJsonTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/org/labkey/test/tests/PackageLockJsonTest.java b/src/org/labkey/test/tests/PackageLockJsonTest.java index b9b040957b..1b10b3cd78 100644 --- a/src/org/labkey/test/tests/PackageLockJsonTest.java +++ b/src/org/labkey/test/tests/PackageLockJsonTest.java @@ -28,8 +28,6 @@ public class PackageLockJsonTest { private static final Set ALLOWED_DEPENDENCY_HOSTS = Set.of("registry.npmjs.org", "labkey.jfrog.io"); - // Allow-list of '@isaacs/cliui' dependencies - private static final Set ALLOWED_NONSTANDARD_VERSIONS = Set.of("npm:string-width@^4.2.0", "npm:strip-ansi@^6.0.1", "npm:wrap-ansi@^7.0.0"); private final List errors = new ArrayList<>(); private final File moduleDir; @@ -148,7 +146,7 @@ private void verifyPackage(String packageName, JSONObject packageJson, File pack else { String tVer = transitiveDeps.optString(tDep); - if (tVer == null || tVer.contains(":") && !ALLOWED_NONSTANDARD_VERSIONS.contains(tVer)) // URL, file, or workspace dependency + if (tVer == null || (tVer.contains(":") && !tVer.startsWith("npm:"))) // URL, file, or workspace dependency { String message = "Package " + packageName + " has bad transitive dependency [" + tVer + "] in " + packageLockFile.getAbsolutePath(); errors.add(message); From df04f44ca1b451d6f86182c8c5ed1bfa9f48a615 Mon Sep 17 00:00:00 2001 From: labkey-tchad Date: Wed, 13 May 2026 09:57:01 -0700 Subject: [PATCH 5/6] Improve error message formatting --- .../test/tests/PackageLockJsonTest.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/org/labkey/test/tests/PackageLockJsonTest.java b/src/org/labkey/test/tests/PackageLockJsonTest.java index 1b10b3cd78..5a90e92764 100644 --- a/src/org/labkey/test/tests/PackageLockJsonTest.java +++ b/src/org/labkey/test/tests/PackageLockJsonTest.java @@ -28,6 +28,7 @@ public class PackageLockJsonTest { private static final Set ALLOWED_DEPENDENCY_HOSTS = Set.of("registry.npmjs.org", "labkey.jfrog.io"); + private static final File SERVER_MODULES_DIR = new File(TestFileUtils.getLabKeyRoot(), "server/modules"); private final List errors = new ArrayList<>(); private final File moduleDir; @@ -42,11 +43,10 @@ public static Collection data() { List allModules = new ArrayList<>(); - File modulesDir = new File(TestFileUtils.getLabKeyRoot(), "server/modules"); - File[] files = modulesDir.listFiles(); + File[] files = SERVER_MODULES_DIR.listFiles(); if (files == null) { - throw new RuntimeException("No files found in modules directory: " + modulesDir.getAbsolutePath()); + throw new RuntimeException("No files found in modules directory: " + SERVER_MODULES_DIR.getAbsolutePath()); } for (File file : files) { @@ -94,17 +94,19 @@ public void testPackageLock() throws Exception } } - Assert.assertTrue("Bad sources: " + errors, errors.isEmpty()); + Assert.assertTrue("Untrusted package sources:\n" + String.join("\n", errors), errors.isEmpty()); } /// Verify that a package reference in a package-lock.json file only resolves to known hosts and has a valid version /// Also checks sub-dependencies private void verifyPackage(String packageName, JSONObject packageJson, File packageLockFile) { + String relPath = SERVER_MODULES_DIR.toPath().relativize(packageLockFile.toPath()).toString(); + String resolved = packageJson.optString("resolved"); if (resolved.isBlank()) { - TestLogger.debug("Resolved field is blank for package " + packageName + " in " + packageLockFile.getAbsolutePath()); + TestLogger.debug("Resolved field is blank for package " + packageName + " in " + relPath); } else { @@ -114,14 +116,14 @@ private void verifyPackage(String packageName, JSONObject packageJson, File pack String host = resolvedURL.getHost(); if (!ALLOWED_DEPENDENCY_HOSTS.contains(host)) { - String message = "Package " + packageName + " resolved to unrecognized host [" + host + "] in " + packageLockFile.getAbsolutePath(); + String message = "Package " + packageName + " resolved to unrecognized host [" + host + "] in " + relPath; errors.add(message); TestLogger.error(message); } } catch (URISyntaxException e) { - String message = "Package " + packageName + " resolved to an invalid location [" + resolved + "] in " + packageLockFile.getAbsolutePath(); + String message = "Package " + packageName + " resolved to an invalid location [" + resolved + "] in " + relPath; errors.add(message); TestLogger.error(message); } @@ -130,7 +132,7 @@ private void verifyPackage(String packageName, JSONObject packageJson, File pack String version = packageJson.optString("version"); if (version.isBlank() || !CharUtils.isAsciiNumeric(version.charAt(0))) { - String message = "Package " + packageName + " has bad version [" + version + "] in " + packageLockFile.getAbsolutePath(); + String message = "Package " + packageName + " has bad version [" + version + "] in " + relPath; errors.add(message); TestLogger.error(message); } @@ -146,9 +148,9 @@ private void verifyPackage(String packageName, JSONObject packageJson, File pack else { String tVer = transitiveDeps.optString(tDep); - if (tVer == null || (tVer.contains(":") && !tVer.startsWith("npm:"))) // URL, file, or workspace dependency + if (tVer == null || (tVer.contains(":"))) // URL, file, or workspace dependency { - String message = "Package " + packageName + " has bad transitive dependency [" + tVer + "] in " + packageLockFile.getAbsolutePath(); + String message = "Package " + packageName + " has bad transitive dependency [" + tVer + "] in " + relPath; errors.add(message); TestLogger.error(message); } From 69726b7782486cadfe5d0bab90843b90925e043d Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 13 May 2026 16:51:24 -0500 Subject: [PATCH 6/6] CR feedback - trim off starting "npm:" prefix before check --- src/org/labkey/test/tests/PackageLockJsonTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/tests/PackageLockJsonTest.java b/src/org/labkey/test/tests/PackageLockJsonTest.java index 5a90e92764..14a255a10e 100644 --- a/src/org/labkey/test/tests/PackageLockJsonTest.java +++ b/src/org/labkey/test/tests/PackageLockJsonTest.java @@ -148,7 +148,7 @@ private void verifyPackage(String packageName, JSONObject packageJson, File pack else { String tVer = transitiveDeps.optString(tDep); - if (tVer == null || (tVer.contains(":"))) // URL, file, or workspace dependency + if (tVer == null || tVer.replaceAll("^npm:", "").contains(":")) // URL, file, or workspace dependency { String message = "Package " + packageName + " has bad transitive dependency [" + tVer + "] in " + relPath; errors.add(message);