Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for downloadTarget #854

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
public class FileSystemTufStore implements MetaStore, TargetStore {

private final Path repoBaseDir;
private final Path targetsCache;
private final Path targetsDir;

@VisibleForTesting
FileSystemTufStore(Path repoBaseDir, Path targetsCache) {
FileSystemTufStore(Path repoBaseDir, Path targetsDir) {
this.repoBaseDir = repoBaseDir;
this.targetsCache = targetsCache;
this.targetsDir = targetsDir;
}

public static FileSystemTufStore newFileSystemStore(Path repoBaseDir) throws IOException {
Expand All @@ -62,19 +62,19 @@ public static FileSystemTufStore newFileSystemStore(Path repoBaseDir, Path targe

@Override
public String getIdentifier() {
return "Meta: " + repoBaseDir.toAbsolutePath() + ", Targets:" + targetsCache.toAbsolutePath();
return "Meta: " + repoBaseDir.toAbsolutePath() + ", Targets:" + targetsDir.toAbsolutePath();
}

@Override
public void writeTarget(String targetName, byte[] targetContents) throws IOException {
var encoded = URLEncoder.encode(targetName, StandardCharsets.UTF_8);
Files.write(targetsCache.resolve(encoded), targetContents);
Files.write(targetsDir.resolve(encoded), targetContents);
}

@Override
public byte[] readTarget(String targetName) throws IOException {
var encoded = URLEncoder.encode(targetName, StandardCharsets.UTF_8);
return Files.readAllBytes(targetsCache.resolve(encoded));
return Files.readAllBytes(targetsDir.resolve(encoded));
}

@Override
Expand Down Expand Up @@ -106,4 +106,12 @@ public void clearMeta(String role) throws IOException {
Files.delete(metaFile);
}
}

public Path getRepoBaseDir() {
return repoBaseDir;
}

public Path getTargetsDir() {
return targetsDir;
}
}
90 changes: 56 additions & 34 deletions sigstore-java/src/test/java/dev/sigstore/tuf/UpdaterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,11 @@
import io.github.netmikey.logunit.api.LogCapturer;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;
Expand Down Expand Up @@ -119,8 +117,7 @@ static void startRemoteResourceServer() throws Exception {
}

@Test
public void testRootUpdate_notEnoughSignatures()
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
public void testRootUpdate_notEnoughSignatures() throws Exception {
setupMirror("synthetic/root-unsigned", "2.root.json");
var updater = createTimeStaticUpdater(localStorePath, UPDATER_SYNTHETIC_TRUSTED_ROOT);
try {
Expand Down Expand Up @@ -453,8 +450,7 @@ public void testTargetsUpdate_targetExpired() throws Exception {
}

@Test
public void testTargetsUpdate_success()
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
public void testTargetsUpdate_success() throws Exception {
setupMirror(
"synthetic/test-template",
"2.root.json",
Expand Down Expand Up @@ -495,8 +491,7 @@ public void testTargetsDownload_targetMissingTargetMetadata() throws Exception {
}

@Test
public void testTargetsDownload_targetFileNotFound()
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
public void testTargetsDownload_targetFileNotFound() throws Exception {
setupMirror(
"synthetic/test-template",
"2.root.json",
Expand All @@ -512,8 +507,7 @@ public void testTargetsDownload_targetFileNotFound()
}

@Test
public void testTargetsDownload_targetInvalidLength()
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
public void testTargetsDownload_targetInvalidLength() throws Exception {
setupMirror(
"synthetic/targets-download-invalid-length",
"2.root.json",
Expand All @@ -530,8 +524,7 @@ public void testTargetsDownload_targetInvalidLength()
}

@Test
public void testTargetsDownload_targetFileInvalidHash()
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
public void testTargetsDownload_targetFileInvalidHash() throws Exception {
setupMirror(
"synthetic/targets-download-invalid-hash",
"2.root.json",
Expand Down Expand Up @@ -585,6 +578,53 @@ public void testTargetsDownload_sha256Only() throws Exception {
assertDoesNotThrow(updater::update);
}

@Test
public void testDownloadTarget_singleTarget() throws Exception {
setupMirror(
"synthetic/test-template",
"2.root.json",
"timestamp.json",
"3.snapshot.json",
"3.targets.json",
"targets/860de8f9a858eea7190fcfa1b53fe55914d3c38f17f8f542273012d19cc9509bb423f37b7c13c577a56339ad7f45273b479b1d0df837cb6e20a550c27cce0885.test.txt",
"targets/32005f02eac21b4cf161a02495330b6c14b548622b5f7e19d59ecfa622de650603ecceea39ed86cc322749a813503a72ad14ce5462c822b511eaf2f2cd2ad8f2.test.txt.v2",
"targets/53904bc6216230bf8da0ec42d34004a3f36764de698638641870e37d270e4fd13e1079285f8bca73c2857a279f6f7fbc82038274c3eb48ec5bb2da9b2e30491a.test2.txt");
var updater = createTimeStaticUpdater(localStorePath, UPDATER_SYNTHETIC_TRUSTED_ROOT);
updater.updateMeta();
updater.downloadTarget("test.txt");
Assertions.assertEquals(1, countFilesInTargetsDir(updater));
updater.downloadTarget("test2.txt");
Assertions.assertEquals(2, countFilesInTargetsDir(updater));
}

@Test
public void testDownloadTarget_inSubDirectory() throws Exception {
var root =
Path.of(
Resources.getResource("dev/sigstore/tuf/synthetic/targets-with-subdirs/root.json")
.getPath());
setupMirror(
"synthetic/targets-with-subdirs",
"1.root.json",
"timestamp.json",
"1.snapshot.json",
"1.targets.json",
"targets/subdir/860de8f9a858eea7190fcfa1b53fe55914d3c38f17f8f542273012d19cc9509bb423f37b7c13c577a56339ad7f45273b479b1d0df837cb6e20a550c27cce0885.test.txt");
var updater = createTimeStaticUpdater(localStorePath, root);
updater.updateMeta();
updater.downloadTarget("subdir/test.txt");
Assertions.assertEquals(1, countFilesInTargetsDir(updater));
}

private long countFilesInTargetsDir(Updater updater) throws IOException {
try (var filesStream =
Files.list(((FileSystemTufStore) updater.getTargetStore()).getTargetsDir())) {
return filesStream.count();
} catch (UncheckedIOException ex) {
throw ex.getCause();
}
}

private static final byte[] TEST_HASH_VERIFYIER_BYTES =
"testdata".getBytes(StandardCharsets.UTF_8);
private static final String GOOD_256_HASH =
Expand Down Expand Up @@ -737,8 +777,7 @@ private void bootstrapLocalStore(
"04cc1cd53a61c23e88cc54b488dfae168a257c34fac3e88811c55962b24cffbfecb724447999c54670e365883716302e49da57c79a33cd3e16f81fbc66f0bcdf48"));

@Test
public void testVerifyDelegate_verified()
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException {
public void testVerifyDelegate_verified() throws Exception {
List<Signature> sigs = ImmutableList.of(SIG_1, SIG_2);

Map<String, Key> publicKeys =
Expand Down Expand Up @@ -800,8 +839,7 @@ public void testVerifyDelegate_belowThreshold() throws Exception {

// Just testing boundary conditions for iteration bugs.
@Test
public void testVerifyDelegate_emptyLists()
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException {
public void testVerifyDelegate_emptyLists() throws Exception {
List<Signature> sigs = ImmutableList.of();

Map<String, Key> publicKeys = ImmutableMap.of();
Expand All @@ -821,8 +859,7 @@ public void testVerifyDelegate_emptyLists()
}

@Test
public void testVerifyDelegate_goodSigsAndKeysButNotInRole()
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException {
public void testVerifyDelegate_goodSigsAndKeysButNotInRole() throws Exception {
List<Signature> sigs = ImmutableList.of(SIG_1, SIG_2);

Map<String, Key> publicKeys =
Expand Down Expand Up @@ -931,21 +968,6 @@ private static void setupMirror(String repoName, String... files) throws IOExcep
TestResources.setupRepoFiles(repoName, localMirrorPath, files);
}

private void assertRootNotExpired(Root root) {
assertTrue(
root.getSignedMeta()
.getExpiresAsDate()
.isAfter(ZonedDateTime.parse(TEST_STATIC_UPDATE_TIME)),
"The root should not be expired passed test static update time: "
+ TEST_STATIC_UPDATE_TIME);
}

private void assertRootVersionIncreased(Root oldRoot, Root newRoot) throws IOException {
assertTrue(
oldRoot.getSignedMeta().getVersion() <= newRoot.getSignedMeta().getVersion(),
"The new root version should be higher than the old root.");
}

private void assertStoreContains(String resource) {
assertTrue(
localStorePath.resolve(resource).toFile().exists(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"signed":{"_type":"root","spec_version":"1.0","version":1,"expires":"2025-02-18T18:35:54Z","keys":{"32ebeea523ee901ac346018dc416e153e399a9c5a337c9197e55962bf75884db":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5RfvOGyg9WsH7ss0fLE/ugmvIFIa\nzpHIEPhk4m2WPG1UVrxgIZVJQdIqOwEx9dRGVIJJb3mKBIYv4VKMBCUgfg==\n-----END PUBLIC KEY-----\n"}},"3332a046bd204e13b3c749c87179351a5b5fbf20735b37137d9694835a846c42":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEK9TCGwshxW1d+pPkHt9pMLab9AZZ\n2ovDuLHI561zAhgh+5PxPvCSZc/KVzFXK854qltuh2nhVgoAJya40p6yew==\n-----END PUBLIC KEY-----\n"}},"54461f997d405cd03a912649b306f349412dc9ef2e475a89a1f18981e1a2cf5e":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPcRd5DQoGtZIEPgzUnrIHPeMUpb0\nDG4HepKiiFavuZ43kPBMl77XEXP3Fmvj650uahsqLnhrjIljkQEra41waw==\n-----END PUBLIC KEY-----\n"}},"97b9f13f07972ce34e386ca1fc74fa1f293ca9b1b23c23b1da178a31e8b77d0b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsoSjUEAYDjgUt4jikGNdUN9bVWSz\nTCohcyDKwCCDr1rfStHF8m8ommeFfiTyYtTGdNGtdyMv4wsqLs+CVFXXKg==\n-----END PUBLIC KEY-----\n"}},"f944fd2f09223b2d8a7f7673bb31f625ed12026fb6d2a4c251a3cfd6e43f9119":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEToq4xkfD1+vpPCyeAft/GKmNOb5J\nQzBiNnle6envv61RXZ0+Zv+6RLL/GpMYJ3GQnDwz3vQ2KTT2SNbtiHlWiA==\n-----END PUBLIC KEY-----\n"}}},"roles":{"root":{"keyids":["32ebeea523ee901ac346018dc416e153e399a9c5a337c9197e55962bf75884db","54461f997d405cd03a912649b306f349412dc9ef2e475a89a1f18981e1a2cf5e"],"threshold":1},"snapshot":{"keyids":["f944fd2f09223b2d8a7f7673bb31f625ed12026fb6d2a4c251a3cfd6e43f9119"],"threshold":1},"targets":{"keyids":["97b9f13f07972ce34e386ca1fc74fa1f293ca9b1b23c23b1da178a31e8b77d0b"],"threshold":1},"timestamp":{"keyids":["3332a046bd204e13b3c749c87179351a5b5fbf20735b37137d9694835a846c42"],"threshold":1}},"consistent_snapshot":true},"signatures":[{"keyid":"32ebeea523ee901ac346018dc416e153e399a9c5a337c9197e55962bf75884db","sig":"3045022100cd1606f8a435c67277ba5afc61d7c48a2cf5c3f9433a3547fc4a8a3228711d50022047492c1bb08cb999c8525536e2822ac46a44bd69c91217655499814012ff3f1a"},{"keyid":"54461f997d405cd03a912649b306f349412dc9ef2e475a89a1f18981e1a2cf5e","sig":"304502205a37d21f635b8616dfeb0fd65459896efc13b2de9442b9fc5a8279696c0acc0d022100996988b3f2e26bc2fe352d89162a532e81123c6be4f7bfcf72300898d845c547"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"signed":{"_type":"snapshot","spec_version":"1.0","version":1,"expires":"2025-01-19T18:36:49Z","meta":{"targets.json":{"length":532,"hashes":{"sha512":"53d5256dd4926de0b79662f0d911ed42a2dd19c6480bce690199ac2eec9228aa97f5e3709746ef615d6dd758115d221790bbc7e4976907f62fc742a7406a0062"},"version":1}}},"signatures":[{"keyid":"f944fd2f09223b2d8a7f7673bb31f625ed12026fb6d2a4c251a3cfd6e43f9119","sig":"3046022100cfdb316b9407245c20f3b4ebe24cbc524e5324e1ceadd7ba0298384d8218ec76022100a596bc5912fa9a78fab28223d5bb36b7667dfa3ca5f63017eddcf9b427990b24"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"signed":{"_type":"targets","spec_version":"1.0","version":1,"expires":"2025-02-20T18:36:39Z","targets":{"subdir/test.txt":{"length":10,"hashes":{"sha512":"860de8f9a858eea7190fcfa1b53fe55914d3c38f17f8f542273012d19cc9509bb423f37b7c13c577a56339ad7f45273b479b1d0df837cb6e20a550c27cce0885"}}}},"signatures":[{"keyid":"97b9f13f07972ce34e386ca1fc74fa1f293ca9b1b23c23b1da178a31e8b77d0b","sig":"304402206393d229300c00882ee9e0d20a4364b554a76f8fc744cf1a5d042867946b2e05022029c8b3c4288cbdc585bb900e16236e95307050f611ea8e9261c4980aa8830ec0"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Setup test data

```shell
tuf init
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" root
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" targets
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" snapshot
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" timestamp
mkdir -p staged/targets/subdir
echo "test file" > staged/targets/subdir/test.txt
tuf add "subdir/test.txt"
tuf snapshot --expires=60
tuf timestamp --expires=30
tuf commit
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"signed":{"_type":"root","spec_version":"1.0","version":1,"expires":"2025-02-18T18:35:54Z","keys":{"32ebeea523ee901ac346018dc416e153e399a9c5a337c9197e55962bf75884db":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5RfvOGyg9WsH7ss0fLE/ugmvIFIa\nzpHIEPhk4m2WPG1UVrxgIZVJQdIqOwEx9dRGVIJJb3mKBIYv4VKMBCUgfg==\n-----END PUBLIC KEY-----\n"}},"3332a046bd204e13b3c749c87179351a5b5fbf20735b37137d9694835a846c42":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEK9TCGwshxW1d+pPkHt9pMLab9AZZ\n2ovDuLHI561zAhgh+5PxPvCSZc/KVzFXK854qltuh2nhVgoAJya40p6yew==\n-----END PUBLIC KEY-----\n"}},"54461f997d405cd03a912649b306f349412dc9ef2e475a89a1f18981e1a2cf5e":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPcRd5DQoGtZIEPgzUnrIHPeMUpb0\nDG4HepKiiFavuZ43kPBMl77XEXP3Fmvj650uahsqLnhrjIljkQEra41waw==\n-----END PUBLIC KEY-----\n"}},"97b9f13f07972ce34e386ca1fc74fa1f293ca9b1b23c23b1da178a31e8b77d0b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsoSjUEAYDjgUt4jikGNdUN9bVWSz\nTCohcyDKwCCDr1rfStHF8m8ommeFfiTyYtTGdNGtdyMv4wsqLs+CVFXXKg==\n-----END PUBLIC KEY-----\n"}},"f944fd2f09223b2d8a7f7673bb31f625ed12026fb6d2a4c251a3cfd6e43f9119":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEToq4xkfD1+vpPCyeAft/GKmNOb5J\nQzBiNnle6envv61RXZ0+Zv+6RLL/GpMYJ3GQnDwz3vQ2KTT2SNbtiHlWiA==\n-----END PUBLIC KEY-----\n"}}},"roles":{"root":{"keyids":["32ebeea523ee901ac346018dc416e153e399a9c5a337c9197e55962bf75884db","54461f997d405cd03a912649b306f349412dc9ef2e475a89a1f18981e1a2cf5e"],"threshold":1},"snapshot":{"keyids":["f944fd2f09223b2d8a7f7673bb31f625ed12026fb6d2a4c251a3cfd6e43f9119"],"threshold":1},"targets":{"keyids":["97b9f13f07972ce34e386ca1fc74fa1f293ca9b1b23c23b1da178a31e8b77d0b"],"threshold":1},"timestamp":{"keyids":["3332a046bd204e13b3c749c87179351a5b5fbf20735b37137d9694835a846c42"],"threshold":1}},"consistent_snapshot":true},"signatures":[{"keyid":"32ebeea523ee901ac346018dc416e153e399a9c5a337c9197e55962bf75884db","sig":"3045022100cd1606f8a435c67277ba5afc61d7c48a2cf5c3f9433a3547fc4a8a3228711d50022047492c1bb08cb999c8525536e2822ac46a44bd69c91217655499814012ff3f1a"},{"keyid":"54461f997d405cd03a912649b306f349412dc9ef2e475a89a1f18981e1a2cf5e","sig":"304502205a37d21f635b8616dfeb0fd65459896efc13b2de9442b9fc5a8279696c0acc0d022100996988b3f2e26bc2fe352d89162a532e81123c6be4f7bfcf72300898d845c547"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"signed":{"_type":"timestamp","spec_version":"1.0","version":1,"expires":"2024-12-20T18:36:58Z","meta":{"snapshot.json":{"length":544,"hashes":{"sha512":"4467bf790a07dc4220baac68918d6f1bb7f6cb2a2f2663436e5817f3800ddbdc9c18b33e0a869e66eee523f9b3745799db9c7753393378fd3387ce5d74c5c3b0"},"version":1}}},"signatures":[{"keyid":"3332a046bd204e13b3c749c87179351a5b5fbf20735b37137d9694835a846c42","sig":"30450220386af40c0096bc8c7e9a5397ccd79de0ef40b04ab63f7c1c1243a9ea247e34d50221008767dabffb2022c732e7a9874a2f48bd1073c0a6cbcf86a1d6f604130f12f1d1"}]}
Loading