Skip to content

Commit

Permalink
Try adding tuf conformance
Browse files Browse the repository at this point in the history
Signed-off-by: Appu Goundan <[email protected]>
  • Loading branch information
loosebazooka committed Nov 1, 2024
1 parent 775e0a0 commit 58b5d85
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 14 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/tuf-conformance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: TUF Conformance Tests

on:
push:
branches:
- '**'
pull_request:
workflow_dispatch:
# TODO: add cron

jobs:
conformance:
strategy:
max-parallel: 1
matrix:
java-version: [11, 17]
fail-fast: false

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1

- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
with:
java-version: ${{ matrix.java-version }}
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0

- name: Build tuf cli
run: ./gradlew :tuf-cli:build

- name: Unpack tuf distribution
run: tar -xvf ${{ github.workspace }}/tuf-cli/build/distributions/tuf-cli-*.tar --strip-components 1

- uses: theupdateframework/tuf-conformance@v2
with:
entrypoint: ${{ github.workspace }}/bin/tuf-cli
4 changes: 3 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ include("sigstore-java")
include("sigstore-gradle:sigstore-gradle-sign-base-plugin")
include("sigstore-gradle:sigstore-gradle-sign-plugin")
include("sigstore-testkit")
include("sigstore-cli")
include("sigstore-maven-plugin")

include("sigstore-cli")
include("tuf-cli")

include("fuzzing")
35 changes: 22 additions & 13 deletions sigstore-java/src/main/java/dev/sigstore/tuf/Updater.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class Updater {

// Mutable State
private ZonedDateTime updateStartTime;
private boolean metaUpdated;

Updater(
Clock clock,
Expand Down Expand Up @@ -99,25 +100,32 @@ public void update()
downloadTargets(trustedMetaStore.getTargets());
}

/** Update just metadata but do not download targets. */
public void updateMeta() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
updateRoot();
var oldTimestamp = trustedMetaStore.findTimestamp();
updateTimestamp();
if (Objects.equals(oldTimestamp.orElse(null), trustedMetaStore.getTimestamp())
&& trustedMetaStore.findSnapshot().isPresent()
&& trustedMetaStore.findTargets().isPresent()) {
return;
}
// if we need to update or we can't find targets/timestamps locally then grab new snapshot and
// targets from remote
updateSnapshot();
updateTargets();
try {
updateRoot();
var oldTimestamp = trustedMetaStore.findTimestamp();
updateTimestamp();
if (Objects.equals(oldTimestamp.orElse(null), trustedMetaStore.getTimestamp())
&& trustedMetaStore.findSnapshot().isPresent()
&& trustedMetaStore.findTargets().isPresent()) {
return;
}
// if we need to update or we can't find targets/timestamps locally then grab new snapshot and
// targets from remote
updateSnapshot();
updateTargets();
} finally {
metaUpdated = true;
}
}

/** Download a single target defined in targets. Does not handle delegated targets. */
public void downloadTarget(String targetName)
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
// update should run at least once before we try to grab targets
if (!metaUpdated) {
updateMeta();
}
var targetData = trustedMetaStore.getTargets().getSignedMeta().getTargets().get(targetName);
if (targetData == null) {
throw new TargetMetadataMissingException(targetName);
Expand Down Expand Up @@ -323,6 +331,7 @@ void updateTimestamp()
// 4) check expiration timestamp is after tuf update start time, else fail.
throwIfExpired(timestamp.getSignedMeta().getExpiresAsDate());
// 5) persist timestamp.json
System.out.println("persisting");
trustedMetaStore.setTimestamp(timestamp);
}

Expand Down
11 changes: 11 additions & 0 deletions tuf-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Sigstore-Java Tuf CLI

Used for conformance testing and internal processes. This is not meant for public consumption, we will not support
any usecase that uses this.

## Usage

### Help
```
./gradlew tuf-cli:run
```
30 changes: 30 additions & 0 deletions tuf-cli/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
plugins {
id("build-logic.java")
id("application")
}

repositories {
mavenCentral()
}

dependencies {
implementation(project(":sigstore-java"))
implementation("info.picocli:picocli:4.7.6")
implementation("com.google.guava:guava:33.3.1-jre")

implementation(platform("com.google.oauth-client:google-oauth-client-bom:1.36.0"))
implementation("com.google.oauth-client:google-oauth-client")

annotationProcessor("info.picocli:picocli-codegen:4.7.6")
}

tasks.compileJava {
options.compilerArgs.add("-Aproject=${project.group}/${project.name}")
}

application {
mainClass.set("dev.sigstore.tuf.cli.Tuf")
}
tasks.run.configure {
workingDir = rootProject.projectDir
}
56 changes: 56 additions & 0 deletions tuf-cli/src/main/java/dev/sigstore/tuf/cli/Download.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2024 The Sigstore Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sigstore.tuf.cli;

import dev.sigstore.tuf.FileSystemTufStore;
import dev.sigstore.tuf.HttpFetcher;
import dev.sigstore.tuf.MetaFetcher;
import dev.sigstore.tuf.PassthroughCacheMetaStore;
import dev.sigstore.tuf.RootProvider;
import dev.sigstore.tuf.TrustedMetaStore;
import dev.sigstore.tuf.Updater;
import java.util.concurrent.Callable;
import picocli.CommandLine.Command;
import picocli.CommandLine.ParentCommand;

@Command(name = "download", description = "download targets from a remote location")
public class Download implements Callable<Integer> {

@ParentCommand private Tuf tufCommand;

@Override
public Integer call() throws Exception {
var metadataDir = tufCommand.getMetadataDir();
var metadataUrl = tufCommand.getMetadataUrl();
var targetDir = tufCommand.getTargetDir();
var targetBaseUrl = tufCommand.getTargetBaseUrl();
var targetName = tufCommand.getTargetName();

var fsStore = FileSystemTufStore.newFileSystemStore(metadataDir, targetDir);
var tuf =
Updater.builder()
.setTrustedMetaStore(
TrustedMetaStore.newTrustedMetaStore(
PassthroughCacheMetaStore.newPassthroughMetaCache(fsStore)))
.setTrustedRootPath(RootProvider.fromFile(metadataDir.resolve("root.json")))
.setMetaFetcher(MetaFetcher.newFetcher(HttpFetcher.newFetcher(metadataUrl)))
.setTargetFetcher(HttpFetcher.newFetcher(targetBaseUrl))
.setTargetStore(fsStore)
.build();
tuf.downloadTarget(targetName);
return 0;
}
}
51 changes: 51 additions & 0 deletions tuf-cli/src/main/java/dev/sigstore/tuf/cli/Init.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2024 The Sigstore Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sigstore.tuf.cli;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.ParentCommand;

@Command(name = "init", description = "initialize a local tuf repo")
public class Init implements Callable<Integer> {

@Parameters(arity = "1", paramLabel = "<TRUSTED_ROOT>")
Path trustedRoot;

@ParentCommand private Tuf tufCommand;

@Override
public Integer call() throws Exception {
var metadataDir = tufCommand.getMetadataDir();

if (!Files.isRegularFile(trustedRoot)) {
throw new IllegalArgumentException(trustedRoot + " is not a regular file");
}
if (Files.exists(metadataDir)) {
if (!Files.isDirectory(metadataDir)) {
throw new IllegalArgumentException(metadataDir + " is not a directory");
}
} else {
Files.createDirectories(metadataDir);
}

Files.copy(trustedRoot, metadataDir.resolve("root.json"));
return 0;
}
}
51 changes: 51 additions & 0 deletions tuf-cli/src/main/java/dev/sigstore/tuf/cli/Refresh.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2024 The Sigstore Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sigstore.tuf.cli;

import dev.sigstore.tuf.FileSystemTufStore;
import dev.sigstore.tuf.HttpFetcher;
import dev.sigstore.tuf.MetaFetcher;
import dev.sigstore.tuf.PassthroughCacheMetaStore;
import dev.sigstore.tuf.RootProvider;
import dev.sigstore.tuf.TrustedMetaStore;
import dev.sigstore.tuf.Updater;
import java.util.concurrent.Callable;
import picocli.CommandLine.Command;
import picocli.CommandLine.ParentCommand;

@Command(name = "refresh", description = "update local tuf metadata from the repository")
public class Refresh implements Callable<Integer> {

@ParentCommand private Tuf tufCommand;

@Override
public Integer call() throws Exception {
var metadataDir = tufCommand.getMetadataDir();
var metadataUrl = tufCommand.getMetadataUrl();

var fsStore = FileSystemTufStore.newFileSystemStore(metadataDir);
var tuf =
Updater.builder()
.setTrustedMetaStore(
TrustedMetaStore.newTrustedMetaStore(
PassthroughCacheMetaStore.newPassthroughMetaCache(fsStore)))
.setTrustedRootPath(RootProvider.fromFile(metadataDir.resolve("root.json")))
.setMetaFetcher(MetaFetcher.newFetcher(HttpFetcher.newFetcher(metadataUrl)))
.build();
tuf.update();
return 0;
}
}
Loading

0 comments on commit 58b5d85

Please sign in to comment.