Skip to content

Commit 8b0cb78

Browse files
committed
Add tuf conformance
ignores all currently failing tests with xfails Signed-off-by: Appu Goundan <[email protected]>
1 parent ed37516 commit 8b0cb78

File tree

9 files changed

+407
-1
lines changed

9 files changed

+407
-1
lines changed

.github/workflows/tuf-conformance.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: TUF Conformance Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- '**'
7+
pull_request:
8+
workflow_dispatch:
9+
# TODO: add cron
10+
11+
jobs:
12+
conformance:
13+
strategy:
14+
max-parallel: 1
15+
matrix:
16+
java-version: [11, 17]
17+
fail-fast: false
18+
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
22+
23+
- name: Set up JDK ${{ matrix.java-version }}
24+
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
25+
with:
26+
java-version: ${{ matrix.java-version }}
27+
distribution: 'temurin'
28+
29+
- name: Setup Gradle
30+
uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
31+
32+
- name: Build tuf cli
33+
run: ./gradlew :tuf-cli:build
34+
35+
- name: Unpack tuf distribution
36+
run: tar -xvf ${{ github.workspace }}/tuf-cli/build/distributions/tuf-cli-*.tar --strip-components 1
37+
38+
- uses: theupdateframework/tuf-conformance@v2
39+
with:
40+
entrypoint: ${{ github.workspace }}/bin/tuf-cli

settings.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ include("sigstore-java")
77
include("sigstore-gradle:sigstore-gradle-sign-base-plugin")
88
include("sigstore-gradle:sigstore-gradle-sign-plugin")
99
include("sigstore-testkit")
10-
include("sigstore-cli")
1110
include("sigstore-maven-plugin")
1211

12+
include("sigstore-cli")
13+
include("tuf-cli")
14+
1315
include("fuzzing")

tuf-cli/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Sigstore-Java Tuf CLI
2+
3+
Used for conformance testing and internal processes. This is not meant for public consumption, we will not support
4+
any usecase that uses this.
5+
6+
## Usage
7+
8+
### Help
9+
```
10+
./gradlew tuf-cli:run
11+
```

tuf-cli/build.gradle.kts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
plugins {
2+
id("build-logic.java")
3+
id("application")
4+
}
5+
6+
repositories {
7+
mavenCentral()
8+
}
9+
10+
dependencies {
11+
implementation(project(":sigstore-java"))
12+
implementation("info.picocli:picocli:4.7.6")
13+
implementation("com.google.guava:guava:33.3.1-jre")
14+
15+
implementation(platform("com.google.oauth-client:google-oauth-client-bom:1.36.0"))
16+
implementation("com.google.oauth-client:google-oauth-client")
17+
18+
annotationProcessor("info.picocli:picocli-codegen:4.7.6")
19+
}
20+
21+
tasks.compileJava {
22+
options.compilerArgs.add("-Aproject=${project.group}/${project.name}")
23+
}
24+
25+
application {
26+
mainClass.set("dev.sigstore.tuf.cli.Tuf")
27+
}
28+
29+
distributions.main {
30+
contents {
31+
from("tuf-cli.xfails") {
32+
into("bin")
33+
}
34+
}
35+
}
36+
37+
tasks.run.configure {
38+
workingDir = rootProject.projectDir
39+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.tuf.cli;
17+
18+
import dev.sigstore.tuf.FileSystemTufStore;
19+
import dev.sigstore.tuf.HttpFetcher;
20+
import dev.sigstore.tuf.MetaFetcher;
21+
import dev.sigstore.tuf.PassthroughCacheMetaStore;
22+
import dev.sigstore.tuf.RootProvider;
23+
import dev.sigstore.tuf.TrustedMetaStore;
24+
import dev.sigstore.tuf.Updater;
25+
import java.util.concurrent.Callable;
26+
import picocli.CommandLine.Command;
27+
import picocli.CommandLine.ParentCommand;
28+
29+
@Command(name = "download", description = "download targets from a remote location")
30+
public class Download implements Callable<Integer> {
31+
32+
@ParentCommand private Tuf tufCommand;
33+
34+
@Override
35+
public Integer call() throws Exception {
36+
var metadataDir = tufCommand.getMetadataDir();
37+
var metadataUrl = tufCommand.getMetadataUrl();
38+
var targetDir = tufCommand.getTargetDir();
39+
var targetBaseUrl = tufCommand.getTargetBaseUrl();
40+
var targetName = tufCommand.getTargetName();
41+
42+
var fsStore = FileSystemTufStore.newFileSystemStore(metadataDir, targetDir);
43+
var tuf =
44+
Updater.builder()
45+
.setTrustedMetaStore(
46+
TrustedMetaStore.newTrustedMetaStore(
47+
PassthroughCacheMetaStore.newPassthroughMetaCache(fsStore)))
48+
.setTrustedRootPath(RootProvider.fromFile(metadataDir.resolve("root.json")))
49+
.setMetaFetcher(MetaFetcher.newFetcher(HttpFetcher.newFetcher(metadataUrl)))
50+
.setTargetFetcher(HttpFetcher.newFetcher(targetBaseUrl))
51+
.setTargetStore(fsStore)
52+
.build();
53+
// the java client isn't one shot like other clients, so downloadTarget doesn't call update
54+
// for the sake of conformance updateMeta here
55+
tuf.updateMeta();
56+
tuf.downloadTarget(targetName);
57+
return 0;
58+
}
59+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.tuf.cli;
17+
18+
import java.nio.file.Files;
19+
import java.nio.file.Path;
20+
import java.util.concurrent.Callable;
21+
import picocli.CommandLine.Command;
22+
import picocli.CommandLine.Parameters;
23+
import picocli.CommandLine.ParentCommand;
24+
25+
@Command(name = "init", description = "initialize a local tuf repo")
26+
public class Init implements Callable<Integer> {
27+
28+
@Parameters(arity = "1", paramLabel = "<TRUSTED_ROOT>")
29+
Path trustedRoot;
30+
31+
@ParentCommand private Tuf tufCommand;
32+
33+
@Override
34+
public Integer call() throws Exception {
35+
var metadataDir = tufCommand.getMetadataDir();
36+
37+
if (!Files.isRegularFile(trustedRoot)) {
38+
throw new IllegalArgumentException(trustedRoot + " is not a regular file");
39+
}
40+
if (Files.exists(metadataDir)) {
41+
if (!Files.isDirectory(metadataDir)) {
42+
throw new IllegalArgumentException(metadataDir + " is not a directory");
43+
}
44+
} else {
45+
Files.createDirectories(metadataDir);
46+
}
47+
48+
Files.copy(trustedRoot, metadataDir.resolve("root.json"));
49+
return 0;
50+
}
51+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.tuf.cli;
17+
18+
import dev.sigstore.tuf.FileSystemTufStore;
19+
import dev.sigstore.tuf.HttpFetcher;
20+
import dev.sigstore.tuf.MetaFetcher;
21+
import dev.sigstore.tuf.PassthroughCacheMetaStore;
22+
import dev.sigstore.tuf.RootProvider;
23+
import dev.sigstore.tuf.TrustedMetaStore;
24+
import dev.sigstore.tuf.Updater;
25+
import java.util.concurrent.Callable;
26+
import picocli.CommandLine.Command;
27+
import picocli.CommandLine.ParentCommand;
28+
29+
@Command(name = "refresh", description = "update local tuf metadata from the repository")
30+
public class Refresh implements Callable<Integer> {
31+
32+
@ParentCommand private Tuf tufCommand;
33+
34+
@Override
35+
public Integer call() throws Exception {
36+
var metadataDir = tufCommand.getMetadataDir();
37+
var metadataUrl = tufCommand.getMetadataUrl();
38+
39+
var fsStore = FileSystemTufStore.newFileSystemStore(metadataDir);
40+
var tuf =
41+
Updater.builder()
42+
.setTrustedMetaStore(
43+
TrustedMetaStore.newTrustedMetaStore(
44+
PassthroughCacheMetaStore.newPassthroughMetaCache(fsStore)))
45+
.setTrustedRootPath(RootProvider.fromFile(metadataDir.resolve("root.json")))
46+
.setMetaFetcher(MetaFetcher.newFetcher(HttpFetcher.newFetcher(metadataUrl)))
47+
.build();
48+
tuf.update();
49+
return 0;
50+
}
51+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.tuf.cli;
17+
18+
import java.net.URL;
19+
import java.nio.file.Path;
20+
import picocli.CommandLine;
21+
import picocli.CommandLine.Command;
22+
import picocli.CommandLine.Model.CommandSpec;
23+
import picocli.CommandLine.Option;
24+
import picocli.CommandLine.ParameterException;
25+
import picocli.CommandLine.Spec;
26+
27+
@Command(
28+
name = "tuf",
29+
mixinStandardHelpOptions = true,
30+
subcommands = {Init.class, Refresh.class, Download.class})
31+
public class Tuf {
32+
@Spec CommandSpec spec;
33+
34+
public CommandSpec getSpec() {
35+
return spec;
36+
}
37+
38+
@Option(
39+
names = {"--metadata-dir"},
40+
required = false,
41+
paramLabel = "<METADATA_DIR>")
42+
private Path metadataDir;
43+
44+
@Option(
45+
names = {"--metadata-url"},
46+
required = false,
47+
paramLabel = "<METADATA_URL>")
48+
private URL metadataUrl;
49+
50+
@Option(
51+
names = {"--target-name"},
52+
required = false,
53+
paramLabel = "<TARGET_PATH>")
54+
private String targetName;
55+
56+
@Option(
57+
names = {"--target-base-url"},
58+
required = false,
59+
paramLabel = "<TARGET_URL>")
60+
private URL targetBaseUrl;
61+
62+
@Option(
63+
names = {"--target-dir"},
64+
required = false,
65+
paramLabel = "<TARGET_DIR>")
66+
private Path targetDir;
67+
68+
Path getMetadataDir() {
69+
if (metadataDir == null) {
70+
throw new ParameterException(spec.commandLine(), "--metadata-dir not set");
71+
}
72+
return metadataDir;
73+
}
74+
75+
URL getMetadataUrl() {
76+
if (metadataUrl == null) {
77+
throw new ParameterException(spec.commandLine(), "--metadata-url not set");
78+
}
79+
return metadataUrl;
80+
}
81+
82+
String getTargetName() {
83+
if (targetName == null) {
84+
throw new ParameterException(spec.commandLine(), "--target-name not set");
85+
}
86+
return targetName;
87+
}
88+
89+
URL getTargetBaseUrl() {
90+
if (targetBaseUrl == null) {
91+
throw new ParameterException(spec.commandLine(), "--target-base-url not set");
92+
}
93+
return targetBaseUrl;
94+
}
95+
96+
Path getTargetDir() {
97+
if (targetDir == null) {
98+
throw new ParameterException(spec.commandLine(), "--target-dir not set");
99+
}
100+
return targetDir;
101+
}
102+
103+
public static void main(String[] args) {
104+
int exitCode = new CommandLine(new Tuf()).execute(args);
105+
System.exit(exitCode);
106+
}
107+
}

0 commit comments

Comments
 (0)