Skip to content
24 changes: 12 additions & 12 deletions src/org/labkey/test/tests/PackageLockJsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
public class PackageLockJsonTest
{
private static final Set<String> ALLOWED_DEPENDENCY_HOSTS = Set.of("registry.npmjs.org", "labkey.jfrog.io");
// Allow-list of '@isaacs/cliui' dependencies
private static final Set<String> 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 File SERVER_MODULES_DIR = new File(TestFileUtils.getLabKeyRoot(), "server/modules");

private final List<String> errors = new ArrayList<>();
private final File moduleDir;
Expand All @@ -44,11 +43,10 @@ public static Collection<Object[]> data()
{
List<File> 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)
{
Expand Down Expand Up @@ -96,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
{
Expand All @@ -116,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);
}
Expand All @@ -132,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);
}
Expand All @@ -148,9 +148,9 @@ 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.replaceAll("^npm:", "").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);
}
Expand Down