Compare commits

...
Sign in to create a new pull request.

103 commits

Author SHA1 Message Date
Mikolaj Izdebski
261e44c3fa Add deprecation notice to README.md 2025-03-24 08:47:41 +01:00
Mikolaj Izdebski
0999df51b8 Fix a typo in maven4 package name 2025-02-26 23:24:09 +01:00
Mikolaj Izdebski
26792c770b Increase generic package size limit 2025-02-26 23:09:58 +01:00
Mikolaj Izdebski
13f9485252 Configure files for maven4 2025-02-26 23:06:06 +01:00
Mikolaj Izdebski
d5d139af27 Increase allowed size for javapackages-bootstrap 2025-02-26 20:43:17 +01:00
Mikolaj Izdebski
5db07614a8 Add files whiletists for jline 2025-02-26 20:41:03 +01:00
Marian Koncek
4758ee4fda Allow junit5 to install executables 2025-02-25 10:48:31 +01:00
Mikolaj Izdebski
25bf954aac Allow public domain for plexus-utils4 2025-02-16 18:06:31 +01:00
Mikolaj Izdebski
af194b6641 Skip ExclusiveArch validation for known non-Java packages 2024-12-11 16:31:34 +01:00
Mikolaj Izdebski
75adec844b Use unnamed variables (JEP 456)
See https://openjdk.org/jeps/456
2024-12-11 07:10:11 +01:00
Mikolaj Izdebski
0cd1370868 Skip file check for javapackages-tools and javapackages-bootstrap 2024-12-02 17:57:42 +01:00
Mikolaj Izdebski
745343f757 Update to RUnit version 1.0.0
The Sonatype snapshot repository is no longer needed as RUnit 1.0.0 is
available on Maven Central, but keep it commented out in case we want
to start using RUnit snapshots again.

The list of dependencies was generated with Maven and jq:

    mvn -f ~/.m2/repository/io/kojan/runit-validator/1.0.0/runit-validator-1.0.0.pom \
            dependency:tree -Dscope=runtime -DoutputType=json -DoutputFile=/dev/fd/3 3>&1 1>&2 |
	jq -r 'recurse(.children[]?) | ("  " + .groupId + ":" + .artifactId + ":" + .version + " \\")' |
	sort
2024-11-30 10:26:48 +01:00
Mikolaj Izdebski
50e2e10695 Drop unneeded imports 2024-11-29 09:50:19 +01:00
Mikolaj Izdebski
c9fe403c5e Allow versioned apache-commons JPMS provides 2024-11-29 09:38:17 +01:00
Mikolaj Izdebski
27b31452b9 Use RUnitMatchers for matching apache-commons JPMS provides 2024-11-29 09:24:43 +01:00
Mikolaj Izdebski
1433c52224 Enable apache-commons JPMS provides check 2024-11-29 07:33:03 +01:00
Mikolaj Izdebski
4d05ece41c Use RUnitMatchers for matching bundled provides 2024-11-29 07:28:59 +01:00
Mikolaj Izdebski
5f09737c33 Add check for Conflicts 2024-11-29 07:28:19 +01:00
Mikolaj Izdebski
cfa4787b3b Remove duplitcate checks irrelevant for Fedora 42+ 2024-11-29 07:17:24 +01:00
Mikolaj Izdebski
d633634528 Fix jpackage_script check 2024-11-29 07:07:02 +01:00
Mikolaj Izdebski
ed92ce4e3b Allow duplicate files in ant-openjdk* 2024-11-24 19:22:41 +01:00
Mikolaj Izdebski
b86f2bd711 Add /jpackage_script check 2024-11-23 18:47:02 +00:00
Mikolaj Izdebski
ab6a8c544a Allow new binding files 2024-11-23 09:37:12 +01:00
Mikolaj Izdebski
f3f789d7c8 Remove file whitelists for javapackages-tools 2024-11-23 09:29:59 +01:00
Marian Koncek
f36b1f9ec6 Add ant JDK binding file 2024-10-30 13:38:53 +01:00
Mikolaj Izdebski
dfe9493ee7 Bump max allowed bytecode version to 21 2024-09-27 16:45:44 +02:00
Mikolaj Izdebski
da2f3b64d6 Allow dot in package names 2024-08-28 09:55:29 +02:00
Marian Koncek
15f8f4398a Revert "Run tests only on x86_64"
This reverts commit dd3c24887d.
2024-08-19 16:26:41 +02:00
Mikolaj Izdebski
dd3c24887d Run tests only on x86_64 2024-08-14 16:20:58 +02:00
Mikolaj Izdebski
b0300a3876 Fix a typo in generic flavor factory 2024-08-09 10:25:44 +02:00
Mikolaj Izdebski
abf645f388 Revert "Try enabling colors"
This reverts commit 9268133272.
2024-08-08 17:33:55 +02:00
Mikolaj Izdebski
9268133272 Try enabling colors 2024-08-08 16:00:18 +02:00
Mikolaj Izdebski
569590fe86 Use SAX-PD-2.0 license instead of SAX-PD 2024-08-07 08:52:49 +02:00
Mikolaj Izdebski
b94880fa5f Make use of repeatable annotations 2024-08-02 11:49:35 +02:00
Mikolaj Izdebski
4d53b55041 Port to new RUnit API 2024-08-02 11:23:54 +02:00
Mikolaj Izdebski
e329349409 Override JpmsProvidesValidatorJP test name 2024-08-01 17:41:54 +02:00
Mikolaj Izdebski
ef3b34fa5d Add JpmsProvidesValidatorJP 2024-08-01 17:34:36 +02:00
Mikolaj Izdebski
93d8b3ac06 Remove unused import 2024-08-01 17:28:53 +02:00
Mikolaj Izdebski
4b485ba76d Drop vanilla flavor 2024-08-01 15:37:40 +02:00
Mikolaj Izdebski
4ae5ee753f Add generic flavor 2024-08-01 15:16:58 +02:00
Mikolaj Izdebski
8ed9563d81 Drop runit.fmf 2024-07-31 14:51:29 +02:00
Mikolaj Izdebski
15381c38a6 Integrate runit tests with JP validators 2024-07-31 14:48:01 +02:00
Mikolaj Izdebski
6c83076bdf Switch away from custom runit container image 2024-07-31 14:35:00 +02:00
Mikolaj Izdebski
707483b8b5 Still allow /usr/lib/java/javapackages-bootstrap 2024-07-31 04:14:48 +02:00
Mikolaj Izdebski
36ba3a0a7d Allow /usr/lib/javapackages-bootstrap for javapackages-bootstrap 2024-07-30 20:04:26 +02:00
Mikolaj Izdebski
b5fc0e766e Disapprove CC-BY-2.5 for jsr-305 2024-07-30 12:02:27 +02:00
Mikolaj Izdebski
5e98b7b135 Switch to the new RUnit API 2024-07-30 09:51:46 +02:00
Mikolaj Izdebski
aa925a2124 Approve 0BSD license, used by xz-java 2024-07-29 19:33:53 +02:00
Mikolaj Izdebski
a3f18d49bd Maven is allowed to put files in /usr/bin/ 2024-07-29 17:39:04 +02:00
Mikolaj Izdebski
e1a66d68e8 Only check JARs in javadir and jnidir 2024-07-24 11:00:48 +02:00
Mikolaj Izdebski
26be4efbd6 Remove tests duplicated between BasicCheck and FileCheck 2024-07-24 09:21:47 +02:00
Mikolaj Izdebski
a59d4fec63 Enable runit tests in production 2024-07-24 09:20:59 +02:00
Mikolaj Izdebski
25ec6ea104 Disallow /usr/share/doc/ from javadoc packages
/usr/share/doc/ was used for license files in the past, but since then
all packages should've been migrated to /usr/share/licenses/.
2024-07-24 08:56:21 +02:00
Mikolaj Izdebski
a726712ae6 Split basic check into several checks
There are issues with displaying huge HTML files generated by JPV,
therefore it's better to have a few smaller files instead.
2024-07-24 08:53:28 +02:00
Mikolaj Izdebski
a5d9cbdc3b Provisionally allow CC-BY-2.5 for jsr-305 2024-07-24 08:17:56 +02:00
Mikolaj Izdebski
a95157444d Fix java_cup naming exception 2024-07-24 08:07:32 +02:00
Mikolaj Izdebski
8ccf218367 Make use of RUnit filtering on annotation level 2024-07-23 19:06:20 +02:00
Mikolaj Izdebski
b9e002af45 Improve failure messages of license check 2024-07-23 07:01:37 +02:00
Mikolaj Izdebski
ed298de4a6 Use new RUnit assumptions 2024-07-23 05:34:41 +02:00
Mikolaj Izdebski
2a36967b05 Use hamcrest Matcher in license check 2024-07-23 05:11:09 +02:00
Mikolaj Izdebski
e2fea19c9f Use new RUnit assertions 2024-07-23 05:00:10 +02:00
Mikolaj Izdebski
d212186599 Exclude source packages from modeTest 2024-07-22 13:49:10 +02:00
Mikolaj Izdebski
81e0d8e710 Make use of RpmInfo.getSourceName() 2024-07-18 03:38:11 +02:00
Mikolaj Izdebski
80629ccaac Implement jpv_flavor fmf dimension
Vanilla flavor runs unmodified upstream validator, skipping extra
validators from src/ directory.
2024-07-17 20:14:31 +02:00
Mikolaj Izdebski
b2e1d2ad16 Try to enable file tests
Memory issues should've been fixed with
1f2d90c1fb
2024-07-17 15:09:32 +02:00
Mikolaj Izdebski
2fea375be4 Rework the license check 2024-07-17 10:11:17 +02:00
Mikolaj Izdebski
c950749eaa Implement apache-commons license check 2024-07-17 08:34:07 +02:00
Mikolaj Izdebski
f32125de3f Untabify ApacheCommonsCheck.java sources 2024-07-17 08:33:43 +02:00
Mikolaj Izdebski
145bf154c2 Whitelist SAX-PD license 2024-07-16 10:28:57 +02:00
Mikolaj Izdebski
895145ddab Disable the last remaining FileTest due to OOM 2024-07-16 10:11:26 +02:00
Mikolaj Izdebski
b13dff6a47 Disable runit tests that use too much memory 2024-07-16 09:11:53 +02:00
Mikolaj Izdebski
250f5e78b7 Allowlist licenses ANTLR-PD, BSD-3-Clause-Sun, W3C 2024-07-16 08:56:21 +02:00
Mikolaj Izdebski
11373015d0 Implement more basic checks 2024-07-16 08:53:41 +02:00
Mikolaj Izdebski
1b70956120 Add runit test for SPDX license 2024-07-16 08:37:03 +02:00
Mikolaj Izdebski
4e37f2b106 Exclude antlr-C++ from sane-name test 2024-07-16 07:52:10 +02:00
Mikolaj Izdebski
7a2bd88447 Disable built-in validator factory
Disable the use of upstream DefaultValidatorFactory, so that we have
more control of which validators are executed.
2024-07-11 16:23:21 +02:00
Marian Koncek
9f8f906ef1 Put javapackages test code into a separate shell script 2024-07-10 11:43:21 +02:00
Marian Koncek
14b44cb6ec Unify indentation to use 2 spaces 2024-07-09 15:39:55 +02:00
Marian Koncek
b2c991e859 Add more javapackages test metadata 2024-07-09 15:39:55 +02:00
Marian Koncek
dbcbaa2c0b Revert "Add tmtref"
This reverts commit cbf1b7c021.
2024-07-09 15:39:32 +02:00
Marian Koncek
2dfb4e9dcc Revert "Differentiate generic and Java SST tests"
This reverts commit fa344c07f6.
2024-07-09 15:39:30 +02:00
Marian Koncek
fa344c07f6 Differentiate generic and Java SST tests 2024-06-12 15:05:07 +02:00
Marian Koncek
cbf1b7c021 Add tmtref 2024-06-12 15:05:07 +02:00
Mikolaj Izdebski
989b4038b8 Disable JPMS provides test for now 2023-12-11 16:04:36 +01:00
Mikolaj Izdebski
f1de5523f0 Add test case for apache-commons-* JPMS provides 2023-12-11 15:55:26 +01:00
Mikolaj Izdebski
e6508ea7ee Add basic test based on runit framework
See: https://github.com/mizdebsk/runit
2023-12-06 21:15:12 +01:00
Mikolaj Izdebski
b57074fd52 Move test script one level up in fmf tree 2023-12-06 19:03:01 +01:00
Mikolaj Izdebski
953b91c90c Intoduce JP_VALIDATOR_SOURCE_PATH env variable 2023-12-06 19:00:37 +01:00
Marian Koncek
932e57ff98 Merge branch 'f40' 2023-12-06 11:00:12 +01:00
Marian Koncek
bd21d85bf2 Port to new JPV interface 2023-11-30 11:38:40 +01:00
Marian Koncek
fa83b8fa59 Files: Add /usr/bin files for javacc 2023-11-28 12:46:52 +01:00
Marian Koncek
fea4a270e6 Remove remaining test ending parenthesis 2023-11-01 10:18:24 +01:00
Marian Koncek
afcee6c256 Allow selecting validators via an env var
Port to new JPV
2023-10-31 15:55:55 +01:00
Marian Koncek
3e4d228486 Revert "Remove JP-specific validators"
This reverts commit 3635d041dc.
2023-10-18 13:48:16 +02:00
Marian Koncek
cdd86f5765 Change JP validator image to fedora-java 2023-10-18 13:43:40 +02:00
Marian Koncek
2e4e9c77ef Pass class path only if sources are provided 2023-10-13 12:10:48 +02:00
Marian Koncek
3527a2b904 Use a more complex command 2023-10-13 11:54:35 +02:00
Marian Koncek
a8c564b033 Do not fail on unset path flags 2023-10-13 10:57:42 +02:00
Marian Koncek
2e690c69b1 Conditionally include source path 2023-10-13 10:38:38 +02:00
Marian Koncek
3635d041dc Remove JP-specific validators 2023-10-12 15:23:23 +02:00
Marian Koncek
76b3e99286 Port to JPV 2 2023-10-12 15:11:58 +02:00
Mikolaj Izdebski
7bf8bbb751 Allow Java 17 bytecode in general 2023-03-13 15:47:28 +01:00
Mikolaj Izdebski
e6c7f32026 Whitelist files for xmvn-generator 2023-03-13 15:46:23 +01:00
27 changed files with 848 additions and 328 deletions

View file

@ -1,46 +1,5 @@
# javapackages-validator-tests
# Deprecated
This repository contains files used for testing Fedora Java packages using the
tool `javapackages-validator` and to store configuration files for that tool.
This repository is deprecated.
## Contents
* **`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
The test uses an optional environment variable, `TEST_ARTIFACTS`, which can used
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.
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/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 **src/**
directory.
Custom test configuration is handled by using standard Java interfaces. The
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 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.
Javapackages tests were moved to https://gitlab.com/redhat/centos-stream/tests/javapackages

33
javapackages.sh Executable file
View file

@ -0,0 +1,33 @@
#!/usr/bin/bash
set -eux
tmt_root="${TMT_TREE%/tree}"
test_data="${TMT_TEST_DATA##"${tmt_root}"/}"
# Fails with CI which uses a local image
if echo "${JP_VALIDATOR_IMAGE}" | grep -q '/'; then
podman pull "${JP_VALIDATOR_IMAGE}" || sleep 10
fi
command=(podman run --rm --security-opt='label=disable'
--mount type=bind,source="${TEST_ARTIFACTS}",target='/mnt/test-artifacts/',readonly
--mount type=bind,source="${tmt_root}",target='/mnt/tmt/'
)
[ -n "${JP_VALIDATOR_SOURCE_PATH}" ] && command+=(
--mount type=bind,source="${JP_VALIDATOR_SOURCE_PATH}",target='/mnt/project/src',readonly
)
[ -n "${JP_VALIDATOR_OUTPUT_DIR}" ] && command+=(
--mount type=bind,source="${JP_VALIDATOR_OUTPUT_DIR}",target='/mnt/project/classes'
)
command+=(
--env TMT_TEST_DATA="/mnt/tmt/${test_data}"
--env TMT_TREE="/mnt/tmt/tree"
"${JP_VALIDATOR_IMAGE}" org.fedoraproject.javapackages.validator.MainTmt -x
-f '/mnt/test-artifacts/'
)
[ -n "${JP_VALIDATOR_SOURCE_PATH}" ] && command+=(
-sp '/mnt/project/src' -d '/mnt/project/classes'
)
command+=(${JP_VALIDATOR_ARGS})
exec "${command[@]}"

View file

@ -1,12 +0,0 @@
#!/bin/bash
set -eu
# /mnt/envroot required by SymlinkConfig
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\
"${JP_VALIDATOR_IMAGE}" ${@} '/mnt/test_artifacts/'\
;

31
main.fmf Normal file
View file

@ -0,0 +1,31 @@
summary: Javapackages-validator tests
contact:
- Marian Koncek <mkoncek@redhat.com>
- Mikolaj Izdebski <mizdebsk@redhat.com>
description: |
This test executes a series of tests checking for various aspects of the Java package.
This includes packaging guidelines compliance, package sanity and various regressions.
tier: 0
framework: shell
require:
- bash
- podman
environment:
TEST_ARTIFACTS: /var/share/test-artifacts
JP_VALIDATOR_IMAGE: quay.io/fedora-java/javapackages-validator:2
JP_VALIDATOR_SOURCE_PATH: src
JP_VALIDATOR_OUTPUT_DIR: ""
JP_VALIDATOR_ARGS: |
org.fedoraproject.javapackages.validator.validators.jp.ValidatorFactoryGeneric
org.fedoraproject.javapackages.validator.validators.jp.ValidatorFactoryJP
io.kojan.runit.validator.RunitValidatorFactory
result: custom
test: exec ./javapackages.sh
/javapackages-validator:
adjust:
# Generic flavor. Run selected upstream validators as well certain downstream ones.
- when: jpv_flavor == generic
environment+:
JP_VALIDATOR_ARGS: |
org.fedoraproject.javapackages.validator.validators.jp.ValidatorFactoryGeneric

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>config</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -1,73 +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 BytecodeVersionConfigJP implements BytecodeVersionConfig {
private Set<String> 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-activation1",
"jakarta-mail",
"jakarta-oro",
"jdepend",
"jsch",
"jzlib",
"regexp",
"xalan-j2",
"xerces-j2",
"xml-commons-apis",
"xml-commons-resolver",
});
@Override
public boolean allowedVersion(RpmInfo rpm, String jarName, String className, int version) {
// JEP 238: Multi-Release JAR Files
// https://openjdk.org/jeps/238
if (className.startsWith("META-INF/versions/")) {
return version <= 44 + Integer.parseInt(className.substring(18, className.indexOf('/', 18)));
}
if (className.equals("module-info.class") || className.equals("package-info.class")) {
return true;
}
if (packagesReqVersion8.contains(rpm.getPackageName())) {
return version <= 44 + 8;
}
return version <= 44 + 17;
}
}

View file

@ -0,0 +1,115 @@
package org.fedoraproject.javapackages.validator.validators.jp;
import java.nio.file.Path;
import java.util.Map;
import java.util.Set;
import org.fedoraproject.javapackages.validator.spi.Decorated;
import org.fedoraproject.javapackages.validator.util.BytecodeVersionJarValidator;
import org.fedoraproject.javapackages.validator.util.Common;
import io.kojan.javadeptools.rpm.RpmPackage;
public class BytecodeVersionJarValidatorJP extends BytecodeVersionJarValidator {
@Override
public String getTestName() {
return "/java/jp/bytecode_version";
}
private Set<String> 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-activation1",
"jakarta-mail",
"jakarta-oro",
"jdepend",
"jsch",
"jzlib",
"regexp",
"xalan-j2",
"xerces-j2",
"xml-commons-apis",
"xml-commons-resolver",
});
@Override
public void validate(RpmPackage rpm, Path jarPath, Map<Path, Version> classVersions) {
for (var entry : classVersions.entrySet()) {
Path classPath = entry.getKey();
int version = entry.getValue().major();
int maxAllowedVersion = 21;
int expected;
if (classPath.endsWith("module-info.class") || classPath.endsWith("package-info.class")) {
// pass
} else if (classPath.startsWith("META-INF/versions")) {
// JEP 238: Multi-Release JAR Files
// https://openjdk.org/jeps/238
if (version > 44 + (expected = Short.parseShort(classPath.getName(2).toString()))) {
fail("{0}: {1}: {2}: class bytecode version is {3} which is larger than {4}",
Decorated.rpm(rpm),
Decorated.custom(jarPath, DECORATION_JAR),
Decorated.struct(classPath),
Decorated.actual(version),
Decorated.expected(expected));
continue;
} else {
// pass
}
} else if (packagesReqVersion8.contains(Common.getPackageName(rpm.getInfo())) && version > 44 + 8) {
fail("{0}: {1}: {2}: class bytecode version is {3} which is larger than {4} (package is required to have a bytecode version compatible with JVM 8)",
Decorated.rpm(rpm),
Decorated.custom(jarPath, DECORATION_JAR),
Decorated.struct(classPath),
Decorated.actual(version),
Decorated.expected(44 + 8));
continue;
} else if (version > 44 + maxAllowedVersion) {
fail("{0}: {1}: {2}: class bytecode version is {3} which is larger than {4} (all packages should have bytecode version compatible with JVM {5})",
Decorated.rpm(rpm),
Decorated.custom(jarPath, DECORATION_JAR),
Decorated.struct(classPath),
Decorated.actual(version),
Decorated.expected(44 + maxAllowedVersion),
Decorated.plain(maxAllowedVersion));
continue;
}
pass("{0}: {1}: {2}: class bytecode version: {3}",
Decorated.rpm(rpm),
Decorated.custom(jarPath, DECORATION_JAR),
Decorated.struct(classPath),
Decorated.actual(version));
}
}
}

View file

@ -1,26 +0,0 @@
package org.fedoraproject.javapackages.validator.config;
import java.nio.file.Path;
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(Path path, Collection<? extends RpmInfo> 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"))) {
return true;
}
if (providerRpms.stream().allMatch(rpm -> rpm.getName().startsWith("maven-local-openjdk"))) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,30 @@
package org.fedoraproject.javapackages.validator.validators.jp;
import java.nio.file.Path;
import java.util.Collection;
import org.fedoraproject.javapackages.validator.util.Common;
import org.fedoraproject.javapackages.validator.util.DuplicateFileValidator.DefaultDuplicateFileValidator;
import io.kojan.javadeptools.rpm.RpmInfo;
public class DuplicateFileValidatorJP extends DefaultDuplicateFileValidator {
@Override
public String getTestName() {
return "/jp/duplicate_files";
}
@Override
public boolean allowedDuplicateFile(Path path, Collection<? extends RpmInfo> providerRpms) throws Exception {
if (path.getParent().equals(Path.of("/usr/share/jpbinding"))) {
return true;
}
// FIXME we want to get rid of these duplicates
if (path.toString().startsWith("/usr/share/licenses/")) {
return providerRpms.stream().map(Common::getPackageName).distinct().count() == 1;
}
return false;
}
}

View file

@ -1,31 +1,51 @@
package org.fedoraproject.javapackages.validator.config;
package org.fedoraproject.javapackages.validator.validators.jp;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.spi.Decorated;
import org.fedoraproject.javapackages.validator.util.Common;
import org.fedoraproject.javapackages.validator.util.FilesValidator;
import io.kojan.javadeptools.rpm.RpmInfo;
import io.kojan.javadeptools.rpm.RpmPackage;
public class FilesValidatorJP extends FilesValidator {
@Override
public String getTestName() {
return "/jp/files";
}
public class FilesConfigJP implements FilesConfig {
private Map<String, Pattern> patternsCache = new TreeMap<>();
private static String substitute(RpmInfo rpm, String text) {
return text
.replace("${package}", rpm.getPackageName())
.replace("${package}", Common.getPackageName(rpm))
.replace("${rpm.name}", rpm.getName())
;
}
private static class Prefix {
static final String ETC = "/etc/${package}";
static final String JPBINDING = "/usr/share/jpbinding";
static final String ETC_PKG = "/etc/${package}";
static final String ETC_JAVA = "/etc/java";
static final String USR_BIN = "/usr/bin/";
static final String USR_LIB_BUILD_ID = "/usr/lib/.build-id";
}
private static Set<String> ignoredComponents = new LinkedHashSet<>();
static {
ignoredComponents.add("javapackages-bootstrap");
ignoredComponents.add("javapackages-tools");
}
private static Map<String, List<String>> nameAliases = new TreeMap<>();
static {
nameAliases.put("maven-resolver", List.of("aether"));
@ -40,30 +60,33 @@ public class FilesConfigJP implements FilesConfig {
private static Map<String, List<String>> prefixes = new TreeMap<>();
static {
prefixes.put("ant", List.of(Prefix.ETC, Prefix.USR_BIN));
prefixes.put("ant", List.of(Prefix.ETC_PKG, Prefix.ETC_JAVA, Prefix.JPBINDING, 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("javacc", List.of(Prefix.USR_BIN));
prefixes.put("java_cup", List.of(Prefix.USR_BIN));
prefixes.put("javapackages-bootstrap", List.of("/usr/lib/java/javapackages-bootstrap", "/usr/lib/rpm", "/etc/rpm", "/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("jline", List.of(Prefix.USR_LIB_BUILD_ID));
prefixes.put("junit5", List.of(Prefix.USR_BIN));
prefixes.put("maven", List.of(Prefix.ETC_PKG, Prefix.ETC_JAVA, Prefix.JPBINDING, Prefix.USR_BIN));
prefixes.put("maven4", List.of(Prefix.ETC_PKG, Prefix.ETC_JAVA, Prefix.JPBINDING, Prefix.USR_BIN));
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));
prefixes.put("xmvn", List.of(Prefix.JPBINDING, Prefix.USR_BIN));
prefixes.put("xmvn-generator", List.of("/usr/lib/rpm", "/etc/rpm"));
}
private static Map<String, List<String>> 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("maven", List.of("/etc/m2.conf"));
exceptionalFiles.put("maven4", List.of("/etc/m24.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"));
exceptionalFiles.put("jline", List.of("/usr/lib/jline", "/usr/lib/jline/libjlinenative.so", "/usr/lib/java/jline"));
}
private static boolean namesRelated(String lhs, String rhs) {
@ -105,13 +128,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(rpm.getPackageName(), Collections.emptyList())) {
for (String prefix : prefixes.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) {
if (filename.startsWith(substitute(rpm, prefix))) {
return true;
}
}
for (String filepath : exceptionalFiles.getOrDefault(rpm.getPackageName(), Collections.emptyList())) {
for (String filepath : exceptionalFiles.getOrDefault(Common.getPackageName(rpm), Collections.emptyList())) {
if (filename.equals(filepath)) {
return true;
}
@ -145,8 +168,8 @@ public class FilesConfigJP implements FilesConfig {
return true;
}
if (patternsCache.computeIfAbsent(rpm.getPackageName() + "/javadoc",
p -> Pattern.compile("/usr/share/javadoc/" + rpm.getPackageName() + "(:?/.*)?"))
if (patternsCache.computeIfAbsent(Common.getPackageName(rpm) + "/javadoc",
_ -> Pattern.compile("/usr/share/javadoc/" + Common.getPackageName(rpm) + "(:?/.*)?"))
.matcher(filename).matches()) {
return true;
}
@ -221,7 +244,7 @@ public class FilesConfigJP implements FilesConfig {
}
if (namesRelated(rpm.getName(), rpmEntryPrefix)
|| namesRelated(rpm.getPackageName(), rpmEntryPrefix)
|| namesRelated(Common.getPackageName(rpm), rpmEntryPrefix)
|| isAlias(rpm.getName(), rpmEntryPrefix)) {
return true;
}
@ -240,7 +263,7 @@ public class FilesConfigJP implements FilesConfig {
}
if (namesRelated(rpm.getName(), rpmEntryPrefix)
|| namesRelated(rpm.getPackageName(), rpmEntryPrefix)
|| namesRelated(Common.getPackageName(rpm), rpmEntryPrefix)
|| isAlias(rpm.getName(), rpmEntryPrefix)) {
return true;
}
@ -258,7 +281,7 @@ public class FilesConfigJP implements FilesConfig {
return true;
}
if (filename.startsWith("/usr/bin/" + rpm.getPackageName() + "/")) {
if (filename.startsWith("/usr/bin/" + Common.getPackageName(rpm) + "/")) {
return true;
}
@ -308,6 +331,16 @@ public class FilesConfigJP implements FilesConfig {
return false;
}
@Override
public void validate(RpmPackage rpm) throws Exception {
if (ignoredComponents.contains(rpm.getInfo().getSourceName())) {
skip("{0}: the component {1} is ignored", Decorated.rpm(rpm),
Decorated.actual(rpm.getInfo().getSourceName()));
} else {
super.validate(rpm);
}
}
@Override
public boolean allowedFile(RpmInfo rpm, Path path) {
if (rpm.isSourcePackage()) {
@ -315,21 +348,20 @@ public class FilesConfigJP implements FilesConfig {
return true;
}
// TODO
String filename = path.toString();
if (rpm.getName().equals(rpm.getPackageName() + "-javadoc") || rpm.getName().equals(rpm.getPackageName() + "-javadocs")) {
if (rpm.getName().equals(Common.getPackageName(rpm) + "-javadoc") || rpm.getName().equals(Common.getPackageName(rpm) + "-javadocs")) {
return allowedJavadocFile(rpm, filename);
} else if (rpm.getName().equals(rpm.getPackageName() + "-debuginfo")) {
} else if (rpm.getName().equals(Common.getPackageName(rpm) + "-debuginfo")) {
return allowedDebuginfoFile(rpm, filename);
} else if (rpm.getName().equals(rpm.getPackageName() + "-debugsource")) {
} 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
// TODO differentiate Java applications ad libraries
return allowedJavaApplicationFile(rpm, filename);
}
}

View file

@ -0,0 +1,27 @@
package org.fedoraproject.javapackages.validator.validators.jp;
import java.util.Set;
import org.fedoraproject.javapackages.validator.spi.Decorated;
import org.fedoraproject.javapackages.validator.validators.JavaExclusiveArchValidator;
import io.kojan.javadeptools.rpm.RpmPackage;
public class JavaExclusiveArchValidatorJP extends JavaExclusiveArchValidator {
@Override
public String getTestName() {
return "/java/jp/exclusive_arch";
}
private static final Set<String> SKIPPED = Set.of("javapackages-tools", "byaccj", "jurand");
@Override
public void validate(RpmPackage rpm) throws Exception {
String component = rpm.getInfo().getSourceName();
if (SKIPPED.contains(component)) {
skip("Skipping rpm {0}", Decorated.rpm(rpm));
return;
}
super.validate(rpm);
}
}

View file

@ -0,0 +1,23 @@
package org.fedoraproject.javapackages.validator.validators.jp;
import org.apache.commons.compress.archivers.cpio.CpioArchiveEntry;
import org.fedoraproject.javapackages.validator.spi.Decorated;
import org.fedoraproject.javapackages.validator.validators.JpmsProvidesValidator;
import io.kojan.javadeptools.rpm.RpmPackage;
public class JpmsProvidesValidatorJP extends JpmsProvidesValidator {
@Override
public String getTestName() {
return "/java/jp/jpms-provides";
}
@Override
public void acceptJarEntry(RpmPackage rpm, CpioArchiveEntry cpio, byte[] bytes) throws Exception {
if (rpm.getInfo().getSourceName().equals("javapackages-bootstrap")) {
skip("Skipping rpm {0}", Decorated.rpm(rpm));
return;
}
super.acceptJarEntry(rpm, cpio, bytes);
}
}

View file

@ -1,31 +0,0 @@
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 (rpm.getPackageName().equals("javapackages-bootstrap")) {
return sizeBytes <= 40_000_000;
}
// javadoc rpms
if (rpm.getName().equals(rpm.getPackageName() + "-javadoc")) {
return sizeBytes <= 4_000_000;
}
// maven-lib and xmvn-minimal bundle dependencies during bootstrap
if (rpm.getRelease().endsWith("~bootstrap")) {
if (rpm.getName().equals("maven-lib") || rpm.getName().equals("xmvn-minimal")) {
return sizeBytes <= 10_000_000;
}
}
return sizeBytes <= 3_500_000;
}
}

View file

@ -0,0 +1,38 @@
package org.fedoraproject.javapackages.validator.validators.jp;
import org.fedoraproject.javapackages.validator.util.Common;
import org.fedoraproject.javapackages.validator.util.RpmFilesizeValidator;
import io.kojan.javadeptools.rpm.RpmInfo;
public class RpmFilesizeValidatorJP extends RpmFilesizeValidator {
@Override
public String getTestName() {
return "/jp/rpm_filesize";
}
@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 <= 60_000_000;
}
// javadoc rpms
if (rpm.getName().equals(Common.getPackageName(rpm) + "-javadoc")) {
return sizeBytes <= 4_000_000;
}
// maven-lib and xmvn-minimal bundle dependencies during bootstrap
if (rpm.getRelease().endsWith("~bootstrap")) {
if (rpm.getName().equals("maven-lib") || rpm.getName().equals("xmvn-minimal")) {
return sizeBytes <= 10_000_000;
}
}
return sizeBytes <= 4_000_000;
}
}

View file

@ -1,9 +0,0 @@
package org.fedoraproject.javapackages.validator.config;
import java.nio.file.Paths;
public class SymlinkConfigJP extends SymlinkConfig.EnvrootImpl {
public SymlinkConfigJP() {
super(Paths.get("/mnt/envroot"));
}
}

View file

@ -0,0 +1,20 @@
package org.fedoraproject.javapackages.validator.validators.jp;
import java.util.List;
import org.fedoraproject.javapackages.validator.spi.Validator;
import org.fedoraproject.javapackages.validator.spi.ValidatorFactory;
import org.fedoraproject.javapackages.validator.validators.*;
public class ValidatorFactoryGeneric implements ValidatorFactory {
@Override
public List<Validator> getValidators() {
return List.of(new Validator[] {
new AttributeProvidesValidator(),
new JavadocNoarchValidator(),
new JavaExclusiveArchValidatorJP(),
new MavenMetadataValidator(),
new NoBootstrapValidator(),
});
}
}

View file

@ -0,0 +1,18 @@
package org.fedoraproject.javapackages.validator.validators.jp;
import java.util.List;
import org.fedoraproject.javapackages.validator.spi.Validator;
import org.fedoraproject.javapackages.validator.spi.ValidatorFactory;
public class ValidatorFactoryJP implements ValidatorFactory {
@Override
public List<Validator> getValidators() {
return List.of(new Validator[] {
new BytecodeVersionJarValidatorJP(),
new DuplicateFileValidatorJP(),
new FilesValidatorJP(),
new RpmFilesizeValidatorJP(),
});
}
}

View file

@ -0,0 +1,13 @@
compiler.release=22
#repositories=https://s01.oss.sonatype.org/content/repositories/snapshots
dependencies=\
io.kojan:runit-api:1.0.0 \
io.kojan:runit-validator:1.0.0 \
org.apiguardian:apiguardian-api:1.1.2 \
org.hamcrest:hamcrest:3.0 \
org.junit.jupiter:junit-jupiter-api:5.11.3 \
org.junit.jupiter:junit-jupiter-engine:5.11.3 \
org.junit.platform:junit-platform-commons:1.11.3 \
org.junit.platform:junit-platform-engine:1.11.3 \
org.junit.platform:junit-platform-launcher:1.11.3 \
org.opentest4j:opentest4j:1.3.0 \

View file

@ -0,0 +1,2 @@
org.fedoraproject.javapackages.validator.validators.jp.ValidatorFactoryGeneric
org.fedoraproject.javapackages.validator.validators.jp.ValidatorFactoryJP

View file

@ -0,0 +1,37 @@
package tests;
import static io.kojan.runit.api.RUnit.*;
import static io.kojan.runit.api.matcher.RUnitMatchers.*;
import static org.hamcrest.Matchers.*;
import org.junit.jupiter.api.DisplayName;
import io.kojan.javadeptools.rpm.*;
import io.kojan.runit.api.*;
@DisplayName("/apache-commons")
public class ApacheCommonsCheck {
@PackageTest
@IncludeSource("apache-commons-.*")
@IncludeBinary("apache-commons-.*")
@ExcludeBinary("apache-commons-collections-testframework")
public void saneName(RpmInfo rpm) {
assertThat("Package name is sane", rpm.getName(), matchesRegex("apache-commons-[a-z][a-z0-9]+(-javadoc)?"));
}
@PackageTest
@IncludeBinary("apache-commons-[a-z][a-z0-9]+")
@ExcludeBinary("apache-commons-parent") // Parent POM, no Java code
public void jpmsProvides(RpmInfo rpm) {
String id = rpm.getName().substring("apache-commons-".length());
assertThat("Apache Commons packages should have jpms provides", rpm,
provides("jpms\\(org.apache.commons." + id + "\\)( = .*)?"));
}
@PackageTest
@IncludeBinary("apache-commons-.*")
public void apacheLicense(RpmInfo rpm) {
assertThat("Apache Commons packages license should be Apache-2.0", rpm.getLicense(), is("Apache-2.0"));
}
}

57
src/runit/BasicCheck.java Normal file
View file

@ -0,0 +1,57 @@
package tests;
import static io.kojan.runit.api.RUnit.*;
import static io.kojan.runit.api.matcher.RUnitMatchers.*;
import static org.hamcrest.Matchers.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.jupiter.api.DisplayName;
import io.kojan.javadeptools.rpm.*;
import io.kojan.runit.api.*;
@DisplayName("/basic")
public class BasicCheck {
@PackageTest
public void noBootstrapRelease(RpmInfo rpm) {
assertThat("No ~bootstrap in release", rpm.getRelease(), not(endsWith("~bootstrap")));
}
@PackageTest
@ExcludeSource("java_cup")
@ExcludeBinary("java_cup")
@ExcludeBinary("java_cup-javadoc")
@ExcludeBinary("java_cup-manual")
@ExcludeBinary("antlr-C\\+\\+")
public void saneName(RpmInfo rpm) {
assertThat("Package name is sane", rpm.getName(), matchesRegex("[a-z][a-z0-9.-]+[a-z0-9]"));
}
@PackageTest
@ExcludeBinary("maven-lib")
@ExcludeBinary("sisu")
@ExcludeBinary("javapackages-bootstrap")
public void bundledProvides(RpmInfo rpm) {
assertThat("No bundled(*) provides", rpm, not(provides("bundled\\(.*\\)")));
}
@PackageTest
@IncludeBinary
public void binaryVersionMatchesSourceVersion(RpmInfo rpm) {
Pattern srpmPattern = Pattern.compile("^(.+)-([^-]+)-([^-]+).src.rpm$");
Matcher matcher = srpmPattern.matcher(rpm.getSourceRPM());
assertThat("SRPM name matches regex", matcher.matches(), is(true));
assertThat("Binary package Version matches SRPM Version", rpm.getVersion(), is(matcher.group(2)));
assertThat("Binary package Release matches SRPM Release", rpm.getRelease(), is(matcher.group(3)));
}
@PackageTest
@IncludeBinary
public void noConflicts(RpmInfo rpm) {
assertThat("Packages have no explicit Conflicts", rpm, not(conflicts(".*")));
}
}

49
src/runit/FileCheck.java Normal file
View file

@ -0,0 +1,49 @@
package tests;
import static io.kojan.runit.api.RUnit.*;
import static org.hamcrest.Matchers.*;
import java.nio.file.Path;
import java.util.Arrays;
import org.junit.jupiter.api.DisplayName;
import io.kojan.javadeptools.rpm.*;
import io.kojan.runit.api.*;
@DisplayName("/file")
public class FileCheck {
@FileTest
@IncludeRegularFile
@ExcludeBinary(".*-debuginfo")
public void elvesLiveInUserLib(RpmInfo rpm, Path path, byte[] data, RpmFile entry) {
assumeThat("File is not too small to be ELF", entry.getSize(), is(greaterThanOrEqualTo(4L)));
assumeThat("ELF magic is present", Arrays.copyOfRange(data, 0, 4), is(new byte[] { 0x7f, 'E', 'L', 'F' }));
assertThat("ELF files must be under /usr/lib", path.toString(), startsWith("/usr/lib/"));
assertThat("Noarch packages must not contain ELF files", rpm.getArch(), is(not("noarch")));
}
@FileTest
@IncludeBinary
@ExcludeBinary(".*-debuginfo")
public void modeTest(RpmInfo rpm, Path path, byte[] data, RpmFile entry) throws Exception {
String mode = Integer.toOctalString((int) entry.getMode() & 07777);
if (entry.isRegularFile()) {
if (entry.getSize() >= 4 && data[0] == 0x7f && data[1] == 'E' && data[2] == 'L' && data[3] == 'F') {
assertThat("ELF files must have mode 755", mode, is("755"));
} else if (entry.getSize() >= 2 && data[0] == '#' && data[1] == '!') {
assertThat("Files with shebang must have mode 755", mode, is("755"));
} else if (entry.getSize() == 0) {
assertThat("Empty files must have mode 644 or 0", mode, either(is("644")).or(is("0")));
} else {
assertThat("Other regular files must have mode 644", mode, is("644"));
}
} else if (entry.isDirectory()) {
assertThat("Directories must have mode 755", mode, is("755"));
} else if (!entry.isSymbolicLink()) {
assertThat("Not a regular file, not a symlink and not a directory", false, is(true));
}
}
}

View file

@ -0,0 +1,37 @@
package tests;
import static io.kojan.runit.api.RUnit.*;
import static io.kojan.runit.api.matcher.RUnitMatchers.*;
import static org.hamcrest.Matchers.*;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.DisplayName;
import io.kojan.javadeptools.rpm.RpmInfo;
import io.kojan.runit.api.ExcludeFileName;
import io.kojan.runit.api.ExcludeSource;
import io.kojan.runit.api.ExcludeSymlink;
import io.kojan.runit.api.FileTest;
import io.kojan.runit.api.IncludeFileName;
@DisplayName("/jpackage_script")
public class JPackageScriptCheck {
@FileTest
@IncludeFileName("/usr/bin/.*")
@ExcludeSource
@ExcludeSymlink
@ExcludeFileName("/usr/bin/ant")
public void testJPackageScript(RpmInfo rpm, byte[] bytes) {
assumeThat("The binary is a script with a shebang", bytes.length, greaterThan(1));
assumeThat("The binary is a script with a shebang", bytes[0], is((byte)'#'));
assumeThat("The binary is a script with a shebang", bytes[1], is((byte)'!'));
String content = new String(bytes, StandardCharsets.UTF_8);
assumeThat("The script was generated with %jpackage_script", content,
containsString(". /usr/share/java-utils/java-functions\n"));
assertThat("The script explicitly sets JAVA_HOME to Java 21", content,
containsString("\nJAVA_HOME=\"${JAVA_HOME:-/usr/lib/jvm/jre-21-openjdk}\"\n"));
assertThat("Requires on java-21-openjdk-headless are present", rpm, requires("java-21-openjdk-headless"));
assertThat("Requires on javapackages-tools are present", rpm, requires("javapackages-tools"));
}
}

43
src/runit/JarCheck.java Normal file
View file

@ -0,0 +1,43 @@
package tests;
import static io.kojan.runit.api.RUnit.*;
import static org.hamcrest.Matchers.*;
import java.io.ByteArrayInputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.jar.Attributes;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.junit.jupiter.api.DisplayName;
import io.kojan.javadeptools.rpm.*;
import io.kojan.runit.api.*;
@DisplayName("/jar")
public class JarCheck {
@FileTest
@IncludeFileName("/usr/(share|lib)/java/.*\\.jar")
@ExcludeSource
@ExcludeSymlink
public void testJarSanity(RpmInfo rpm, Path path, byte[] content, RpmFile entry) throws Exception {
assertThat("JAR file must be a regular file", entry.isRegularFile(), is(true));
assertThat("JAR file mode must be 644", Integer.toOctalString((int) entry.getMode() & 07777), is("644"));
assertThat("JAR file must not be empty", entry.getSize(), greaterThan(10L));
assertThat("JAR file has PKZIP magic number", (char) content[0], is('P'));
assertThat("JAR file has PKZIP magic number", (char) content[1], is('K'));
try (JarInputStream jis = new JarInputStream(new ByteArrayInputStream(content))) {
Manifest mf = jis.getManifest();
assertThat("JAR must have manifest", mf, not(nullValue()));
Attributes attrs = mf.getMainAttributes();
assertThat("JAR must have main attritutes", attrs, not(nullValue()));
for (String attr : Arrays.asList("Javapackages-GroupId", "Javapackages-ArtifactId",
"Javapackages-Version")) {
String val = attrs.getValue(attr);
assertThat("JAR must have " + attr + " manifest attribute", val, not(nullValue()));
}
}
}
}

View file

@ -0,0 +1,28 @@
package tests;
import static io.kojan.runit.api.RUnit.*;
import static org.hamcrest.Matchers.*;
import java.nio.file.Path;
import org.junit.jupiter.api.DisplayName;
import io.kojan.javadeptools.rpm.*;
import io.kojan.runit.api.*;
@DisplayName("/javadoc")
public class JavadocCheck {
@PackageTest
@IncludeBinary(".*-javadoc")
public void testJavadocNoarch(RpmInfo rpm) {
assertThat("Javadoc package is noarch", rpm.getArch(), is("noarch"));
}
@FileTest
@IncludeBinary(".*-javadoc")
public void javadocFiles(RpmInfo rpm, Path path) {
assertThat("Javadoc package contains only javadoc content", path.toString(),
anyOf(startsWith("/usr/share/javadoc/"), startsWith("/usr/share/licenses/")));
}
}

188
src/runit/LicenseCheck.java Normal file
View file

@ -0,0 +1,188 @@
package tests;
import static io.kojan.runit.api.RUnit.*;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.jupiter.api.DisplayName;
import io.kojan.javadeptools.rpm.*;
import io.kojan.runit.api.*;
@DisplayName("/license")
public class LicenseCheck {
// General-purpose licenses that are approved for everything, including code.
// See: https://docs.fedoraproject.org/en-US/legal/allowed-licenses/
private static final Set<String> GLOBAL_ALLOWED_LICENSES = Set.of( //
// General-purpose permissive licenses
"0BSD", //
"Apache-1.1", //
"Apache-2.0", //
"BSD-2-Clause", //
"BSD-3-Clause", //
"BSD-3-Clause-Sun", //
"CPL-1.0", //
"EPL-1.0", //
"EPL-2.0", //
"ISC", //
"MIT", //
"Plexus", //
"SMLNJ", //
"Saxpath", //
"xpp", //
"W3C", //
// Very permissive licenses, close to public domain
"ANTLR-PD", //
"CC0-1.0", //
"SAX-PD-2.0", //
// GPL is only allowed with classpath exception,
// and only as alternative to permissive licenses
"EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0", //
"EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only WITH Classpath-exception-2.0", //
// Likewise LGPL
"LGPL-2.0-or-later OR Apache-2.0", //
"Apache-2.0 OR LGPL-2.0-or-later" //
);
// Public domain is valid only for packages that were reviewed by Fedora legal
// and which were added to public-domain-text.txt at
// https://gitlab.com/fedora/legal/fedora-license-data
private static final Set<String> PUBLIC_DOMAIN_PACKAGES = Set.of( //
"aopalliance", //
"plexus-utils", //
"plexus-utils4", //
"xz-java", //
"javapackages-bootstrap" // special case, as it it bundles all the above
);
// Allowed content licenses, in addition to GLOBAL_ALLOWED_LICENSES
private static final Set<String> CONTENT_ALLOWED_LICENSES = Set.of( //
"GPL-2.0-or-later", //
"LGPL-2.1-or-later", //
"AFL-2.0", //
"CC-BY-2.5" //
);
@PackageTest
@IncludeBinary
public void testLicense(RpmInfo rpm) {
// Licenses that are allowed for particular package. This may be a superset of
// GLOBAL_ALLOWED_LICENSES, for example if the package is known to be docs-only,
// content licenses may be allowed in addition to general-purpose licenses.
Set<String> packageAllowedLicenses = new LinkedHashSet<String>(GLOBAL_ALLOWED_LICENSES);
if (PUBLIC_DOMAIN_PACKAGES.contains(rpm.getSourceName())) {
packageAllowedLicenses.add("LicenseRef-Fedora-Public-Domain");
}
if (rpm.getName().endsWith("-javadoc") || rpm.getName().endsWith("-manual")) {
packageAllowedLicenses.addAll(CONTENT_ALLOWED_LICENSES);
}
assertThat("License is allowed", rpm.getLicense(), new LicenseMatcher(packageAllowedLicenses));
}
}
class LicenseMatcher extends TypeSafeMatcher<String> {
private static final Pattern ID_REGEX = Pattern.compile("([a-zA-Z0-9.-]+).*");
private final Set<String> packageAllowedLicenses;
private String expression;
private int parserPos;
public LicenseMatcher(Set<String> packageAllowedLicenses) {
this.packageAllowedLicenses = packageAllowedLicenses;
}
private void parseError(String msg) {
StringBuilder sb = new StringBuilder();
sb.append("Syntax error - " + msg + "\n");
sb.append(" SPDX expression: \"" + expression + "\"\n");
sb.append(" Location: here ---" + new String("-").repeat(parserPos) + "^");
fail(sb.toString());
}
private void parseEof() {
if (parserPos != expression.length()) {
parseError("Expected EOF");
}
}
private boolean matches(String op) {
if (expression.substring(parserPos).startsWith(op)) {
parserPos += op.length();
return true;
}
return false;
}
private boolean allowed(int beginPos) {
String expr = expression.substring(beginPos, parserPos);
return packageAllowedLicenses.contains(expr);
}
private void parseAtom() {
Matcher matcher = ID_REGEX.matcher(expression.substring(parserPos));
if (!matcher.matches()) {
parseError("Expected identifier");
}
String tag = matcher.group(1);
parserPos += tag.length();
}
private boolean parsePrimary() {
if (matches("(")) {
boolean allowed = parseUnion();
if (!matches(")")) {
parseError("Unclosed parenthesis");
}
return allowed;
}
int beginPos = parserPos;
parseAtom();
if (matches(" WITH ")) {
parseAtom();
}
return allowed(beginPos);
}
private boolean parseIntersection() {
int beginPos = parserPos;
boolean allowed = parsePrimary();
if (matches(" AND ")) {
allowed &= parseIntersection();
}
return allowed || allowed(beginPos);
}
private boolean parseUnion() {
int beginPos = parserPos;
boolean allowed = parseIntersection();
if (matches(" OR ")) {
allowed &= parseUnion();
}
return allowed || allowed(beginPos);
}
@Override
protected boolean matchesSafely(String license) {
expression = license;
parserPos = 0;
boolean allowed = parseUnion();
parseEof();
return allowed;
}
@Override
public void describeTo(Description description) {
description.appendText("approved license");
}
}

View file

@ -1,92 +0,0 @@
contact:
- Marian Koncek <mkoncek@redhat.com>
require:
- bash
- findutils
- podman
environment:
TEST_ARTIFACTS: /var/share/test-artifacts
JP_VALIDATOR_IMAGE: quay.io/mizdebsk/javapackages-validator
ENVROOT: /
/symlink:
description: >
Check for files inside RPMs. This test checks for dangling symlinks.
(configurable)
test: ./jp_validator.sh SymlinkCheck -c /mnt/config/SymlinkConfigJP.java
adjust:
- enabled: false
when: trigger == MBICI
/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 -c /mnt/config/DuplicateFileConfigJP.java
/rpm_filesize:
description: >
Check whether the RPM file has allowed size in bytes.
(configurable)
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 -c /mnt/config/FilesConfigJP.java
/attributes:
description: >
Set of tests to check for RPM attributes.
(configurable)
/conflicts:
test: ./jp_validator.sh attribute.ConflictsCheck
/enhances:
test: ./jp_validator.sh attribute.EnhancesCheck
/obsoletes:
test: ./jp_validator.sh attribute.ObsoletesCheck
/order_with_requires:
test: ./jp_validator.sh attribute.OrderWithRequiresCheck
/provides:
test: ./jp_validator.sh attribute.ProvidesCheck
/recommends:
test: ./jp_validator.sh attribute.RecommendsCheck
/requires:
test: ./jp_validator.sh attribute.RequiresCheck
/suggests:
test: ./jp_validator.sh attribute.SuggestsCheck
/supplements:
test: ./jp_validator.sh attribute.SupplementsCheck
/java_specific:
description: >
Set of tests used for packages that contain Java code.
/bytecode_version:
description: >
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 -c /mnt/config/BytecodeVersionConfigJP.java
/javadoc_noarch:
description: >
Check whether javadoc packages have architecture noarch
test: ./jp_validator.sh JavadocNoarchCheck
/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
test: ./jp_validator.sh JavaExclusiveArchCheck