diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a75f087f..76b080c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [Unreleased] + +### Fixed +- Maven Socket facts honor artifact types that build extensions define, so they no longer list dependencies Maven doesn't resolve, or fetch files under the wrong extension. + ## [1.15.0](https://github.com/SocketDev/socket-cli/releases/tag/v1.15.0) - 2026-11-12 ### Added diff --git a/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketFactsRecordsEngine.java b/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketFactsRecordsEngine.java index 14e098e1e..0400d7680 100644 --- a/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketFactsRecordsEngine.java +++ b/src/commands/manifest/scripts/maven-extension/src/main/java/tech/coana/socket/SocketFactsRecordsEngine.java @@ -168,7 +168,13 @@ public void run(MavenSession session, List reactor, File rootDir, if (SocketSupport.isExcludedDir(excludeBase, module.getBasedir().toPath(), excludes)) continue; Map nodes = new LinkedHashMap<>(); Set directIds = new HashSet<>(); - collectModule(session, module, passingScopes, reactorGavs, populateGavs, opts, nodes, directIds, failures, unscannable); + ClassLoader previous = Thread.currentThread().getContextClassLoader(); + if (module.getClassRealm() != null) Thread.currentThread().setContextClassLoader(module.getClassRealm()); + try { + collectModule(session, module, passingScopes, reactorGavs, populateGavs, opts, nodes, directIds, failures, unscannable); + } finally { + Thread.currentThread().setContextClassLoader(previous); + } rootIdx = emitModuleRoots(lines, rootIdx, projectKey(module), nodes, directIds); } @@ -186,6 +192,8 @@ private static String projectKey(MavenProject module) { // ---- resolution ---- + // Run inside the module's class realm, as Maven's LifecycleDependencyResolver does: artifact types + // the build extensions contribute are only found from there. private void collectModule( MavenSession session, MavenProject module, diff --git a/src/commands/manifest/scripts/test/maven-compat/.gitignore b/src/commands/manifest/scripts/test/maven-compat/.gitignore index eca432613..8c20122e9 100644 --- a/src/commands/manifest/scripts/test/maven-compat/.gitignore +++ b/src/commands/manifest/scripts/test/maven-compat/.gitignore @@ -19,3 +19,6 @@ descriptor-failure/*/target/ unsolvable-conflict/records.tsv unsolvable-conflict/target/ unsolvable-conflict/localrepo/ +extension-type/localrepo/ +extension-type/records.tsv +extension-type/target/ diff --git a/src/commands/manifest/scripts/test/maven-compat/extension-type/pom.xml b/src/commands/manifest/scripts/test/maven-compat/extension-type/pom.xml new file mode 100644 index 000000000..86e622b6f --- /dev/null +++ b/src/commands/manifest/scripts/test/maven-compat/extension-type/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + demo + extension-type + 1.0 + + file://${maven.multiModuleProjectDirectory}/localrepo + + + + socket-stubs + ${stub.repo.url} + + true + ignore + + + false + + + + + + socket-stubs + ${stub.repo.url} + + true + ignore + + + false + + + + + + + demo.ext + fat + 1.0 + fat + + + + + + demo.ext + types-ext + 1.0 + + + + diff --git a/src/commands/manifest/scripts/test/maven-compat/smoke-test-extension-type.sh b/src/commands/manifest/scripts/test/maven-compat/smoke-test-extension-type.sh new file mode 100755 index 000000000..b941c41f6 --- /dev/null +++ b/src/commands/manifest/scripts/test/maven-compat/smoke-test-extension-type.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# Regression guard: an artifact type a build extension defines must apply as it does in Maven's own +# resolution. Type fat, from the types-ext extension, includes its dependencies and is a jar on disk, +# so demo.ext:inner below demo.ext:fat must not be emitted, and --with-files must fetch fat-1.0.jar. +# +# Usage: smoke-test-extension-type.sh +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +MVN="${1:?usage: smoke-test-extension-type.sh }" +JAR="${2:?usage: smoke-test-extension-type.sh }" +PROJECT="$HERE/extension-type" +RECORDS="$PROJECT/records.tsv" +STUBS="$PROJECT/localrepo" +# shellcheck source=SCRIPTDIR/../compat-cache.sh +. "$HERE/../compat-cache.sh" +M2="$SOCKET_COMPAT_CACHE/m2" + +bash "$HERE/../make-stub-repo.sh" "$STUBS" \ + 'demo.ext:types-ext:1.0' \ + 'demo.ext:fat:1.0+demo.ext:inner:1.0' \ + 'demo.ext:inner:1.0' +# The extension is a components.xml registering Maven's own handler class for type fat. +EXT_DIR="$(mktemp -d)" +trap 'rm -rf "$EXT_DIR"' EXIT +mkdir -p "$EXT_DIR/META-INF/plexus" +cat > "$EXT_DIR/META-INF/plexus/components.xml" <<'XML' + + + + org.apache.maven.artifact.handler.ArtifactHandler + fat + org.apache.maven.artifact.handler.DefaultArtifactHandler + + fat + jar + true + + + + +XML +( cd "$EXT_DIR" && jar cf "$STUBS/demo/ext/types-ext/1.0/types-ext-1.0.jar" META-INF ) +rm -rf "$M2/demo/ext/types-ext" "$M2/demo/ext/fat" "$M2/demo/ext/inner" "$RECORDS" + +echo "+ $("$MVN" -v 2>/dev/null | head -1) (extension type)" +( cd "$PROJECT" && "$MVN" --batch-mode -q \ + "-Dmaven.ext.class.path=$JAR" \ + -Dcoana.task=socket-facts \ + -Dsocket.withFiles=true \ + "-Dmaven.repo.local=$M2" \ + "-Dstub.repo.url=file://$STUBS" \ + "-Dsocket.recordsFile=$RECORDS" \ + validate ) + +python3 - "$RECORDS" <<'PY' +import sys +rows = [l.rstrip('\n').split('\t') for l in open(sys.argv[1]) if l.strip()] +nodes = {r[2] for r in rows if r[0] == 'node'} +files = {r[3] for r in rows if r[0] == 'file' and r[2].startswith('demo.ext:fat:')} +failures = [r[1:] for r in rows if r[0] in ('failure', 'unscannable')] +errors = [] +if not any(n.startswith('demo.ext:fat:') for n in nodes): + errors.append(f"demo.ext:fat missing; nodes={sorted(nodes)}") +if any(n.startswith('demo.ext:inner:') for n in nodes): + errors.append("demo.ext:inner emitted, though type fat includes its dependencies") +if not any(p.endswith('fat-1.0.jar') for p in files): + errors.append(f"fat-1.0.jar not materialized; files={sorted(files)}") +if failures: + errors.append(f"no failures expected; got {failures}") +if errors: + print("FAIL:") + for e in errors: + print(" -", e) + sys.exit(1) +print("PASS (extension type): fat emitted as a jar, inner not resolved below it") +PY diff --git a/src/commands/manifest/scripts/test/run-compat.sh b/src/commands/manifest/scripts/test/run-compat.sh index 3e503016e..e21ded508 100755 --- a/src/commands/manifest/scripts/test/run-compat.sh +++ b/src/commands/manifest/scripts/test/run-compat.sh @@ -118,6 +118,7 @@ run_maven() { bash "$HERE/maven-compat/smoke-test-graph-failure.sh" "$dir/bin/mvn" "$jar" bash "$HERE/maven-compat/smoke-test-descriptor-failure.sh" "$dir/bin/mvn" "$jar" bash "$HERE/maven-compat/smoke-test-unsolvable-conflict.sh" "$dir/bin/mvn" "$jar" + bash "$HERE/maven-compat/smoke-test-extension-type.sh" "$dir/bin/mvn" "$jar" done }