Skip to content

Commit 9b0a6e7

Browse files
doanacclaude
andcommitted
keys: Add "fioctl keys tuf download-roots" command
Downloads all versions of a Factory's TUF root.json files (CI or, with --prod, production) into a single gzip'd tarball, incrementing the version until the server returns a 404. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Andy Doan <andy@foundries.io>
1 parent c5aa8ab commit 9b0a6e7

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

‎client/foundries_tuf_root.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ func (a *Api) TufProdRootGet(factory string) (*AtsTufRoot, error) {
121121
return a.tufRootGet(factory, true, -1)
122122
}
123123

124+
func (a *Api) TufProdRootGetVer(factory string, version int) (*AtsTufRoot, error) {
125+
return a.tufRootGet(factory, true, version)
126+
}
127+
124128
func (a *Api) TufRootPost(factory string, root []byte) (string, error) {
125129
return a.tufRootPost(factory, false, root)
126130
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package keys
2+
3+
import (
4+
"archive/tar"
5+
"compress/gzip"
6+
"fmt"
7+
"os"
8+
9+
canonical "github.com/docker/go/canonical/json"
10+
"github.com/spf13/cobra"
11+
"github.com/spf13/viper"
12+
13+
"github.com/foundriesio/fioctl/client"
14+
"github.com/foundriesio/fioctl/subcommands"
15+
)
16+
17+
func init() {
18+
downloadRoots := &cobra.Command{
19+
Use: "download-roots <archive path>",
20+
Short: "Download all versions of the Factory's TUF root metadata into a tarball",
21+
Run: doDownloadRoots,
22+
Args: cobra.ExactArgs(1),
23+
}
24+
downloadRoots.Flags().BoolP("prod", "", false, "Download the production versions")
25+
tufCmd.AddCommand(downloadRoots)
26+
}
27+
28+
func doDownloadRoots(cmd *cobra.Command, args []string) {
29+
factory := viper.GetString("factory")
30+
prod, _ := cmd.Flags().GetBool("prod")
31+
dstPath := args[0]
32+
33+
var getRoot func(factory string, version int) (*client.AtsTufRoot, error)
34+
if prod {
35+
getRoot = api.TufProdRootGetVer
36+
} else {
37+
getRoot = api.TufRootGetVer
38+
}
39+
40+
file, err := os.Create(dstPath)
41+
subcommands.DieNotNil(err)
42+
defer file.Close()
43+
44+
gzipWriter := gzip.NewWriter(file)
45+
defer gzipWriter.Close()
46+
47+
tarWriter := tar.NewWriter(gzipWriter)
48+
defer tarWriter.Close()
49+
50+
for ver := 1; ; ver++ {
51+
var root *client.AtsTufRoot
52+
root, err = getRoot(factory, ver)
53+
if err != nil {
54+
if herr := client.AsHttpError(err); herr != nil && herr.Response.StatusCode == 404 {
55+
break
56+
}
57+
subcommands.DieNotNil(err)
58+
}
59+
60+
bytes, err := canonical.MarshalCanonical(root)
61+
subcommands.DieNotNil(err)
62+
63+
fmt.Printf("= Adding %d.root.json\n", ver)
64+
header := &tar.Header{
65+
Name: fmt.Sprintf("%d.root.json", ver),
66+
Size: int64(len(bytes)),
67+
Mode: 0644,
68+
}
69+
subcommands.DieNotNil(tarWriter.WriteHeader(header))
70+
_, err = tarWriter.Write(bytes)
71+
subcommands.DieNotNil(err)
72+
}
73+
}

0 commit comments

Comments
 (0)