From e70f8f3ccbe89eb3044539e63ea77c9e1e9c598e Mon Sep 17 00:00:00 2001 From: Marian Koncek Date: Aug 22 2022 15:21:16 +0000 Subject: [PATCH 1/3] Move source files into src/ --- diff --git a/config/src/org/fedoraproject/javapackages/validator/config/BytecodeVersionConfigF37.java b/config/src/org/fedoraproject/javapackages/validator/config/BytecodeVersionConfigF37.java deleted file mode 100644 index ec3ba87..0000000 --- a/config/src/org/fedoraproject/javapackages/validator/config/BytecodeVersionConfigF37.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.fedoraproject.javapackages.validator.config; - -import java.util.Set; - -import org.fedoraproject.javadeptools.rpm.RpmInfo; -import org.fedoraproject.javapackages.validator.Common; -import org.fedoraproject.javapackages.validator.config.BytecodeVersionConfig; - -public class BytecodeVersionConfigF37 implements BytecodeVersionConfig { - private Set packagesReqVersion8 = Set.of(new String[] { - "maven", - "apache-commons-cli", - "apache-commons-codec", - "apache-commons-io", - "apache-commons-lang3", - "atinject cdi-api", - "google-guice guava", - "httpcomponents-client", - "httpcomponents-core", - "jakarta-annotations", - "jansi", - "jsr-305", - "maven-resolver", - "maven-shared-utils", - "maven-wagon", - "plexus-cipher", - "plexus-classworlds", - "plexus-containers", - "plexus-interpolation", - "plexus-sec-dispatcher", - "plexus-utils", - "sisu", - "slf4j", - - "ant", - "antlr", - "apache-commons-net", - "bcel", - "bsf", - "jakarta-activation", - "jakarta-mail", - "jakarta-oro", - "jdepend", - "jsch", - "jzlib", - "regexp", - "xalan-j2", - "xerces-j2", - "xml-commons-apis", - "xml-commons-resolver", - }); - - @Override - public VersionRange versionRangeOf(RpmInfo rpm, String jarName, String className) { - if (className.equals("module-info.class")) { - return new VersionRange(-1, Integer.MAX_VALUE); - } - - if (packagesReqVersion8.contains(Common.getPackageName(rpm))) { - return new VersionRange(-1, BytecodeVersionConfig.bytecodeVersionForJava(8)); - } - - return new VersionRange(-1, BytecodeVersionConfig.bytecodeVersionForJava(11)); - } -} diff --git a/config/src/org/fedoraproject/javapackages/validator/config/DuplicateFileConfigF37.java b/config/src/org/fedoraproject/javapackages/validator/config/DuplicateFileConfigF37.java deleted file mode 100644 index df916a8..0000000 --- a/config/src/org/fedoraproject/javapackages/validator/config/DuplicateFileConfigF37.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.fedoraproject.javapackages.validator.config; - -import java.util.Collection; - -import org.fedoraproject.javadeptools.rpm.RpmInfo; -import org.fedoraproject.javapackages.validator.Common; - -public class DuplicateFileConfigF37 implements DuplicateFileConfig { - @Override - public boolean allowedDuplicateFile(String filename, Collection providerRpms) { - if (filename.startsWith("/usr/share/licenses/")) { - return providerRpms.stream().map(Common::getPackageName).distinct().count() == 1; - } - - if (providerRpms.stream().allMatch(rpm -> rpm.getName().startsWith("maven-openjdk"))) { - return true; - } - - if (providerRpms.stream().allMatch(rpm -> rpm.getName().startsWith("maven-local-openjdk"))) { - return true; - } - - return false; - } -} diff --git a/config/src/org/fedoraproject/javapackages/validator/config/ExclusiveArchConfigF37.java b/config/src/org/fedoraproject/javapackages/validator/config/ExclusiveArchConfigF37.java deleted file mode 100644 index 0b4b00f..0000000 --- a/config/src/org/fedoraproject/javapackages/validator/config/ExclusiveArchConfigF37.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.fedoraproject.javapackages.validator.config; - -import java.util.List; - -import org.fedoraproject.javadeptools.rpm.RpmInfo; - -public class ExclusiveArchConfigF37 implements ExclusiveArchConfig { - @Override - public boolean allowedExclusiveArch(RpmInfo rpm, List values) { - boolean buildNoarch = rpm.getBuildArchs().contains("noarch"); - boolean exclusiveNoarch = values.contains("noarch"); - - if (rpm.getName().equals("javapackages-tools")) { - return values.isEmpty(); - } - - return buildNoarch == exclusiveNoarch; - } -} diff --git a/config/src/org/fedoraproject/javapackages/validator/config/FilesConfigF37.java b/config/src/org/fedoraproject/javapackages/validator/config/FilesConfigF37.java deleted file mode 100644 index 671529d..0000000 --- a/config/src/org/fedoraproject/javapackages/validator/config/FilesConfigF37.java +++ /dev/null @@ -1,336 +0,0 @@ -package org.fedoraproject.javapackages.validator.config; - -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.fedoraproject.javadeptools.rpm.RpmInfo; -import org.fedoraproject.javapackages.validator.Common; - -public class FilesConfigF37 implements FilesConfig { - private Map patternsCache = new TreeMap<>(); - - private static String substitute(RpmInfo rpm, String text) { - return text - .replace("${package}", Common.getPackageName(rpm)) - .replace("${rpm.name}", rpm.getName()) - ; - } - - private static class Prefix { - static final String ETC = "/etc/${package}"; - static final String USR_BIN = "/usr/bin/"; - static final String USR_LIB_BUILD_ID = "/usr/lib/.build-id"; - } - - private static Map> nameAliases = new TreeMap<>(); - static { - nameAliases.put("maven-resolver", List.of("aether")); - nameAliases.put("google-guice", List.of("guice")); - nameAliases.put("google-guice-javadoc", List.of("guice-parent")); - nameAliases.put("jakarta-mail", List.of("javamail", "javax.mail")); - } - - private static boolean isAlias(String rpmName, String alias) { - return nameAliases.getOrDefault(rpmName, Collections.emptyList()).stream().anyMatch(a -> alias.equals(a)); - } - - private static Map> prefixes = new TreeMap<>(); - static { - prefixes.put("ant", List.of(Prefix.ETC, Prefix.USR_BIN)); - prefixes.put("antlr", List.of(Prefix.USR_BIN)); - prefixes.put("aqute-bnd", List.of(Prefix.USR_BIN)); - prefixes.put("byaccj", List.of(Prefix.USR_BIN, Prefix.USR_LIB_BUILD_ID)); - prefixes.put("jansi", List.of(Prefix.USR_LIB_BUILD_ID)); - prefixes.put("java_cup", List.of(Prefix.USR_BIN)); - prefixes.put("javapackages-bootstrap", List.of("/usr/share/java/javapackages-bootstrap/", "/usr/lib/rpm/macros.d", "/usr/libexec/javapackages-bootstrap/")); - prefixes.put("javapackages-tools", List.of(Prefix.USR_BIN, "/usr/share/xmvn/conf", "/usr/lib/rpm", "/usr/share/java-utils/", "/usr/lib/eclipse", "/usr/share/eclipse", "/etc/java", "/etc/jvm", "/usr/lib/java", "/usr/lib/jvm", "/etc/ivy", "/etc/ant.d")); - prefixes.put("jflex", List.of(Prefix.USR_BIN)); - prefixes.put("maven", List.of(Prefix.ETC)); - prefixes.put("modello", List.of(Prefix.USR_BIN)); - prefixes.put("objectweb-asm", List.of(Prefix.USR_BIN)); - prefixes.put("xerces-j2", List.of(Prefix.USR_BIN)); - prefixes.put("xml-commons-resolver", List.of(Prefix.USR_BIN)); - prefixes.put("xmvn", List.of(Prefix.USR_BIN)); - } - - private static Map> exceptionalFiles = new TreeMap<>(); - static { - exceptionalFiles.put("aqute-bnd", List.of("/etc/ant.d/aqute-bnd")); - exceptionalFiles.put("maven", List.of("/etc/m2.conf", "/etc/java/maven.conf")); - exceptionalFiles.put("jansi", List.of("/usr/lib/jansi", "/usr/lib/jansi/libjansi.so", "/usr/lib/java/jansi")); - exceptionalFiles.put("javapackages-tools", List.of("/usr/share/java-utils", "/usr/share/xmvn", "/usr/share/ivy-xmls", "/usr/share/java", "/usr/share/javadoc", "/usr/share/jvm", "/usr/share/jvm-common", "/usr/share/maven-metadata", "/usr/share/maven-poms")); - } - - private static boolean namesRelated(String lhs, String rhs) { - int index = 0; - - while (index != lhs.length() && index != rhs.length() && lhs.charAt(index) == rhs.charAt(index)) { - ++index; - } - - if (index == lhs.length() && index == rhs.length()) { - return true; - } - - if (lhs.length() > rhs.length()) { - String temp = lhs; - lhs = rhs; - rhs = temp; - } - - if (index == lhs.length() && rhs.charAt(index) == '-') { - return true; - } - - if (index > 0 && lhs.charAt(index - 1) == '-' && rhs.charAt(index - 1) == '-') { - return true; - } - - return false; - } - - private static boolean startsWithOrEquals(String string, String prefix) { - if (string.startsWith(prefix) && (string.length() == prefix.length() || string.charAt(prefix.length()) == '/')) { - return true; - } - - return false; - } - - private static final Pattern DOC_LICENSE_PATTERN = Pattern.compile("/usr/share/(doc|licenses)/([^/]*)(.*)"); - - private boolean allowedAnyFile(RpmInfo rpm, String filename) { - for (String prefix : prefixes.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) { - if (filename.startsWith(substitute(rpm, prefix))) { - return true; - } - } - - for (String filepath : exceptionalFiles.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) { - if (filename.equals(filepath)) { - return true; - } - } - - Matcher matcher = DOC_LICENSE_PATTERN.matcher(filename); - - if (matcher.matches()) { - if (namesRelated(rpm.getName(), matcher.group(2)) - || isAlias(rpm.getName(), matcher.group(2))) { - if (matcher.group(3).isEmpty()) { - return true; - } - - if (matcher.group(3).charAt(0) == '/') { - if (matcher.group(1).equals("licenses") && - matcher.group(3).codePoints().filter(c -> c == '/').count() != 1) { - return false; - } - - return true; - } - } - } - - return false; - } - - private boolean allowedJavadocFile(RpmInfo rpm, String filename) { - if (allowedAnyFile(rpm, filename)) { - return true; - } - - if (patternsCache.computeIfAbsent(Common.getPackageName(rpm) + "/javadoc", - p -> Pattern.compile("/usr/share/javadoc/" + Common.getPackageName(rpm) + "(:?/.*)?")) - .matcher(filename).matches()) { - return true; - } - - return false; - } - - private boolean allowedDebuginfoFile(RpmInfo rpm, String filename) { - if (allowedAnyFile(rpm, filename)) { - return true; - } - - if (startsWithOrEquals(filename, "/usr/lib/debug")) { - return true; - } - - return false; - } - - private boolean allowedDebugsourceFile(RpmInfo rpm, String filename) { - if (allowedAnyFile(rpm, filename)) { - return true; - } - - if (filename.startsWith("/usr/src/debug/")) { - return true; - } - - return false; - } - - private boolean allowedCLibraryFile(RpmInfo rpm, String filename) { - if (allowedAnyFile(rpm, filename)) { - return true; - } - - if (filename.startsWith("/usr/include/")) { - return true; - } - - if (filename.startsWith("/usr/lib64/lib") && filename.endsWith(".a")) { - return true; - } - - return false; - } - - private boolean allowedPythonLibraryFile(RpmInfo rpm, String filename) { - if (allowedAnyFile(rpm, filename)) { - return true; - } - - if (filename.startsWith("/usr/lib/python")) { - return true; - } - - return false; - } - - private boolean allowedJavaLibraryFile(RpmInfo rpm, String filename) { - if (allowedAnyFile(rpm, filename)) { - return true; - } - - String prefix; - String rpmEntryPrefix; - - if (filename.startsWith(prefix = "/usr/share/java/")) { - rpmEntryPrefix = filename.substring(prefix.length()); - if (filename.endsWith(".jar") && rpmEntryPrefix.codePoints().filter(c -> c == '/').count() <= 1) { - return true; - } - - if (namesRelated(rpm.getName(), rpmEntryPrefix) - || namesRelated(Common.getPackageName(rpm), rpmEntryPrefix) - || isAlias(rpm.getName(), rpmEntryPrefix)) { - return true; - } - } - - if (filename.startsWith(prefix = "/usr/lib/java/") && filename.endsWith(".jar")) { - if (filename.substring(prefix.length()).codePoints().filter(c -> c == '/').count() <= 1) { - return true; - } - } - - if (filename.startsWith(prefix = "/usr/share/maven-poms/")) { - rpmEntryPrefix = filename.substring(prefix.length()); - if (filename.endsWith(".pom") && rpmEntryPrefix.codePoints().filter(c -> c == '/').count() <= 1) { - return true; - } - - if (namesRelated(rpm.getName(), rpmEntryPrefix) - || namesRelated(Common.getPackageName(rpm), rpmEntryPrefix) - || isAlias(rpm.getName(), rpmEntryPrefix)) { - return true; - } - } - - if (filename.startsWith("/usr/share/maven-metadata/") && filename.endsWith(".xml")) { - return true; - } - - return false; - } - - private boolean allowedJavaApplicationFile(RpmInfo rpm, String filename) { - if (allowedJavaLibraryFile(rpm, filename)) { - return true; - } - - if (filename.startsWith("/usr/bin/" + Common.getPackageName(rpm) + "/")) { - return true; - } - - if (filename.startsWith("/usr/share/man/man1/") && filename.endsWith(".1.gz")) { - return true; - } - - if (filename.startsWith("/usr/share/man/man7/") && filename.endsWith(".7.gz")) { - return true; - } - - String prefix; - - if (filename.startsWith(prefix = "/usr/share/bash-completion")) { - if (filename.length() == prefix.length()) { - return true; - } - - if (filename.startsWith(prefix += "/completions")) { - if (filename.length() == prefix.length()) { - return true; - } - - if (filename.charAt(prefix.length()) == '/') { - return true; - } - } - } - - if (filename.startsWith("/usr/share/maven-metadata/") && filename.endsWith(".xml")) { - return true; - } - - if (filename.startsWith(prefix = "/usr/share/")) { - String suffix = filename.substring(prefix.length()); - if (suffix.length() > 0) { - int index = suffix.indexOf('/'); - if (index == -1) { - index = suffix.length(); - } - if (namesRelated(suffix.substring(0, index), rpm.getName())) { - return true; - } - } - } - - return false; - } - - @Override - public boolean allowedFile(RpmInfo rpm, Path path) { - if (rpm.isSourcePackage()) { - // TODO - return true; - } - - // TODO - String filename = path.toString(); - - if (rpm.getName().equals(Common.getPackageName(rpm) + "-javadoc") || rpm.getName().equals(Common.getPackageName(rpm) + "-javadocs")) { - return allowedJavadocFile(rpm, filename); - } else if (rpm.getName().equals(Common.getPackageName(rpm) + "-debuginfo")) { - return allowedDebuginfoFile(rpm, filename); - } else if (rpm.getName().equals(Common.getPackageName(rpm) + "-debugsource")) { - return allowedDebugsourceFile(rpm, filename); - } else if (rpm.getName().startsWith("python3-javapackages")) { - return allowedPythonLibraryFile(rpm, filename); - } else if (rpm.getName().startsWith("antlr-C++")) { - return allowedCLibraryFile(rpm, filename); - } else { - // TODO differentiate Java applications ad libraries - return allowedJavaApplicationFile(rpm, filename); - } - } -} diff --git a/config/src/org/fedoraproject/javapackages/validator/config/RpmFilesizeConfigF37.java b/config/src/org/fedoraproject/javapackages/validator/config/RpmFilesizeConfigF37.java deleted file mode 100644 index 89be977..0000000 --- a/config/src/org/fedoraproject/javapackages/validator/config/RpmFilesizeConfigF37.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.fedoraproject.javapackages.validator.config; - -import org.fedoraproject.javadeptools.rpm.RpmInfo; -import org.fedoraproject.javapackages.validator.Common; - -public class RpmFilesizeConfigF37 implements RpmFilesizeConfig { - @Override - public boolean allowedFilesize(RpmInfo rpm, long sizeBytes) { - if (rpm.isSourcePackage()) { - return sizeBytes <= 1_000_000_000; - } - - if (Common.getPackageName(rpm).equals("javapackages-bootstrap")) { - return sizeBytes <= 40_000_000; - } - - if (rpm.getName().startsWith(Common.getPackageName(rpm) + "-javadoc-")) { - return sizeBytes <= 4_000_000; - } - - if (rpm.getName().endsWith("~bootstrap.noarch.rpm")) { - if (rpm.getName().startsWith("maven-lib-") || rpm.getName().startsWith("xmvn-minimal-")) { - return sizeBytes <= 10_000_000; - } - } - - return sizeBytes <= 3_500_000; - } -} diff --git a/config/src/org/fedoraproject/javapackages/validator/config/SymlinkConfigF37.java b/config/src/org/fedoraproject/javapackages/validator/config/SymlinkConfigF37.java deleted file mode 100644 index 29d0309..0000000 --- a/config/src/org/fedoraproject/javapackages/validator/config/SymlinkConfigF37.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.fedoraproject.javapackages.validator.config; - -import java.nio.file.Paths; - -public class SymlinkConfigF37 extends SymlinkConfig.Envroot { - public SymlinkConfigF37() { - super(Paths.get("/mnt/envroot")); - } -} diff --git a/src/BytecodeVersionConfigJP.java b/src/BytecodeVersionConfigJP.java new file mode 100644 index 0000000..63ea16f --- /dev/null +++ b/src/BytecodeVersionConfigJP.java @@ -0,0 +1,65 @@ +package org.fedoraproject.javapackages.validator.config; + +import java.util.Set; + +import org.fedoraproject.javadeptools.rpm.RpmInfo; +import org.fedoraproject.javapackages.validator.Common; +import org.fedoraproject.javapackages.validator.config.BytecodeVersionConfig; + +public class BytecodeVersionConfigJP implements BytecodeVersionConfig { + private Set packagesReqVersion8 = Set.of(new String[] { + "maven", + "apache-commons-cli", + "apache-commons-codec", + "apache-commons-io", + "apache-commons-lang3", + "atinject cdi-api", + "google-guice guava", + "httpcomponents-client", + "httpcomponents-core", + "jakarta-annotations", + "jansi", + "jsr-305", + "maven-resolver", + "maven-shared-utils", + "maven-wagon", + "plexus-cipher", + "plexus-classworlds", + "plexus-containers", + "plexus-interpolation", + "plexus-sec-dispatcher", + "plexus-utils", + "sisu", + "slf4j", + + "ant", + "antlr", + "apache-commons-net", + "bcel", + "bsf", + "jakarta-activation", + "jakarta-mail", + "jakarta-oro", + "jdepend", + "jsch", + "jzlib", + "regexp", + "xalan-j2", + "xerces-j2", + "xml-commons-apis", + "xml-commons-resolver", + }); + + @Override + public VersionRange versionRangeOf(RpmInfo rpm, String jarName, String className) { + if (className.equals("module-info.class")) { + return new VersionRange(-1, Integer.MAX_VALUE); + } + + if (packagesReqVersion8.contains(Common.getPackageName(rpm))) { + return new VersionRange(-1, BytecodeVersionConfig.bytecodeVersionForJava(8)); + } + + return new VersionRange(-1, BytecodeVersionConfig.bytecodeVersionForJava(11)); + } +} diff --git a/src/DuplicateFileConfigJP.java b/src/DuplicateFileConfigJP.java new file mode 100644 index 0000000..8cb4117 --- /dev/null +++ b/src/DuplicateFileConfigJP.java @@ -0,0 +1,25 @@ +package org.fedoraproject.javapackages.validator.config; + +import java.util.Collection; + +import org.fedoraproject.javadeptools.rpm.RpmInfo; +import org.fedoraproject.javapackages.validator.Common; + +public class DuplicateFileConfigJP implements DuplicateFileConfig { + @Override + public boolean allowedDuplicateFile(String filename, Collection providerRpms) { + if (filename.startsWith("/usr/share/licenses/")) { + return providerRpms.stream().map(Common::getPackageName).distinct().count() == 1; + } + + if (providerRpms.stream().allMatch(rpm -> rpm.getName().startsWith("maven-openjdk"))) { + return true; + } + + if (providerRpms.stream().allMatch(rpm -> rpm.getName().startsWith("maven-local-openjdk"))) { + return true; + } + + return false; + } +} diff --git a/src/FilesConfigJP.java b/src/FilesConfigJP.java new file mode 100644 index 0000000..b671da1 --- /dev/null +++ b/src/FilesConfigJP.java @@ -0,0 +1,336 @@ +package org.fedoraproject.javapackages.validator.config; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.fedoraproject.javadeptools.rpm.RpmInfo; +import org.fedoraproject.javapackages.validator.Common; + +public class FilesConfigJP implements FilesConfig { + private Map patternsCache = new TreeMap<>(); + + private static String substitute(RpmInfo rpm, String text) { + return text + .replace("${package}", Common.getPackageName(rpm)) + .replace("${rpm.name}", rpm.getName()) + ; + } + + private static class Prefix { + static final String ETC = "/etc/${package}"; + static final String USR_BIN = "/usr/bin/"; + static final String USR_LIB_BUILD_ID = "/usr/lib/.build-id"; + } + + private static Map> nameAliases = new TreeMap<>(); + static { + nameAliases.put("maven-resolver", List.of("aether")); + nameAliases.put("google-guice", List.of("guice")); + nameAliases.put("google-guice-javadoc", List.of("guice-parent")); + nameAliases.put("jakarta-mail", List.of("javamail", "javax.mail")); + } + + private static boolean isAlias(String rpmName, String alias) { + return nameAliases.getOrDefault(rpmName, Collections.emptyList()).stream().anyMatch(a -> alias.equals(a)); + } + + private static Map> prefixes = new TreeMap<>(); + static { + prefixes.put("ant", List.of(Prefix.ETC, Prefix.USR_BIN)); + prefixes.put("antlr", List.of(Prefix.USR_BIN)); + prefixes.put("aqute-bnd", List.of(Prefix.USR_BIN)); + prefixes.put("byaccj", List.of(Prefix.USR_BIN, Prefix.USR_LIB_BUILD_ID)); + prefixes.put("jansi", List.of(Prefix.USR_LIB_BUILD_ID)); + prefixes.put("java_cup", List.of(Prefix.USR_BIN)); + prefixes.put("javapackages-bootstrap", List.of("/usr/share/java/javapackages-bootstrap/", "/usr/lib/rpm/macros.d", "/usr/libexec/javapackages-bootstrap/")); + prefixes.put("javapackages-tools", List.of(Prefix.USR_BIN, "/usr/share/xmvn/conf", "/usr/lib/rpm", "/usr/share/java-utils/", "/usr/lib/eclipse", "/usr/share/eclipse", "/etc/java", "/etc/jvm", "/usr/lib/java", "/usr/lib/jvm", "/etc/ivy", "/etc/ant.d")); + prefixes.put("jflex", List.of(Prefix.USR_BIN)); + prefixes.put("maven", List.of(Prefix.ETC)); + prefixes.put("modello", List.of(Prefix.USR_BIN)); + prefixes.put("objectweb-asm", List.of(Prefix.USR_BIN)); + prefixes.put("xerces-j2", List.of(Prefix.USR_BIN)); + prefixes.put("xml-commons-resolver", List.of(Prefix.USR_BIN)); + prefixes.put("xmvn", List.of(Prefix.USR_BIN)); + } + + private static Map> exceptionalFiles = new TreeMap<>(); + static { + exceptionalFiles.put("aqute-bnd", List.of("/etc/ant.d/aqute-bnd")); + exceptionalFiles.put("maven", List.of("/etc/m2.conf", "/etc/java/maven.conf")); + exceptionalFiles.put("jansi", List.of("/usr/lib/jansi", "/usr/lib/jansi/libjansi.so", "/usr/lib/java/jansi")); + exceptionalFiles.put("javapackages-tools", List.of("/usr/share/java-utils", "/usr/share/xmvn", "/usr/share/ivy-xmls", "/usr/share/java", "/usr/share/javadoc", "/usr/share/jvm", "/usr/share/jvm-common", "/usr/share/maven-metadata", "/usr/share/maven-poms")); + } + + private static boolean namesRelated(String lhs, String rhs) { + int index = 0; + + while (index != lhs.length() && index != rhs.length() && lhs.charAt(index) == rhs.charAt(index)) { + ++index; + } + + if (index == lhs.length() && index == rhs.length()) { + return true; + } + + if (lhs.length() > rhs.length()) { + String temp = lhs; + lhs = rhs; + rhs = temp; + } + + if (index == lhs.length() && rhs.charAt(index) == '-') { + return true; + } + + if (index > 0 && lhs.charAt(index - 1) == '-' && rhs.charAt(index - 1) == '-') { + return true; + } + + return false; + } + + private static boolean startsWithOrEquals(String string, String prefix) { + if (string.startsWith(prefix) && (string.length() == prefix.length() || string.charAt(prefix.length()) == '/')) { + return true; + } + + return false; + } + + private static final Pattern DOC_LICENSE_PATTERN = Pattern.compile("/usr/share/(doc|licenses)/([^/]*)(.*)"); + + private boolean allowedAnyFile(RpmInfo rpm, String filename) { + for (String prefix : prefixes.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) { + if (filename.startsWith(substitute(rpm, prefix))) { + return true; + } + } + + for (String filepath : exceptionalFiles.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) { + if (filename.equals(filepath)) { + return true; + } + } + + Matcher matcher = DOC_LICENSE_PATTERN.matcher(filename); + + if (matcher.matches()) { + if (namesRelated(rpm.getName(), matcher.group(2)) + || isAlias(rpm.getName(), matcher.group(2))) { + if (matcher.group(3).isEmpty()) { + return true; + } + + if (matcher.group(3).charAt(0) == '/') { + if (matcher.group(1).equals("licenses") && + matcher.group(3).codePoints().filter(c -> c == '/').count() != 1) { + return false; + } + + return true; + } + } + } + + return false; + } + + private boolean allowedJavadocFile(RpmInfo rpm, String filename) { + if (allowedAnyFile(rpm, filename)) { + return true; + } + + if (patternsCache.computeIfAbsent(Common.getPackageName(rpm) + "/javadoc", + p -> Pattern.compile("/usr/share/javadoc/" + Common.getPackageName(rpm) + "(:?/.*)?")) + .matcher(filename).matches()) { + return true; + } + + return false; + } + + private boolean allowedDebuginfoFile(RpmInfo rpm, String filename) { + if (allowedAnyFile(rpm, filename)) { + return true; + } + + if (startsWithOrEquals(filename, "/usr/lib/debug")) { + return true; + } + + return false; + } + + private boolean allowedDebugsourceFile(RpmInfo rpm, String filename) { + if (allowedAnyFile(rpm, filename)) { + return true; + } + + if (filename.startsWith("/usr/src/debug/")) { + return true; + } + + return false; + } + + private boolean allowedCLibraryFile(RpmInfo rpm, String filename) { + if (allowedAnyFile(rpm, filename)) { + return true; + } + + if (filename.startsWith("/usr/include/")) { + return true; + } + + if (filename.startsWith("/usr/lib64/lib") && filename.endsWith(".a")) { + return true; + } + + return false; + } + + private boolean allowedPythonLibraryFile(RpmInfo rpm, String filename) { + if (allowedAnyFile(rpm, filename)) { + return true; + } + + if (filename.startsWith("/usr/lib/python")) { + return true; + } + + return false; + } + + private boolean allowedJavaLibraryFile(RpmInfo rpm, String filename) { + if (allowedAnyFile(rpm, filename)) { + return true; + } + + String prefix; + String rpmEntryPrefix; + + if (filename.startsWith(prefix = "/usr/share/java/")) { + rpmEntryPrefix = filename.substring(prefix.length()); + if (filename.endsWith(".jar") && rpmEntryPrefix.codePoints().filter(c -> c == '/').count() <= 1) { + return true; + } + + if (namesRelated(rpm.getName(), rpmEntryPrefix) + || namesRelated(Common.getPackageName(rpm), rpmEntryPrefix) + || isAlias(rpm.getName(), rpmEntryPrefix)) { + return true; + } + } + + if (filename.startsWith(prefix = "/usr/lib/java/") && filename.endsWith(".jar")) { + if (filename.substring(prefix.length()).codePoints().filter(c -> c == '/').count() <= 1) { + return true; + } + } + + if (filename.startsWith(prefix = "/usr/share/maven-poms/")) { + rpmEntryPrefix = filename.substring(prefix.length()); + if (filename.endsWith(".pom") && rpmEntryPrefix.codePoints().filter(c -> c == '/').count() <= 1) { + return true; + } + + if (namesRelated(rpm.getName(), rpmEntryPrefix) + || namesRelated(Common.getPackageName(rpm), rpmEntryPrefix) + || isAlias(rpm.getName(), rpmEntryPrefix)) { + return true; + } + } + + if (filename.startsWith("/usr/share/maven-metadata/") && filename.endsWith(".xml")) { + return true; + } + + return false; + } + + private boolean allowedJavaApplicationFile(RpmInfo rpm, String filename) { + if (allowedJavaLibraryFile(rpm, filename)) { + return true; + } + + if (filename.startsWith("/usr/bin/" + Common.getPackageName(rpm) + "/")) { + return true; + } + + if (filename.startsWith("/usr/share/man/man1/") && filename.endsWith(".1.gz")) { + return true; + } + + if (filename.startsWith("/usr/share/man/man7/") && filename.endsWith(".7.gz")) { + return true; + } + + String prefix; + + if (filename.startsWith(prefix = "/usr/share/bash-completion")) { + if (filename.length() == prefix.length()) { + return true; + } + + if (filename.startsWith(prefix += "/completions")) { + if (filename.length() == prefix.length()) { + return true; + } + + if (filename.charAt(prefix.length()) == '/') { + return true; + } + } + } + + if (filename.startsWith("/usr/share/maven-metadata/") && filename.endsWith(".xml")) { + return true; + } + + if (filename.startsWith(prefix = "/usr/share/")) { + String suffix = filename.substring(prefix.length()); + if (suffix.length() > 0) { + int index = suffix.indexOf('/'); + if (index == -1) { + index = suffix.length(); + } + if (namesRelated(suffix.substring(0, index), rpm.getName())) { + return true; + } + } + } + + return false; + } + + @Override + public boolean allowedFile(RpmInfo rpm, Path path) { + if (rpm.isSourcePackage()) { + // TODO + return true; + } + + // TODO + String filename = path.toString(); + + if (rpm.getName().equals(Common.getPackageName(rpm) + "-javadoc") || rpm.getName().equals(Common.getPackageName(rpm) + "-javadocs")) { + return allowedJavadocFile(rpm, filename); + } else if (rpm.getName().equals(Common.getPackageName(rpm) + "-debuginfo")) { + return allowedDebuginfoFile(rpm, filename); + } else if (rpm.getName().equals(Common.getPackageName(rpm) + "-debugsource")) { + return allowedDebugsourceFile(rpm, filename); + } else if (rpm.getName().startsWith("python3-javapackages")) { + return allowedPythonLibraryFile(rpm, filename); + } else if (rpm.getName().startsWith("antlr-C++")) { + return allowedCLibraryFile(rpm, filename); + } else { + // TODO differentiate Java applications ad libraries + return allowedJavaApplicationFile(rpm, filename); + } + } +} diff --git a/src/RpmFilesizeConfigJP.java b/src/RpmFilesizeConfigJP.java new file mode 100644 index 0000000..47f2754 --- /dev/null +++ b/src/RpmFilesizeConfigJP.java @@ -0,0 +1,29 @@ +package org.fedoraproject.javapackages.validator.config; + +import org.fedoraproject.javadeptools.rpm.RpmInfo; +import org.fedoraproject.javapackages.validator.Common; + +public class RpmFilesizeConfigJP implements RpmFilesizeConfig { + @Override + public boolean allowedFilesize(RpmInfo rpm, long sizeBytes) { + if (rpm.isSourcePackage()) { + return sizeBytes <= 1_000_000_000; + } + + if (Common.getPackageName(rpm).equals("javapackages-bootstrap")) { + return sizeBytes <= 40_000_000; + } + + if (rpm.getName().startsWith(Common.getPackageName(rpm) + "-javadoc-")) { + return sizeBytes <= 4_000_000; + } + + if (rpm.getName().endsWith("~bootstrap.noarch.rpm")) { + if (rpm.getName().startsWith("maven-lib-") || rpm.getName().startsWith("xmvn-minimal-")) { + return sizeBytes <= 10_000_000; + } + } + + return sizeBytes <= 3_500_000; + } +} diff --git a/src/SymlinkConfigJP.java b/src/SymlinkConfigJP.java new file mode 100644 index 0000000..135abf9 --- /dev/null +++ b/src/SymlinkConfigJP.java @@ -0,0 +1,9 @@ +package org.fedoraproject.javapackages.validator.config; + +import java.nio.file.Paths; + +public class SymlinkConfigJP extends SymlinkConfig.Envroot { + public SymlinkConfigJP() { + super(Paths.get("/mnt/envroot")); + } +} From 6aeeda8fe89e26b5554509649358a260bb3f9b75 Mon Sep 17 00:00:00 2001 From: Marian Koncek Date: Aug 22 2022 15:21:33 +0000 Subject: [PATCH 2/3] Port to new JPV --- diff --git a/README.md b/README.md index cad3f9f..a0482e2 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ tool `javapackages-validator` and to store configuration files for that tool. ## Contents -* **`config/`** -- Configuration files, described later. -* **`test_scripts/`** -- Shell scripts to be executed. +* **`src/`** -- Configuration `.java` files, described later. +* **`jp_validator.sh`** -- The script which calls the validator tool. * **`tests.fmf`** -- The main `.fmf` file containing metadata for all tests. ## How it works @@ -16,25 +16,31 @@ to specify the path to RPMs. This allows local test execution. The test analyzes the contents of `.rpm` files. The framework used by Fedora provides a standard location `/var/share/test-artifacts` which contains all the -RPMs of the package that is being tested. It is used in `common.sh`. +RPMs of the package that is being tested. -Tests, which require `javapckages-validator` obtain its image from `quay.io` and -execute it using `podman`. This is done in `jp_validator.sh`. +Unless overriden, tests obtain the image `javapckages-validator` from `quay.io` +and execute it using `podman`. This is done in `jp_validator.sh`. ## Configuration The behaviour of the tests is configured in 3 places: -1. The actual [source code](https://github.com/fedora-java/javapackages-validator/tree/rewrite). +1. The actual [source code](https://github.com/fedora-java/javapackages-validator/tree/master). We strive to keep it generic. 2. The `.fmf` configuration files used in each package repository. We strive to keep them as small as possible. -3. Most of the configuration should be done in this repository in the **config** +3. Most of the configuration should be done in this repository in the **src/** directory. Custom test configuration is handled by using standard Java interfaces. The -tests refer to interfaces and the actual implementations are compiled by the -validator. Implementation is then obtained using reflection by constructing +tests refer to interfaces and the actual implementations are compiled by +validator. + +Implementation is then obtained using reflection by constructing configuration classes using an empty constructor. Validator detects which -interfaces the compiled classes implement and uses this information to properly -configure checks. +interfaces the compiled classes implement and uses this information to configure +checks. + +It is possible to use multiple configurations for a simple check. In that case, +the check is executed as many times as the number of configuration classes that +resulted from compilation of the config sources. diff --git a/jp_validator.sh b/jp_validator.sh index c48bea6..c200d1c 100755 --- a/jp_validator.sh +++ b/jp_validator.sh @@ -2,14 +2,11 @@ set -eu -mkdir -p "${CONFIG_BIN_DIR}" - # /mnt/envroot required by SymlinkConfig -exec podman run --privileged\ +exec podman run --security-opt='label=disable'\ --mount type=bind,source="${TEST_ARTIFACTS}",target='/mnt/test_artifacts/',readonly\ - --mount type=bind,source="${CONFIG_SRC_DIR}",target='/mnt/config/src',readonly\ - --mount type=bind,source="${CONFIG_BIN_DIR}",target='/mnt/config/bin'\ + --mount type=bind,source='src/',target='/mnt/config/',readonly\ --mount type=bind,source="${ENVROOT}",target='/mnt/envroot',readonly\ "${JP_VALIDATOR_IMAGE}" ${@} '/mnt/test_artifacts/'\ ; diff --git a/src/BytecodeVersionConfigJP.java b/src/BytecodeVersionConfigJP.java index 63ea16f..dfb446c 100644 --- a/src/BytecodeVersionConfigJP.java +++ b/src/BytecodeVersionConfigJP.java @@ -51,15 +51,15 @@ public class BytecodeVersionConfigJP implements BytecodeVersionConfig { }); @Override - public VersionRange versionRangeOf(RpmInfo rpm, String jarName, String className) { + public boolean allowedVersion(RpmInfo rpm, String jarName, String className, int version) { if (className.equals("module-info.class")) { - return new VersionRange(-1, Integer.MAX_VALUE); + return true; } - if (packagesReqVersion8.contains(Common.getPackageName(rpm))) { - return new VersionRange(-1, BytecodeVersionConfig.bytecodeVersionForJava(8)); + if (packagesReqVersion8.contains(rpm.getPackageName())) { + return version <= 44 + 8; } - return new VersionRange(-1, BytecodeVersionConfig.bytecodeVersionForJava(11)); + return version <= 44 + 11; } } diff --git a/src/DuplicateFileConfigJP.java b/src/DuplicateFileConfigJP.java index 8cb4117..2840aaa 100644 --- a/src/DuplicateFileConfigJP.java +++ b/src/DuplicateFileConfigJP.java @@ -1,5 +1,6 @@ package org.fedoraproject.javapackages.validator.config; +import java.nio.file.Path; import java.util.Collection; import org.fedoraproject.javadeptools.rpm.RpmInfo; @@ -7,9 +8,9 @@ import org.fedoraproject.javapackages.validator.Common; public class DuplicateFileConfigJP implements DuplicateFileConfig { @Override - public boolean allowedDuplicateFile(String filename, Collection providerRpms) { - if (filename.startsWith("/usr/share/licenses/")) { - return providerRpms.stream().map(Common::getPackageName).distinct().count() == 1; + public boolean allowedDuplicateFile(Path path, Collection providerRpms) { + if (path.toString().startsWith("/usr/share/licenses/")) { + return providerRpms.stream().map(RpmInfo::getPackageName).distinct().count() == 1; } if (providerRpms.stream().allMatch(rpm -> rpm.getName().startsWith("maven-openjdk"))) { diff --git a/src/FilesConfigJP.java b/src/FilesConfigJP.java index b671da1..3ccbe96 100644 --- a/src/FilesConfigJP.java +++ b/src/FilesConfigJP.java @@ -9,14 +9,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.fedoraproject.javadeptools.rpm.RpmInfo; -import org.fedoraproject.javapackages.validator.Common; public class FilesConfigJP implements FilesConfig { private Map patternsCache = new TreeMap<>(); private static String substitute(RpmInfo rpm, String text) { return text - .replace("${package}", Common.getPackageName(rpm)) + .replace("${package}", rpm.getPackageName()) .replace("${rpm.name}", rpm.getName()) ; } @@ -105,13 +104,13 @@ public class FilesConfigJP implements FilesConfig { private static final Pattern DOC_LICENSE_PATTERN = Pattern.compile("/usr/share/(doc|licenses)/([^/]*)(.*)"); private boolean allowedAnyFile(RpmInfo rpm, String filename) { - for (String prefix : prefixes.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) { + for (String prefix : prefixes.getOrDefault(rpm.getPackageName(), Collections.emptyList())) { if (filename.startsWith(substitute(rpm, prefix))) { return true; } } - for (String filepath : exceptionalFiles.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) { + for (String filepath : exceptionalFiles.getOrDefault(rpm.getPackageName(), Collections.emptyList())) { if (filename.equals(filepath)) { return true; } @@ -145,8 +144,8 @@ public class FilesConfigJP implements FilesConfig { return true; } - if (patternsCache.computeIfAbsent(Common.getPackageName(rpm) + "/javadoc", - p -> Pattern.compile("/usr/share/javadoc/" + Common.getPackageName(rpm) + "(:?/.*)?")) + if (patternsCache.computeIfAbsent(rpm.getPackageName() + "/javadoc", + p -> Pattern.compile("/usr/share/javadoc/" + rpm.getPackageName() + "(:?/.*)?")) .matcher(filename).matches()) { return true; } @@ -221,7 +220,7 @@ public class FilesConfigJP implements FilesConfig { } if (namesRelated(rpm.getName(), rpmEntryPrefix) - || namesRelated(Common.getPackageName(rpm), rpmEntryPrefix) + || namesRelated(rpm.getPackageName(), rpmEntryPrefix) || isAlias(rpm.getName(), rpmEntryPrefix)) { return true; } @@ -240,7 +239,7 @@ public class FilesConfigJP implements FilesConfig { } if (namesRelated(rpm.getName(), rpmEntryPrefix) - || namesRelated(Common.getPackageName(rpm), rpmEntryPrefix) + || namesRelated(rpm.getPackageName(), rpmEntryPrefix) || isAlias(rpm.getName(), rpmEntryPrefix)) { return true; } @@ -258,7 +257,7 @@ public class FilesConfigJP implements FilesConfig { return true; } - if (filename.startsWith("/usr/bin/" + Common.getPackageName(rpm) + "/")) { + if (filename.startsWith("/usr/bin/" + rpm.getPackageName() + "/")) { return true; } @@ -318,11 +317,11 @@ public class FilesConfigJP implements FilesConfig { // TODO String filename = path.toString(); - if (rpm.getName().equals(Common.getPackageName(rpm) + "-javadoc") || rpm.getName().equals(Common.getPackageName(rpm) + "-javadocs")) { + if (rpm.getName().equals(rpm.getPackageName() + "-javadoc") || rpm.getName().equals(rpm.getPackageName() + "-javadocs")) { return allowedJavadocFile(rpm, filename); - } else if (rpm.getName().equals(Common.getPackageName(rpm) + "-debuginfo")) { + } else if (rpm.getName().equals(rpm.getPackageName() + "-debuginfo")) { return allowedDebuginfoFile(rpm, filename); - } else if (rpm.getName().equals(Common.getPackageName(rpm) + "-debugsource")) { + } else if (rpm.getName().equals(rpm.getPackageName() + "-debugsource")) { return allowedDebugsourceFile(rpm, filename); } else if (rpm.getName().startsWith("python3-javapackages")) { return allowedPythonLibraryFile(rpm, filename); diff --git a/src/RpmFilesizeConfigJP.java b/src/RpmFilesizeConfigJP.java index 47f2754..7f471fd 100644 --- a/src/RpmFilesizeConfigJP.java +++ b/src/RpmFilesizeConfigJP.java @@ -10,11 +10,12 @@ public class RpmFilesizeConfigJP implements RpmFilesizeConfig { return sizeBytes <= 1_000_000_000; } - if (Common.getPackageName(rpm).equals("javapackages-bootstrap")) { + if (rpm.getPackageName().equals("javapackages-bootstrap")) { return sizeBytes <= 40_000_000; } - if (rpm.getName().startsWith(Common.getPackageName(rpm) + "-javadoc-")) { + // javadoc rpms + if (rpm.getName().equals(rpm.getPackageName() + "-javadoc")) { return sizeBytes <= 4_000_000; } diff --git a/src/SymlinkConfigJP.java b/src/SymlinkConfigJP.java index 135abf9..52c16c1 100644 --- a/src/SymlinkConfigJP.java +++ b/src/SymlinkConfigJP.java @@ -2,7 +2,7 @@ package org.fedoraproject.javapackages.validator.config; import java.nio.file.Paths; -public class SymlinkConfigJP extends SymlinkConfig.Envroot { +public class SymlinkConfigJP extends SymlinkConfig.EnvrootImpl { public SymlinkConfigJP() { super(Paths.get("/mnt/envroot")); } diff --git a/tests.fmf b/tests.fmf index 141114c..597a1e8 100644 --- a/tests.fmf +++ b/tests.fmf @@ -6,8 +6,6 @@ require: - podman environment: TEST_ARTIFACTS: /var/share/test-artifacts - CONFIG_SRC_DIR: config/src - CONFIG_BIN_DIR: config/bin JP_VALIDATOR_IMAGE: quay.io/mizdebsk/javapackages-validator ENVROOT: / @@ -15,26 +13,26 @@ environment: description: > Check for files inside RPMs. This test checks for dangling symlinks. (configurable) - test: ./jp_validator.sh SymlinkCheck + test: ./jp_validator.sh SymlinkCheck -c /mnt/config/SymlinkConfigJP.java /duplicate_file: description: > Check for files inside RPMs. This test checks multiple RPMs at once and tests for duplicate files. (configurable) - test: ./jp_validator.sh DuplicateFileCheck + test: ./jp_validator.sh DuplicateFileCheck -c /mnt/config/DuplicateFileConfigJP.java /rpm_filesize: description: > Check whether the RPM file has allowed size in bytes. (configurable) - test: ./jp_validator.sh RpmFilesizeCheck + test: ./jp_validator.sh RpmFilesizeCheck -c /mnt/config/RpmFilesizeConfigJP.java /files: description: > Check RPM and test whether it contains allowed / disallowed files inside. (configurable) - test: ./jp_validator.sh FilesCheck + test: ./jp_validator.sh FilesCheck -c /mnt/config/FilesConfigJP.java /attributes: description: > @@ -42,31 +40,31 @@ environment: (configurable) /conflicts: - test: ./jp_validator.sh ConflictsCheck + test: ./jp_validator.sh attribute.ConflictsCheck /enhances: - test: ./jp_validator.sh EnhancesCheck + test: ./jp_validator.sh attribute.EnhancesCheck /obsoletes: - test: ./jp_validator.sh ObsoletesCheck + test: ./jp_validator.sh attribute.ObsoletesCheck /order_with_requires: - test: ./jp_validator.sh OrderWithRequiresCheck + test: ./jp_validator.sh attribute.OrderWithRequiresCheck /provides: - test: ./jp_validator.sh ProvidesCheck + test: ./jp_validator.sh attribute.ProvidesCheck /recommends: - test: ./jp_validator.sh RecommendsCheck + test: ./jp_validator.sh attribute.RecommendsCheck /requires: - test: ./jp_validator.sh RequiresCheck + test: ./jp_validator.sh attribute.RequiresCheck /suggests: - test: ./jp_validator.sh SuggestsCheck + test: ./jp_validator.sh attribute.SuggestsCheck /supplements: - test: ./jp_validator.sh SupplementsCheck + test: ./jp_validator.sh attribute.SupplementsCheck /java_specific: description: > @@ -77,16 +75,15 @@ environment: Check each .class file present inside each .jar archive inside the RPM and test whether its bytecode version is in valid range. (configurable) - test: ./jp_validator.sh BytecodeVersionCheck + test: ./jp_validator.sh BytecodeVersionCheck -c /mnt/config/BytecodeVersionConfigJP.java /javadoc_noarch: description: > Check whether javadoc packages have architecture noarch test: ./jp_validator.sh JavadocNoarchCheck - /exclusive_arch: + /java_exclusive_arch: description: > Check whether java packages have the ExclusiveArch field set correctly according to this change https://fedoraproject.org/wiki/Changes/Drop_i686_JDKs - (configurable) - test: ./jp_validator.sh ExclusiveArchCheck + test: ./jp_validator.sh JavaExclusiveArchCheck From 17acc96ee933e080640f244918bd12e74b92aae2 Mon Sep 17 00:00:00 2001 From: Marian Koncek Date: Aug 22 2022 15:21:34 +0000 Subject: [PATCH 3/3] Add --rm flag to podman invocation --- diff --git a/jp_validator.sh b/jp_validator.sh index c200d1c..b529965 100755 --- a/jp_validator.sh +++ b/jp_validator.sh @@ -4,7 +4,7 @@ set -eu # /mnt/envroot required by SymlinkConfig -exec podman run --security-opt='label=disable'\ +exec podman run --rm --security-opt='label=disable'\ --mount type=bind,source="${TEST_ARTIFACTS}",target='/mnt/test_artifacts/',readonly\ --mount type=bind,source='src/',target='/mnt/config/',readonly\ --mount type=bind,source="${ENVROOT}",target='/mnt/envroot',readonly\