mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-18 14:34:05 +00:00
Fixed Iris artifact builds
- Loader jars exclude Bukkit dependency bootstrap classes - Artifact verification rejects bootstrap references and executable payloads - Verifier tests cover nested jars and bundled compression libraries - Local VolmLib native setup finishes before Iris native setup
This commit is contained in:
@@ -313,6 +313,8 @@ tasks.named('shadowJar', ShadowJar).configure {
|
||||
// The Bukkit platform binding cannot load without org.bukkit on the classpath, which no mod
|
||||
// loader has. Shipping it only adds dead classes that reference a missing package.
|
||||
exclude('art/arcane/iris/platform/bukkit/**')
|
||||
exclude('art/arcane/iris/platform/bootstrap/SlimJar*.class')
|
||||
exclude('art/arcane/iris/platform/bootstrap/NativeRuntimeLibraries*.class')
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
filesMatching('META-INF/services/**') { FileCopyDetails entry ->
|
||||
entry.duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
|
||||
@@ -305,6 +305,8 @@ tasks.named('shadowJar', ShadowJar).configure {
|
||||
// The Bukkit platform binding cannot load without org.bukkit on the classpath, which no mod
|
||||
// loader has. Shipping it only adds dead classes that reference a missing package.
|
||||
exclude('art/arcane/iris/platform/bukkit/**')
|
||||
exclude('art/arcane/iris/platform/bootstrap/SlimJar*.class')
|
||||
exclude('art/arcane/iris/platform/bootstrap/NativeRuntimeLibraries*.class')
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
filesMatching('META-INF/services/**') { FileCopyDetails entry ->
|
||||
entry.duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
|
||||
@@ -302,6 +302,8 @@ tasks.named('shadowJar', ShadowJar).configure {
|
||||
// The Bukkit platform binding cannot load without org.bukkit on the classpath, which no mod
|
||||
// loader has. Shipping it only adds dead classes that reference a missing package.
|
||||
exclude('art/arcane/iris/platform/bukkit/**')
|
||||
exclude('art/arcane/iris/platform/bootstrap/SlimJar*.class')
|
||||
exclude('art/arcane/iris/platform/bootstrap/NativeRuntimeLibraries*.class')
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
filesMatching('META-INF/services/**') { FileCopyDetails entry ->
|
||||
entry.duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.gradle.api.file.DeleteSpec
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.initialization.IncludedBuild
|
||||
import org.gradle.api.tasks.Copy
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
@@ -78,6 +79,9 @@ String forgeVersion = providers.gradleProperty('forgeVersion').getOrElse('26.3-6
|
||||
String neoForgeVersion = providers.gradleProperty('neoForgeVersion').getOrElse('26.3.0.33-beta')
|
||||
String volmLibShared = 'com.github.VolmitSoftware.VolmLib:volmlib-shared:master-SNAPSHOT'
|
||||
File localVolmLibCheckout = (File) gradle.extensions.extraProperties.get('volmLibDirectory')
|
||||
IncludedBuild localVolmLibBuild = localVolmLibCheckout == null ? null : gradle.includedBuilds.find { IncludedBuild includedBuild ->
|
||||
includedBuild.projectDir.canonicalFile == localVolmLibCheckout.canonicalFile
|
||||
}
|
||||
Map<String, String> volmLibStamp = (Map<String, String>) gradle.extensions.extraProperties.get('volmLibStamp')
|
||||
Closure<String> loaderDisplayVersion = { String loaderVersion ->
|
||||
String coordinatePrefix = "${minecraftVersion}-"
|
||||
@@ -136,6 +140,14 @@ nmsBindings.each { String key ->
|
||||
project(":adapters:bukkit:nms:${key}") {
|
||||
apply plugin: JavaPlugin
|
||||
apply plugin: PaperweightUser
|
||||
if (localVolmLibBuild != null) {
|
||||
tasks.named('paperweightUserdevSetup').configure {
|
||||
dependsOn(localVolmLibBuild.task(":native:${key}:paperweightUserdevSetup"))
|
||||
if (key == 'v26_2_R1') {
|
||||
dependsOn(localVolmLibBuild.task(':native-common:paperweightUserdevSetup'))
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeDevelopmentTargets.Target nativeTarget = NativeDevelopmentTargets.require(key)
|
||||
dependencies.extensions.getByType(PaperweightUserDependenciesExtension)
|
||||
.paperDevBundle(nativeTarget.paperBundle())
|
||||
|
||||
@@ -24,6 +24,10 @@ public final class ModdedArtifactVerifier {
|
||||
"net/jpountz/lz4/LZ4BlockOutputStream"
|
||||
);
|
||||
private static final String INTERNAL_OSHI_REFERENCE = "oshi/SystemInfo";
|
||||
private static final List<String> BUKKIT_DEPENDENCY_BOOTSTRAP_CLASSES = List.of(
|
||||
"art/arcane/iris/platform/bootstrap/SlimJar",
|
||||
"art/arcane/iris/platform/bootstrap/NativeRuntimeLibraries"
|
||||
);
|
||||
private static final List<String> BUNDLED_RUNTIME_PREFIXES = List.of(
|
||||
"net/jpountz/",
|
||||
"oshi/",
|
||||
@@ -97,6 +101,8 @@ public final class ModdedArtifactVerifier {
|
||||
Set<String> asmEntries = new LinkedHashSet<>();
|
||||
Set<String> shippedNestedJars = new LinkedHashSet<>();
|
||||
Set<String> bukkitSupertypeClasses = new LinkedHashSet<>();
|
||||
Set<String> dependencyBootstrapViolations = new LinkedHashSet<>();
|
||||
Set<String> executableEntries = new LinkedHashSet<>();
|
||||
boolean oshiReference = false;
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
@@ -106,6 +112,9 @@ public final class ModdedArtifactVerifier {
|
||||
}
|
||||
|
||||
String name = entry.getName();
|
||||
if (name.toLowerCase(Locale.ROOT).endsWith(".exe")) {
|
||||
executableEntries.add(name);
|
||||
}
|
||||
if (startsWithAny(name, BUNDLED_RUNTIME_PREFIXES)) {
|
||||
bundledRuntimeEntries.add(name);
|
||||
}
|
||||
@@ -116,7 +125,7 @@ public final class ModdedArtifactVerifier {
|
||||
shippedNestedJars.add(name);
|
||||
}
|
||||
if (isNestedJar(name)) {
|
||||
inspectNestedJar(jar, entry, bundledRuntimeEntries, privateReferenceClasses);
|
||||
inspectNestedJar(jar, entry, bundledRuntimeEntries, privateReferenceClasses, dependencyBootstrapViolations, executableEntries);
|
||||
}
|
||||
if (!name.endsWith(".class")) {
|
||||
continue;
|
||||
@@ -124,6 +133,7 @@ public final class ModdedArtifactVerifier {
|
||||
|
||||
byte[] classFile = readEntryBytes(jar, entry);
|
||||
String bytecode = new String(classFile, StandardCharsets.ISO_8859_1);
|
||||
inspectDependencyBootstrap(name, name, bytecode, dependencyBootstrapViolations);
|
||||
if (containsAny(bytecode, PRIVATE_REFERENCE_PREFIXES)) {
|
||||
privateReferenceClasses.add(name);
|
||||
}
|
||||
@@ -145,6 +155,13 @@ public final class ModdedArtifactVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
if (!executableEntries.isEmpty()) {
|
||||
throw new GradleException(artifact.getName() + " contains executable .exe entries: " + preview(executableEntries));
|
||||
}
|
||||
if (!dependencyBootstrapViolations.isEmpty()) {
|
||||
throw new GradleException(artifact.getName() + " contains Bukkit dependency bootstrap code: "
|
||||
+ preview(dependencyBootstrapViolations));
|
||||
}
|
||||
if (!bundledRuntimeEntries.isEmpty()) {
|
||||
throw new GradleException(artifact.getName() + " duplicates Minecraft runtime libraries: "
|
||||
+ preview(bundledRuntimeEntries));
|
||||
@@ -364,7 +381,9 @@ public final class ModdedArtifactVerifier {
|
||||
|
||||
private static void inspectNestedJar(JarFile jar, JarEntry nestedEntry,
|
||||
Set<String> bundledRuntimeEntries,
|
||||
Set<String> privateReferenceClasses) throws IOException {
|
||||
Set<String> privateReferenceClasses,
|
||||
Set<String> dependencyBootstrapViolations,
|
||||
Set<String> executableEntries) throws IOException {
|
||||
String nestedName = nestedEntry.getName();
|
||||
if (isNamedRuntimeLibrary(nestedName)) {
|
||||
bundledRuntimeEntries.add(nestedName);
|
||||
@@ -380,11 +399,15 @@ public final class ModdedArtifactVerifier {
|
||||
|
||||
String name = entry.getName();
|
||||
String path = nestedName + "!/" + name;
|
||||
if (name.toLowerCase(Locale.ROOT).endsWith(".exe")) {
|
||||
executableEntries.add(path);
|
||||
}
|
||||
if (startsWithAny(name, BUNDLED_RUNTIME_PREFIXES)) {
|
||||
bundledRuntimeEntries.add(path);
|
||||
}
|
||||
if (name.endsWith(".class")) {
|
||||
String bytecode = new String(nestedJar.readAllBytes(), StandardCharsets.ISO_8859_1);
|
||||
inspectDependencyBootstrap(name, path, bytecode, dependencyBootstrapViolations);
|
||||
if (containsAny(bytecode, PRIVATE_REFERENCE_PREFIXES)) {
|
||||
privateReferenceClasses.add(path);
|
||||
}
|
||||
@@ -393,6 +416,15 @@ public final class ModdedArtifactVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
private static void inspectDependencyBootstrap(String entry, String path, String bytecode, Set<String> violations) {
|
||||
String topLevel = topLevelClass(entry);
|
||||
for (String forbidden : BUKKIT_DEPENDENCY_BOOTSTRAP_CLASSES) {
|
||||
if (topLevel.equals(forbidden) || bytecode.contains(forbidden)) {
|
||||
violations.add(path + " -> " + forbidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNestedJar(String name) {
|
||||
return name.endsWith(".jar")
|
||||
&& (name.startsWith(NESTED_JAR_DIRECTORY) || name.startsWith("META-INF/jarjar/"));
|
||||
|
||||
@@ -4,6 +4,8 @@ import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
@@ -44,6 +46,91 @@ public class ModdedArtifactVerifierTest {
|
||||
ModdedArtifactVerifier.verify(artifact, REQUIRED_ENTRIES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsBukkitDependencyBootstrapClassesAndNestedClasses() throws Exception {
|
||||
for (String internalName : List.of("art/arcane/iris/platform/bootstrap/SlimJar",
|
||||
"art/arcane/iris/platform/bootstrap/SlimJar$BootstrapLogger",
|
||||
"art/arcane/iris/platform/bootstrap/NativeRuntimeLibraries",
|
||||
"art/arcane/iris/platform/bootstrap/NativeRuntimeLibraries$Provider")) {
|
||||
Map<String, byte[]> entries = validEntries();
|
||||
entries.put(internalName + ".class", classExtending(internalName, "java/lang/Object"));
|
||||
GradleException failure = assertThrows(GradleException.class,
|
||||
() -> ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES));
|
||||
assertTrue(failure.getMessage().contains("Bukkit dependency bootstrap code"));
|
||||
assertTrue(failure.getMessage().contains(internalName));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsDanglingBukkitDependencyBootstrapReferences() throws Exception {
|
||||
for (String internalName : List.of("art/arcane/iris/platform/bootstrap/SlimJar",
|
||||
"art/arcane/iris/platform/bootstrap/NativeRuntimeLibraries")) {
|
||||
Map<String, byte[]> entries = validEntries();
|
||||
String caller = "art/arcane/iris/modded/BootstrapCaller";
|
||||
ClassWriter writer = new ClassWriter(0);
|
||||
writer.visit(Opcodes.V21, Opcodes.ACC_PUBLIC, caller, null, "java/lang/Object", null);
|
||||
MethodVisitor method = writer.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||
"dependencyType", "()Ljava/lang/Class;", null, null);
|
||||
method.visitCode();
|
||||
method.visitLdcInsn(Type.getObjectType(internalName));
|
||||
method.visitInsn(Opcodes.ARETURN);
|
||||
method.visitMaxs(1, 0);
|
||||
method.visitEnd();
|
||||
writer.visitEnd();
|
||||
entries.put(caller + ".class", writer.toByteArray());
|
||||
GradleException failure = assertThrows(GradleException.class,
|
||||
() -> ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES));
|
||||
assertTrue(failure.getMessage().contains(caller));
|
||||
assertTrue(failure.getMessage().contains(internalName));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsBukkitDependencyBootstrapInsideJarJar() throws Exception {
|
||||
Map<String, byte[]> entries = validEntries();
|
||||
String internalName = "art/arcane/iris/platform/bootstrap/SlimJar";
|
||||
entries.put("META-INF/jarjar/dependency-support.jar", createNestedArtifact(Map.of(
|
||||
internalName + ".class", classExtending(internalName, "java/lang/Object"))));
|
||||
GradleException failure = assertThrows(GradleException.class,
|
||||
() -> ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES));
|
||||
assertTrue(failure.getMessage().contains("Bukkit dependency bootstrap code"));
|
||||
assertTrue(failure.getMessage().contains("dependency-support.jar!/" + internalName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsExecutableEntriesRegardlessOfCase() throws Exception {
|
||||
for (String executable : List.of("bin/installer.exe", "native/windows/helper.EXE")) {
|
||||
Map<String, byte[]> entries = validEntries();
|
||||
entries.put(executable, new byte[]{1});
|
||||
GradleException failure = assertThrows(GradleException.class,
|
||||
() -> ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES));
|
||||
assertTrue(failure.getMessage().contains("executable .exe entries"));
|
||||
assertTrue(failure.getMessage().contains(executable));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsExecutableInsideJarJar() throws Exception {
|
||||
Map<String, byte[]> entries = validEntries();
|
||||
entries.put("META-INF/jarjar/native-support.jar", createNestedArtifact(Map.of(
|
||||
"native/helper.exe", new byte[]{1})));
|
||||
GradleException failure = assertThrows(GradleException.class,
|
||||
() -> ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES));
|
||||
assertTrue(failure.getMessage().contains("executable .exe entries"));
|
||||
assertTrue(failure.getMessage().contains("native-support.jar!/native/helper.exe"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptsBundledCompressionLibraries() throws Exception {
|
||||
Map<String, byte[]> entries = validEntries();
|
||||
entries.put("native/windows-x86_64/jlibdeflate.dll", new byte[]{1});
|
||||
entries.put("native/linux-x86_64/libjlibdeflate.so", new byte[]{1});
|
||||
entries.put("native/osx-aarch64/libjlibdeflate.dylib", new byte[]{1});
|
||||
entries.put("com/fulcrumgenomics/jlibdeflate/NativeLoader.class",
|
||||
classExtending("com/fulcrumgenomics/jlibdeflate/NativeLoader", "java/lang/Object"));
|
||||
ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsClientLanguagesWithoutPackMetadata() throws Exception {
|
||||
Map<String, byte[]> entries = validEntries();
|
||||
|
||||
Reference in New Issue
Block a user