chore: vendor

This commit is contained in:
2024-08-04 11:06:58 +02:00
parent 2a5985e44e
commit 04aec8232f
3557 changed files with 981078 additions and 1 deletions
.gitignore
vendor
coopcloud.tech
dario.cat
git.coopcloud.tech
github.com
AlecAivazis
Azure
BurntSushi
Microsoft
ProtonMail
aymanbagabas
beorn7
cenkalti
cespare
charmbracelet
cloudflare
containerd
containers
cpuguy83
cyphar
davecgh
decentral1se
distribution
docker
cli
AUTHORSLICENSENOTICE
cli-plugins
cli
cobra.go
command
compose
config
connhelper
context
debug
error.go
flags
hints
manifest
registry
required.go
streams
trust
version
opts
templates
distribution
docker-credential-helpers
docker
AUTHORSLICENSENOTICE
api
client
README.mdbuild_cancel.gobuild_prune.gocheckpoint_create.gocheckpoint_delete.gocheckpoint_list.goclient.goclient_deprecated.goclient_unix.goclient_windows.goconfig_create.goconfig_inspect.goconfig_list.goconfig_remove.goconfig_update.gocontainer_attach.gocontainer_commit.gocontainer_copy.gocontainer_create.gocontainer_diff.gocontainer_exec.gocontainer_export.gocontainer_inspect.gocontainer_kill.gocontainer_list.gocontainer_logs.gocontainer_pause.gocontainer_prune.gocontainer_remove.gocontainer_rename.gocontainer_resize.gocontainer_restart.gocontainer_start.gocontainer_stats.gocontainer_stop.gocontainer_top.gocontainer_unpause.gocontainer_update.gocontainer_wait.godisk_usage.godistribution_inspect.goenvvars.goerrors.goevents.gohijack.goimage_build.goimage_create.goimage_history.goimage_import.goimage_inspect.goimage_list.goimage_load.goimage_prune.goimage_pull.goimage_push.goimage_remove.goimage_save.goimage_search.goimage_tag.goinfo.gointerface.gointerface_experimental.gointerface_stable.gologin.gonetwork_connect.gonetwork_create.gonetwork_disconnect.gonetwork_inspect.gonetwork_list.gonetwork_prune.gonetwork_remove.gonode_inspect.gonode_list.gonode_remove.gonode_update.gooptions.goping.goplugin_create.goplugin_disable.goplugin_enable.goplugin_inspect.goplugin_install.goplugin_list.goplugin_push.goplugin_remove.goplugin_set.goplugin_upgrade.gorequest.gosecret_create.gosecret_inspect.gosecret_list.gosecret_remove.gosecret_update.goservice_create.goservice_inspect.goservice_list.goservice_logs.goservice_remove.goservice_update.goswarm_get_unlock_key.goswarm_init.goswarm_inspect.goswarm_join.goswarm_leave.goswarm_unlock.goswarm_update.gotask_inspect.gotask_list.gotask_logs.goutils.goversion.govolume_create.govolume_inspect.govolume_list.govolume_prune.govolume_remove.govolume_update.go
errdefs
internal
multierror
pkg
registry
go-connections
go-metrics
go-units
go
libtrust
emirpasic
felixge
fvbommel
ghodss
go-git
gcfg
go-billy
go-git
v5
.gitignoreCODE_OF_CONDUCT.mdCOMPATIBILITY.mdCONTRIBUTING.mdEXTENDING.mdLICENSEMakefileREADME.mdSECURITY.mdblame.gocommon.go
config
doc.go
internal
object_walker.gooptions.gooss-fuzz.sh
plumbing
prune.goremote.gorepository.gosigner.gostatus.go
storage
submodule.go
utils
worktree.goworktree_bsd.goworktree_commit.goworktree_js.goworktree_linux.goworktree_plan9.goworktree_status.goworktree_unix_other.goworktree_windows.go
go-logfmt
go-logr
go-viper
gogo
golang
groupcache
google
gorilla
grpc-ecosystem
hashicorp
inconshreveable
jbenet
go-context
kballard
kevinburke
klauspost
lucasb-eyer
mattn
mgutz
miekg
mitchellh
moby
morikuni
muesli
munnerz
opencontainers
pjbgf
pkg
pmezard
go-difflib
prometheus
client_golang
client_model
common
procfs
rivo
russross
schollz
sergi
sirupsen
skeema
spf13
stretchr
theupdateframework
urfave
xanzy
xeipuuv
go.opentelemetry.io
contrib
otel
.codespellignore.codespellrc.gitattributes.gitignore.golangci.yml.lycheeignore.markdownlint.yamlCHANGELOG.mdCODEOWNERSCONTRIBUTING.mdLICENSEMakefileREADME.mdRELEASING.mdVERSIONING.md
attribute
baggage
codes
doc.goerror_handler.go
exporters
get_main_pkgs.shhandler.go
internal
internal_logging.gometric.go
metric
propagation.go
propagation
renovate.jsonrequirements.txt
sdk
semconv
trace.go
trace
verify_examples.shverify_readmes.shversion.goversions.yaml
proto
golang.org
x
crypto
exp
net
sync
sys
LICENSEPATENTS
cpu
execabs
plan9
unix
.gitignoreREADME.mdaffinity_linux.goaliases.goasm_aix_ppc64.sasm_bsd_386.sasm_bsd_amd64.sasm_bsd_arm.sasm_bsd_arm64.sasm_bsd_ppc64.sasm_bsd_riscv64.sasm_linux_386.sasm_linux_amd64.sasm_linux_arm.sasm_linux_arm64.sasm_linux_loong64.sasm_linux_mips64x.sasm_linux_mipsx.sasm_linux_ppc64x.sasm_linux_riscv64.sasm_linux_s390x.sasm_openbsd_mips64.sasm_solaris_amd64.sasm_zos_s390x.sbluetooth_linux.gobpxsvc_zos.gobpxsvc_zos.scap_freebsd.goconstants.godev_aix_ppc.godev_aix_ppc64.godev_darwin.godev_dragonfly.godev_freebsd.godev_linux.godev_netbsd.godev_openbsd.godev_zos.godirent.goendian_big.goendian_little.goenv_unix.gofcntl.gofcntl_darwin.gofcntl_linux_32bit.gofdset.gogccgo.gogccgo_c.cgccgo_linux_amd64.goifreq_linux.goioctl_linux.goioctl_signed.goioctl_unsigned.goioctl_zos.gomkall.shmkerrors.shmmap_nomremap.gomremap.gopagesize_unix.gopledge_openbsd.goptrace_darwin.goptrace_ios.gorace.gorace0.goreaddirent_getdents.goreaddirent_getdirentries.gosockcmsg_dragonfly.gosockcmsg_linux.gosockcmsg_unix.gosockcmsg_unix_other.gosockcmsg_zos.gosymaddr_zos_s390x.ssyscall.gosyscall_aix.gosyscall_aix_ppc.gosyscall_aix_ppc64.gosyscall_bsd.gosyscall_darwin.gosyscall_darwin_amd64.gosyscall_darwin_arm64.gosyscall_darwin_libSystem.gosyscall_dragonfly.gosyscall_dragonfly_amd64.gosyscall_freebsd.gosyscall_freebsd_386.gosyscall_freebsd_amd64.gosyscall_freebsd_arm.gosyscall_freebsd_arm64.gosyscall_freebsd_riscv64.gosyscall_hurd.gosyscall_hurd_386.gosyscall_illumos.gosyscall_linux.gosyscall_linux_386.gosyscall_linux_alarm.gosyscall_linux_amd64.gosyscall_linux_amd64_gc.gosyscall_linux_arm.gosyscall_linux_arm64.gosyscall_linux_gc.gosyscall_linux_gc_386.gosyscall_linux_gc_arm.gosyscall_linux_gccgo_386.gosyscall_linux_gccgo_arm.gosyscall_linux_loong64.gosyscall_linux_mips64x.gosyscall_linux_mipsx.gosyscall_linux_ppc.gosyscall_linux_ppc64x.gosyscall_linux_riscv64.gosyscall_linux_s390x.gosyscall_linux_sparc64.gosyscall_netbsd.gosyscall_netbsd_386.gosyscall_netbsd_amd64.gosyscall_netbsd_arm.gosyscall_netbsd_arm64.gosyscall_openbsd.gosyscall_openbsd_386.gosyscall_openbsd_amd64.gosyscall_openbsd_arm.gosyscall_openbsd_arm64.gosyscall_openbsd_libc.gosyscall_openbsd_mips64.gosyscall_openbsd_ppc64.gosyscall_openbsd_riscv64.gosyscall_solaris.gosyscall_solaris_amd64.gosyscall_unix.gosyscall_unix_gc.gosyscall_unix_gc_ppc64x.gosyscall_zos_s390x.gosysvshm_linux.gosysvshm_unix.gosysvshm_unix_other.gotimestruct.gounveil_openbsd.goxattr_bsd.gozerrors_aix_ppc.gozerrors_aix_ppc64.gozerrors_darwin_amd64.gozerrors_darwin_arm64.gozerrors_dragonfly_amd64.gozerrors_freebsd_386.gozerrors_freebsd_amd64.gozerrors_freebsd_arm.gozerrors_freebsd_arm64.gozerrors_freebsd_riscv64.gozerrors_linux.gozerrors_linux_386.gozerrors_linux_amd64.gozerrors_linux_arm.gozerrors_linux_arm64.gozerrors_linux_loong64.gozerrors_linux_mips.gozerrors_linux_mips64.gozerrors_linux_mips64le.gozerrors_linux_mipsle.gozerrors_linux_ppc.gozerrors_linux_ppc64.gozerrors_linux_ppc64le.gozerrors_linux_riscv64.gozerrors_linux_s390x.gozerrors_linux_sparc64.gozerrors_netbsd_386.gozerrors_netbsd_amd64.gozerrors_netbsd_arm.gozerrors_netbsd_arm64.gozerrors_openbsd_386.gozerrors_openbsd_amd64.gozerrors_openbsd_arm.gozerrors_openbsd_arm64.gozerrors_openbsd_mips64.gozerrors_openbsd_ppc64.gozerrors_openbsd_riscv64.gozerrors_solaris_amd64.gozerrors_zos_s390x.gozptrace_armnn_linux.gozptrace_linux_arm64.gozptrace_mipsnn_linux.gozptrace_mipsnnle_linux.gozptrace_x86_linux.gozsymaddr_zos_s390x.szsyscall_aix_ppc.gozsyscall_aix_ppc64.gozsyscall_aix_ppc64_gc.gozsyscall_aix_ppc64_gccgo.gozsyscall_darwin_amd64.gozsyscall_darwin_amd64.szsyscall_darwin_arm64.gozsyscall_darwin_arm64.szsyscall_dragonfly_amd64.gozsyscall_freebsd_386.gozsyscall_freebsd_amd64.gozsyscall_freebsd_arm.gozsyscall_freebsd_arm64.gozsyscall_freebsd_riscv64.gozsyscall_illumos_amd64.gozsyscall_linux.gozsyscall_linux_386.gozsyscall_linux_amd64.gozsyscall_linux_arm.gozsyscall_linux_arm64.gozsyscall_linux_loong64.gozsyscall_linux_mips.gozsyscall_linux_mips64.gozsyscall_linux_mips64le.gozsyscall_linux_mipsle.gozsyscall_linux_ppc.gozsyscall_linux_ppc64.gozsyscall_linux_ppc64le.gozsyscall_linux_riscv64.gozsyscall_linux_s390x.gozsyscall_linux_sparc64.gozsyscall_netbsd_386.gozsyscall_netbsd_amd64.gozsyscall_netbsd_arm.gozsyscall_netbsd_arm64.gozsyscall_openbsd_386.gozsyscall_openbsd_386.szsyscall_openbsd_amd64.gozsyscall_openbsd_amd64.szsyscall_openbsd_arm.gozsyscall_openbsd_arm.szsyscall_openbsd_arm64.gozsyscall_openbsd_arm64.szsyscall_openbsd_mips64.gozsyscall_openbsd_mips64.szsyscall_openbsd_ppc64.gozsyscall_openbsd_ppc64.szsyscall_openbsd_riscv64.gozsyscall_openbsd_riscv64.szsyscall_solaris_amd64.gozsyscall_zos_s390x.gozsysctl_openbsd_386.gozsysctl_openbsd_amd64.gozsysctl_openbsd_arm.gozsysctl_openbsd_arm64.gozsysctl_openbsd_mips64.gozsysctl_openbsd_ppc64.gozsysctl_openbsd_riscv64.gozsysnum_darwin_amd64.gozsysnum_darwin_arm64.gozsysnum_dragonfly_amd64.gozsysnum_freebsd_386.gozsysnum_freebsd_amd64.gozsysnum_freebsd_arm.gozsysnum_freebsd_arm64.gozsysnum_freebsd_riscv64.gozsysnum_linux_386.gozsysnum_linux_amd64.gozsysnum_linux_arm.gozsysnum_linux_arm64.gozsysnum_linux_loong64.gozsysnum_linux_mips.gozsysnum_linux_mips64.gozsysnum_linux_mips64le.gozsysnum_linux_mipsle.gozsysnum_linux_ppc.gozsysnum_linux_ppc64.gozsysnum_linux_ppc64le.gozsysnum_linux_riscv64.gozsysnum_linux_s390x.gozsysnum_linux_sparc64.gozsysnum_netbsd_386.gozsysnum_netbsd_amd64.gozsysnum_netbsd_arm.gozsysnum_netbsd_arm64.gozsysnum_openbsd_386.gozsysnum_openbsd_amd64.gozsysnum_openbsd_arm.gozsysnum_openbsd_arm64.gozsysnum_openbsd_mips64.gozsysnum_openbsd_ppc64.gozsysnum_openbsd_riscv64.gozsysnum_zos_s390x.goztypes_aix_ppc.goztypes_aix_ppc64.goztypes_darwin_amd64.goztypes_darwin_arm64.goztypes_dragonfly_amd64.goztypes_freebsd_386.goztypes_freebsd_amd64.goztypes_freebsd_arm.goztypes_freebsd_arm64.goztypes_freebsd_riscv64.goztypes_linux.goztypes_linux_386.goztypes_linux_amd64.goztypes_linux_arm.goztypes_linux_arm64.goztypes_linux_loong64.goztypes_linux_mips.goztypes_linux_mips64.goztypes_linux_mips64le.goztypes_linux_mipsle.goztypes_linux_ppc.goztypes_linux_ppc64.goztypes_linux_ppc64le.goztypes_linux_riscv64.goztypes_linux_s390x.goztypes_linux_sparc64.goztypes_netbsd_386.goztypes_netbsd_amd64.goztypes_netbsd_arm.goztypes_netbsd_arm64.goztypes_openbsd_386.goztypes_openbsd_amd64.goztypes_openbsd_arm.goztypes_openbsd_arm64.goztypes_openbsd_mips64.goztypes_openbsd_ppc64.goztypes_openbsd_riscv64.goztypes_solaris_amd64.goztypes_zos_s390x.go
windows
term
text
time
google.golang.org
genproto
googleapis
grpc
AUTHORSCODE-OF-CONDUCT.mdCONTRIBUTING.mdGOVERNANCE.mdLICENSEMAINTAINERS.mdMakefileNOTICE.txtREADME.mdSECURITY.md
attributes
backoff.go
backoff
balancer
balancer_wrapper.go
binarylog
grpc_binarylog_v1
call.go
channelz
clientconn.gocodec.go
codes
connectivity
credentials
dialoptions.godoc.go
encoding
grpclog
health
interceptor.go
internal
keepalive
metadata
peer
picker_wrapper.gopreloader.goregenerate.sh
resolver
resolver_wrapper.gorpc_util.goserver.goservice_config.go
serviceconfig
shared_buffer_pool.go
stats
status
stream.gostream_interfaces.go
tap
trace.gotrace_notrace.gotrace_withtrace.goversion.go
protobuf
LICENSEPATENTS
encoding
internal
proto
protoadapt
reflect
runtime
types
known
anypb
durationpb
fieldmaskpb
structpb
timestamppb
wrapperspb
gopkg.in
gotest.tools
modules.txt

@ -0,0 +1,463 @@
package client
import (
"encoding/json"
"fmt"
"regexp"
"github.com/sirupsen/logrus"
"github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/cryptoservice"
store "github.com/theupdateframework/notary/storage"
"github.com/theupdateframework/notary/trustpinning"
"github.com/theupdateframework/notary/tuf"
"github.com/theupdateframework/notary/tuf/data"
"github.com/theupdateframework/notary/tuf/signed"
)
// tufClient is a usability wrapper around a raw TUF repo
type tufClient struct {
remote store.RemoteStore
cache store.MetadataStore
oldBuilder tuf.RepoBuilder
newBuilder tuf.RepoBuilder
}
// Update performs an update to the TUF repo as defined by the TUF spec
func (c *tufClient) Update() (*tuf.Repo, *tuf.Repo, error) {
// 1. Get timestamp
// a. If timestamp error (verification, expired, etc...) download new root and return to 1.
// 2. Check if local snapshot is up to date
// a. If out of date, get updated snapshot
// i. If snapshot error, download new root and return to 1.
// 3. Check if root correct against snapshot
// a. If incorrect, download new root and return to 1.
// 4. Iteratively download and search targets and delegations to find target meta
logrus.Debug("updating TUF client")
err := c.update()
if err != nil {
logrus.Debug("Error occurred. Root will be downloaded and another update attempted")
logrus.Debug("Resetting the TUF builder...")
c.newBuilder = c.newBuilder.BootstrapNewBuilder()
if err := c.updateRoot(); err != nil {
logrus.Debug("Client Update (Root): ", err)
return nil, nil, err
}
// If we error again, we now have the latest root and just want to fail
// out as there's no expectation the problem can be resolved automatically
logrus.Debug("retrying TUF client update")
if err := c.update(); err != nil {
return nil, nil, err
}
}
return c.newBuilder.Finish()
}
func (c *tufClient) update() error {
if err := c.downloadTimestamp(); err != nil {
logrus.Debugf("Client Update (Timestamp): %s", err.Error())
return err
}
if err := c.downloadSnapshot(); err != nil {
logrus.Debugf("Client Update (Snapshot): %s", err.Error())
return err
}
// will always need top level targets at a minimum
if err := c.downloadTargets(); err != nil {
logrus.Debugf("Client Update (Targets): %s", err.Error())
return err
}
return nil
}
// updateRoot checks if there is a newer version of the root available, and if so
// downloads all intermediate root files to allow proper key rotation.
func (c *tufClient) updateRoot() error {
// Get current root version
currentRootConsistentInfo := c.oldBuilder.GetConsistentInfo(data.CanonicalRootRole)
currentVersion := c.oldBuilder.GetLoadedVersion(currentRootConsistentInfo.RoleName)
// Get new root version
raw, err := c.downloadRoot()
switch err.(type) {
case *trustpinning.ErrRootRotationFail:
// Rotation errors are okay since we haven't yet downloaded
// all intermediate root files
break
case nil:
// No error updating root - we were at most 1 version behind
return nil
default:
// Return any non-rotation error.
return err
}
// Load current version into newBuilder
currentRaw, err := c.cache.GetSized(data.CanonicalRootRole.String(), -1)
if err != nil {
logrus.Debugf("error loading %d.%s: %s", currentVersion, data.CanonicalRootRole, err)
return err
}
if err := c.newBuilder.LoadRootForUpdate(currentRaw, currentVersion, false); err != nil {
logrus.Debugf("%d.%s is invalid: %s", currentVersion, data.CanonicalRootRole, err)
return err
}
// Extract newest version number
signedRoot := &data.Signed{}
if err := json.Unmarshal(raw, signedRoot); err != nil {
return err
}
newestRoot, err := data.RootFromSigned(signedRoot)
if err != nil {
return err
}
newestVersion := newestRoot.Signed.SignedCommon.Version
// Update from current + 1 (current already loaded) to newest - 1 (newest loaded below)
if err := c.updateRootVersions(currentVersion+1, newestVersion-1); err != nil {
return err
}
// Already downloaded newest, verify it against newest - 1
if err := c.newBuilder.LoadRootForUpdate(raw, newestVersion, true); err != nil {
logrus.Debugf("downloaded %d.%s is invalid: %s", newestVersion, data.CanonicalRootRole, err)
return err
}
logrus.Debugf("successfully verified downloaded %d.%s", newestVersion, data.CanonicalRootRole)
// Write newest to cache
if err := c.cache.Set(data.CanonicalRootRole.String(), raw); err != nil {
logrus.Debugf("unable to write %d.%s to cache: %s", newestVersion, data.CanonicalRootRole, err)
}
logrus.Debugf("finished updating root files")
return nil
}
// updateRootVersions updates the root from it's current version to a target, rotating keys
// as they are found
func (c *tufClient) updateRootVersions(fromVersion, toVersion int) error {
for v := fromVersion; v <= toVersion; v++ {
logrus.Debugf("updating root from version %d to version %d, currently fetching %d", fromVersion, toVersion, v)
versionedRole := fmt.Sprintf("%d.%s", v, data.CanonicalRootRole)
raw, err := c.remote.GetSized(versionedRole, -1)
if err != nil {
logrus.Debugf("error downloading %s: %s", versionedRole, err)
return err
}
if err := c.newBuilder.LoadRootForUpdate(raw, v, false); err != nil {
logrus.Debugf("downloaded %s is invalid: %s", versionedRole, err)
return err
}
logrus.Debugf("successfully verified downloaded %s", versionedRole)
}
return nil
}
// downloadTimestamp is responsible for downloading the timestamp.json
// Timestamps are special in that we ALWAYS attempt to download and only
// use cache if the download fails (and the cache is still valid).
func (c *tufClient) downloadTimestamp() error {
logrus.Debug("Loading timestamp...")
role := data.CanonicalTimestampRole
consistentInfo := c.newBuilder.GetConsistentInfo(role)
// always get the remote timestamp, since it supersedes the local one
cachedTS, cachedErr := c.cache.GetSized(role.String(), notary.MaxTimestampSize)
_, remoteErr := c.tryLoadRemote(consistentInfo, cachedTS)
// check that there was no remote error, or if there was a network problem
// If there was a validation error, we should error out so we can download a new root or fail the update
switch remoteErr.(type) {
case nil:
return nil
case store.ErrMetaNotFound, store.ErrServerUnavailable, store.ErrOffline, store.NetworkError:
break
default:
return remoteErr
}
// since it was a network error: get the cached timestamp, if it exists
if cachedErr != nil {
logrus.Debug("no cached or remote timestamp available")
return remoteErr
}
logrus.Warn("Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely")
err := c.newBuilder.Load(role, cachedTS, 1, false)
if err == nil {
logrus.Debug("successfully verified cached timestamp")
}
return err
}
// downloadSnapshot is responsible for downloading the snapshot.json
func (c *tufClient) downloadSnapshot() error {
logrus.Debug("Loading snapshot...")
role := data.CanonicalSnapshotRole
consistentInfo := c.newBuilder.GetConsistentInfo(role)
_, err := c.tryLoadCacheThenRemote(consistentInfo)
return err
}
// downloadTargets downloads all targets and delegated targets for the repository.
// It uses a pre-order tree traversal as it's necessary to download parents first
// to obtain the keys to validate children.
func (c *tufClient) downloadTargets() error {
toDownload := []data.DelegationRole{{
BaseRole: data.BaseRole{Name: data.CanonicalTargetsRole},
Paths: []string{""},
}}
for len(toDownload) > 0 {
role := toDownload[0]
toDownload = toDownload[1:]
consistentInfo := c.newBuilder.GetConsistentInfo(role.Name)
if !consistentInfo.ChecksumKnown() {
logrus.Debugf("skipping %s because there is no checksum for it", role.Name)
continue
}
children, err := c.getTargetsFile(role, consistentInfo)
switch err.(type) {
case signed.ErrExpired, signed.ErrRoleThreshold:
if role.Name == data.CanonicalTargetsRole {
return err
}
logrus.Warnf("Error getting %s: %s", role.Name, err)
break
case nil:
toDownload = append(children, toDownload...)
default:
return err
}
}
return nil
}
func (c tufClient) getTargetsFile(role data.DelegationRole, ci tuf.ConsistentInfo) ([]data.DelegationRole, error) {
logrus.Debugf("Loading %s...", role.Name)
tgs := &data.SignedTargets{}
raw, err := c.tryLoadCacheThenRemote(ci)
if err != nil {
return nil, err
}
// we know it unmarshals because if `tryLoadCacheThenRemote` didn't fail, then
// the raw has already been loaded into the builder
json.Unmarshal(raw, tgs)
return tgs.GetValidDelegations(role), nil
}
// downloadRoot is responsible for downloading the root.json
func (c *tufClient) downloadRoot() ([]byte, error) {
role := data.CanonicalRootRole
consistentInfo := c.newBuilder.GetConsistentInfo(role)
// We can't read an exact size for the root metadata without risking getting stuck in the TUF update cycle
// since it's possible that downloading timestamp/snapshot metadata may fail due to a signature mismatch
if !consistentInfo.ChecksumKnown() {
logrus.Debugf("Loading root with no expected checksum")
// get the cached root, if it exists, just for version checking
cachedRoot, _ := c.cache.GetSized(role.String(), -1)
// prefer to download a new root
return c.tryLoadRemote(consistentInfo, cachedRoot)
}
return c.tryLoadCacheThenRemote(consistentInfo)
}
func (c *tufClient) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([]byte, error) {
cachedTS, err := c.cache.GetSized(consistentInfo.RoleName.String(), consistentInfo.Length())
if err != nil {
logrus.Debugf("no %s in cache, must download", consistentInfo.RoleName)
return c.tryLoadRemote(consistentInfo, nil)
}
if err = c.newBuilder.Load(consistentInfo.RoleName, cachedTS, 1, false); err == nil {
logrus.Debugf("successfully verified cached %s", consistentInfo.RoleName)
return cachedTS, nil
}
logrus.Debugf("cached %s is invalid (must download): %s", consistentInfo.RoleName, err)
return c.tryLoadRemote(consistentInfo, cachedTS)
}
func (c *tufClient) tryLoadRemote(consistentInfo tuf.ConsistentInfo, old []byte) ([]byte, error) {
consistentName := consistentInfo.ConsistentName()
raw, err := c.remote.GetSized(consistentName, consistentInfo.Length())
if err != nil {
logrus.Debugf("error downloading %s: %s", consistentName, err)
return old, err
}
// try to load the old data into the old builder - only use it to validate
// versions if it loads successfully. If it errors, then the loaded version
// will be 1
c.oldBuilder.Load(consistentInfo.RoleName, old, 1, true)
minVersion := c.oldBuilder.GetLoadedVersion(consistentInfo.RoleName)
if err := c.newBuilder.Load(consistentInfo.RoleName, raw, minVersion, false); err != nil {
logrus.Debugf("downloaded %s is invalid: %s", consistentName, err)
return raw, err
}
logrus.Debugf("successfully verified downloaded %s", consistentName)
if err := c.cache.Set(consistentInfo.RoleName.String(), raw); err != nil {
logrus.Debugf("Unable to write %s to cache: %s", consistentInfo.RoleName, err)
}
return raw, nil
}
// TUFLoadOptions are provided to LoadTUFRepo, which loads a TUF repo from cache,
// from a remote store, or both
type TUFLoadOptions struct {
GUN data.GUN
TrustPinning trustpinning.TrustPinConfig
CryptoService signed.CryptoService
Cache store.MetadataStore
RemoteStore store.RemoteStore
AlwaysCheckInitialized bool
}
// bootstrapClient attempts to bootstrap a root.json to be used as the trust
// anchor for a repository. The checkInitialized argument indicates whether
// we should always attempt to contact the server to determine if the repository
// is initialized or not. If set to true, we will always attempt to download
// and return an error if the remote repository errors.
//
// Populates a tuf.RepoBuilder with this root metadata. If the root metadata
// downloaded is a newer version than what is on disk, then intermediate
// versions will be downloaded and verified in order to rotate trusted keys
// properly. Newer root metadata must always be signed with the previous
// threshold and keys.
//
// Fails if the remote server is reachable and does not know the repo
// (i.e. before any metadata has been published), in which case the error is
// store.ErrMetaNotFound, or if the root metadata (from whichever source is used)
// is not trusted.
//
// Returns a TUFClient for the remote server, which may not be actually
// operational (if the URL is invalid but a root.json is cached).
func bootstrapClient(l TUFLoadOptions) (*tufClient, error) {
minVersion := 1
// the old root on disk should not be validated against any trust pinning configuration
// because if we have an old root, it itself is the thing that pins trust
oldBuilder := tuf.NewRepoBuilder(l.GUN, l.CryptoService, trustpinning.TrustPinConfig{})
// by default, we want to use the trust pinning configuration on any new root that we download
newBuilder := tuf.NewRepoBuilder(l.GUN, l.CryptoService, l.TrustPinning)
// Try to read root from cache first. We will trust this root until we detect a problem
// during update which will cause us to download a new root and perform a rotation.
// If we have an old root, and it's valid, then we overwrite the newBuilder to be one
// preloaded with the old root or one which uses the old root for trust bootstrapping.
if rootJSON, err := l.Cache.GetSized(data.CanonicalRootRole.String(), store.NoSizeLimit); err == nil {
// if we can't load the cached root, fail hard because that is how we pin trust
if err := oldBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, true); err != nil {
return nil, err
}
// again, the root on disk is the source of trust pinning, so use an empty trust
// pinning configuration
newBuilder = tuf.NewRepoBuilder(l.GUN, l.CryptoService, trustpinning.TrustPinConfig{})
if err := newBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, false); err != nil {
// Ok, the old root is expired - we want to download a new one. But we want to use the
// old root to verify the new root, so bootstrap a new builder with the old builder
// but use the trustpinning to validate the new root
minVersion = oldBuilder.GetLoadedVersion(data.CanonicalRootRole)
newBuilder = oldBuilder.BootstrapNewBuilderWithNewTrustpin(l.TrustPinning)
}
}
if !newBuilder.IsLoaded(data.CanonicalRootRole) || l.AlwaysCheckInitialized {
// remoteErr was nil and we were not able to load a root from cache or
// are specifically checking for initialization of the repo.
// if remote store successfully set up, try and get root from remote
// We don't have any local data to determine the size of root, so try the maximum (though it is restricted at 100MB)
tmpJSON, err := l.RemoteStore.GetSized(data.CanonicalRootRole.String(), store.NoSizeLimit)
if err != nil {
// we didn't have a root in cache and were unable to load one from
// the server. Nothing we can do but error.
return nil, err
}
if !newBuilder.IsLoaded(data.CanonicalRootRole) {
// we always want to use the downloaded root if we couldn't load from cache
if err := newBuilder.Load(data.CanonicalRootRole, tmpJSON, minVersion, false); err != nil {
return nil, err
}
err = l.Cache.Set(data.CanonicalRootRole.String(), tmpJSON)
if err != nil {
// if we can't write cache we should still continue, just log error
logrus.Errorf("could not save root to cache: %s", err.Error())
}
}
}
// We can only get here if remoteErr != nil (hence we don't download any new root),
// and there was no root on disk
if !newBuilder.IsLoaded(data.CanonicalRootRole) {
return nil, ErrRepoNotInitialized{}
}
return &tufClient{
oldBuilder: oldBuilder,
newBuilder: newBuilder,
remote: l.RemoteStore,
cache: l.Cache,
}, nil
}
// LoadTUFRepo bootstraps a trust anchor (root.json) from cache (if provided) before updating
// all the metadata for the repo from the remote (if provided). It loads a TUF repo from cache,
// from a remote store, or both.
func LoadTUFRepo(options TUFLoadOptions) (*tuf.Repo, *tuf.Repo, error) {
// set some sane defaults, so nothing has to be provided necessarily
if options.RemoteStore == nil {
options.RemoteStore = store.OfflineStore{}
}
if options.Cache == nil {
options.Cache = store.NewMemoryStore(nil)
}
if options.CryptoService == nil {
options.CryptoService = cryptoservice.EmptyService
}
c, err := bootstrapClient(options)
if err != nil {
if _, ok := err.(store.ErrMetaNotFound); ok {
return nil, nil, ErrRepositoryNotExist{
remote: options.RemoteStore.Location(),
gun: options.GUN,
}
}
return nil, nil, err
}
repo, invalid, err := c.Update()
if err != nil {
// notFound.Resource may include a version or checksum so when the role is root,
// it will be root, <version>.root or root.<checksum>.
notFound, ok := err.(store.ErrMetaNotFound)
isRoot, _ := regexp.MatchString(`\.?`+data.CanonicalRootRole.String()+`\.?`, notFound.Resource)
if ok && isRoot {
return nil, nil, ErrRepositoryNotExist{
remote: options.RemoteStore.Location(),
gun: options.GUN,
}
}
return nil, nil, err
}
warnRolesNearExpiry(repo)
return repo, invalid, nil
}