Skip to content

Commit e887c23

Browse files
authored
Merge pull request #854 from sigstore/more_tuf_tests
Add tests for downloadTarget
2 parents abd0524 + ecfcccd commit e887c23

File tree

9 files changed

+91
-40
lines changed

9 files changed

+91
-40
lines changed

sigstore-java/src/main/java/dev/sigstore/tuf/FileSystemTufStore.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
public class FileSystemTufStore implements MetaStore, TargetStore {
3232

3333
private final Path repoBaseDir;
34-
private final Path targetsCache;
34+
private final Path targetsDir;
3535

3636
@VisibleForTesting
37-
FileSystemTufStore(Path repoBaseDir, Path targetsCache) {
37+
FileSystemTufStore(Path repoBaseDir, Path targetsDir) {
3838
this.repoBaseDir = repoBaseDir;
39-
this.targetsCache = targetsCache;
39+
this.targetsDir = targetsDir;
4040
}
4141

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

6363
@Override
6464
public String getIdentifier() {
65-
return "Meta: " + repoBaseDir.toAbsolutePath() + ", Targets:" + targetsCache.toAbsolutePath();
65+
return "Meta: " + repoBaseDir.toAbsolutePath() + ", Targets:" + targetsDir.toAbsolutePath();
6666
}
6767

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

7474
@Override
7575
public byte[] readTarget(String targetName) throws IOException {
7676
var encoded = URLEncoder.encode(targetName, StandardCharsets.UTF_8);
77-
return Files.readAllBytes(targetsCache.resolve(encoded));
77+
return Files.readAllBytes(targetsDir.resolve(encoded));
7878
}
7979

8080
@Override
@@ -106,4 +106,12 @@ public void clearMeta(String role) throws IOException {
106106
Files.delete(metaFile);
107107
}
108108
}
109+
110+
public Path getRepoBaseDir() {
111+
return repoBaseDir;
112+
}
113+
114+
public Path getTargetsDir() {
115+
return targetsDir;
116+
}
109117
}

sigstore-java/src/test/java/dev/sigstore/tuf/UpdaterTest.java

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,11 @@
4343
import io.github.netmikey.logunit.api.LogCapturer;
4444
import java.io.File;
4545
import java.io.IOException;
46+
import java.io.UncheckedIOException;
4647
import java.net.URL;
4748
import java.nio.charset.StandardCharsets;
4849
import java.nio.file.Files;
4950
import java.nio.file.Path;
50-
import java.security.InvalidKeyException;
51-
import java.security.NoSuchAlgorithmException;
52-
import java.security.spec.InvalidKeySpecException;
5351
import java.time.Clock;
5452
import java.time.Instant;
5553
import java.time.ZoneOffset;
@@ -119,8 +117,7 @@ static void startRemoteResourceServer() throws Exception {
119117
}
120118

121119
@Test
122-
public void testRootUpdate_notEnoughSignatures()
123-
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
120+
public void testRootUpdate_notEnoughSignatures() throws Exception {
124121
setupMirror("synthetic/root-unsigned", "2.root.json");
125122
var updater = createTimeStaticUpdater(localStorePath, UPDATER_SYNTHETIC_TRUSTED_ROOT);
126123
try {
@@ -453,8 +450,7 @@ public void testTargetsUpdate_targetExpired() throws Exception {
453450
}
454451

455452
@Test
456-
public void testTargetsUpdate_success()
457-
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
453+
public void testTargetsUpdate_success() throws Exception {
458454
setupMirror(
459455
"synthetic/test-template",
460456
"2.root.json",
@@ -495,8 +491,7 @@ public void testTargetsDownload_targetMissingTargetMetadata() throws Exception {
495491
}
496492

497493
@Test
498-
public void testTargetsDownload_targetFileNotFound()
499-
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
494+
public void testTargetsDownload_targetFileNotFound() throws Exception {
500495
setupMirror(
501496
"synthetic/test-template",
502497
"2.root.json",
@@ -512,8 +507,7 @@ public void testTargetsDownload_targetFileNotFound()
512507
}
513508

514509
@Test
515-
public void testTargetsDownload_targetInvalidLength()
516-
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
510+
public void testTargetsDownload_targetInvalidLength() throws Exception {
517511
setupMirror(
518512
"synthetic/targets-download-invalid-length",
519513
"2.root.json",
@@ -530,8 +524,7 @@ public void testTargetsDownload_targetInvalidLength()
530524
}
531525

532526
@Test
533-
public void testTargetsDownload_targetFileInvalidHash()
534-
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
527+
public void testTargetsDownload_targetFileInvalidHash() throws Exception {
535528
setupMirror(
536529
"synthetic/targets-download-invalid-hash",
537530
"2.root.json",
@@ -585,6 +578,53 @@ public void testTargetsDownload_sha256Only() throws Exception {
585578
assertDoesNotThrow(updater::update);
586579
}
587580

581+
@Test
582+
public void testDownloadTarget_singleTarget() throws Exception {
583+
setupMirror(
584+
"synthetic/test-template",
585+
"2.root.json",
586+
"timestamp.json",
587+
"3.snapshot.json",
588+
"3.targets.json",
589+
"targets/860de8f9a858eea7190fcfa1b53fe55914d3c38f17f8f542273012d19cc9509bb423f37b7c13c577a56339ad7f45273b479b1d0df837cb6e20a550c27cce0885.test.txt",
590+
"targets/32005f02eac21b4cf161a02495330b6c14b548622b5f7e19d59ecfa622de650603ecceea39ed86cc322749a813503a72ad14ce5462c822b511eaf2f2cd2ad8f2.test.txt.v2",
591+
"targets/53904bc6216230bf8da0ec42d34004a3f36764de698638641870e37d270e4fd13e1079285f8bca73c2857a279f6f7fbc82038274c3eb48ec5bb2da9b2e30491a.test2.txt");
592+
var updater = createTimeStaticUpdater(localStorePath, UPDATER_SYNTHETIC_TRUSTED_ROOT);
593+
updater.updateMeta();
594+
updater.downloadTarget("test.txt");
595+
Assertions.assertEquals(1, countFilesInTargetsDir(updater));
596+
updater.downloadTarget("test2.txt");
597+
Assertions.assertEquals(2, countFilesInTargetsDir(updater));
598+
}
599+
600+
@Test
601+
public void testDownloadTarget_inSubDirectory() throws Exception {
602+
var root =
603+
Path.of(
604+
Resources.getResource("dev/sigstore/tuf/synthetic/targets-with-subdirs/root.json")
605+
.getPath());
606+
setupMirror(
607+
"synthetic/targets-with-subdirs",
608+
"1.root.json",
609+
"timestamp.json",
610+
"1.snapshot.json",
611+
"1.targets.json",
612+
"targets/subdir/860de8f9a858eea7190fcfa1b53fe55914d3c38f17f8f542273012d19cc9509bb423f37b7c13c577a56339ad7f45273b479b1d0df837cb6e20a550c27cce0885.test.txt");
613+
var updater = createTimeStaticUpdater(localStorePath, root);
614+
updater.updateMeta();
615+
updater.downloadTarget("subdir/test.txt");
616+
Assertions.assertEquals(1, countFilesInTargetsDir(updater));
617+
}
618+
619+
private long countFilesInTargetsDir(Updater updater) throws IOException {
620+
try (var filesStream =
621+
Files.list(((FileSystemTufStore) updater.getTargetStore()).getTargetsDir())) {
622+
return filesStream.count();
623+
} catch (UncheckedIOException ex) {
624+
throw ex.getCause();
625+
}
626+
}
627+
588628
private static final byte[] TEST_HASH_VERIFYIER_BYTES =
589629
"testdata".getBytes(StandardCharsets.UTF_8);
590630
private static final String GOOD_256_HASH =
@@ -737,8 +777,7 @@ private void bootstrapLocalStore(
737777
"04cc1cd53a61c23e88cc54b488dfae168a257c34fac3e88811c55962b24cffbfecb724447999c54670e365883716302e49da57c79a33cd3e16f81fbc66f0bcdf48"));
738778

739779
@Test
740-
public void testVerifyDelegate_verified()
741-
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException {
780+
public void testVerifyDelegate_verified() throws Exception {
742781
List<Signature> sigs = ImmutableList.of(SIG_1, SIG_2);
743782

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

801840
// Just testing boundary conditions for iteration bugs.
802841
@Test
803-
public void testVerifyDelegate_emptyLists()
804-
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException {
842+
public void testVerifyDelegate_emptyLists() throws Exception {
805843
List<Signature> sigs = ImmutableList.of();
806844

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

823861
@Test
824-
public void testVerifyDelegate_goodSigsAndKeysButNotInRole()
825-
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IOException {
862+
public void testVerifyDelegate_goodSigsAndKeysButNotInRole() throws Exception {
826863
List<Signature> sigs = ImmutableList.of(SIG_1, SIG_2);
827864

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

934-
private void assertRootNotExpired(Root root) {
935-
assertTrue(
936-
root.getSignedMeta()
937-
.getExpiresAsDate()
938-
.isAfter(ZonedDateTime.parse(TEST_STATIC_UPDATE_TIME)),
939-
"The root should not be expired passed test static update time: "
940-
+ TEST_STATIC_UPDATE_TIME);
941-
}
942-
943-
private void assertRootVersionIncreased(Root oldRoot, Root newRoot) throws IOException {
944-
assertTrue(
945-
oldRoot.getSignedMeta().getVersion() <= newRoot.getSignedMeta().getVersion(),
946-
"The new root version should be higher than the old root.");
947-
}
948-
949971
private void assertStoreContains(String resource) {
950972
assertTrue(
951973
localStorePath.resolve(resource).toFile().exists(),
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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"}]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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"}]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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"}]}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Setup test data
2+
3+
```shell
4+
tuf init
5+
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" root
6+
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" targets
7+
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" snapshot
8+
tuf gen-key --expires=90 --scheme="ecdsa-sha2-nistp256" timestamp
9+
mkdir -p staged/targets/subdir
10+
echo "test file" > staged/targets/subdir/test.txt
11+
tuf add "subdir/test.txt"
12+
tuf snapshot --expires=60
13+
tuf timestamp --expires=30
14+
tuf commit
15+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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"}]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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"}]}

0 commit comments

Comments
 (0)