Skip to content
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
10 changes: 10 additions & 0 deletions cmd/ate-setup/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ Each reference is then pinned to the digest its tag names, which takes one HEAD
request per image, so the installer needs read access to `REPO` and not only the
cluster does.

That read is authenticated with the docker config file and the credential
helpers it names, plus gcloud's own credentials for GCR and Artifact Registry:
Application Default Credentials, falling back to the `gcloud` CLI. Installing a
release onto GKE therefore needs no `~/.docker/config.json` entry. Amazon ECR
and Azure Container Registry need credential-helper modules this repository does
not depend on, so those registries need a `docker login` first.

`TAG` may itself carry a digest, as in `--image-tag v0.0.0@sha256:...`. A tag
that already names a manifest is used as written, and is not looked up.

## Deploy

| `ate-setup` | `hack/install-ate.sh` |
Expand Down
20 changes: 15 additions & 5 deletions cmd/ate-setup/internal/images/digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,38 @@ import (

"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/google"
"github.com/google/go-containerregistry/pkg/v1/remote"
)

// keychain authenticates the digest lookups.
//
// The docker config file and the credential helpers it names, plus GCP. ko
// resolves credentials through a multi-keychain of its own, and matching the
// GCP half of it matters: a user whose Artifact Registry credentials are
// gcloud's rather than a helper wired into ~/.docker/config.json would
// otherwise get a working build from source and a 401 from --image-repo. ECR
// and ACR need credential-helper modules this repository does not depend on,
// so those registries need a docker login.
var keychain = authn.NewMultiKeychain(authn.DefaultKeychain, google.Keychain)

// Digester resolves a tagged image reference to the digest its tag currently
// names, in "sha256:..." form. Prebuilt takes one so tests can rewrite
// manifests without a registry.
type Digester func(ctx context.Context, ref string) (string, error)

// RemoteDigest asks ref's registry which manifest the tag names.
//
// One HEAD request per image, needing only read access, and authenticated the
// way docker and ko are: from the docker config file and the credential helpers
// it names. A localhost registry is contacted over plain HTTP, which is what
// the Kind local registry serves.
// One HEAD request per image, needing only read access. A localhost registry is
// contacted over plain HTTP, which is what the Kind local registry serves.
func RemoteDigest(ctx context.Context, ref string) (string, error) {
parsed, err := name.ParseReference(ref)
if err != nil {
return "", fmt.Errorf("%s is not a valid image reference: %w", ref, err)
}
desc, err := remote.Head(parsed,
remote.WithContext(ctx),
remote.WithAuthFromKeychain(authn.DefaultKeychain),
remote.WithAuthFromKeychain(keychain),
)
if err != nil {
return "", fmt.Errorf("resolving %s to a digest: %w", ref, err)
Expand Down
6 changes: 6 additions & 0 deletions cmd/ate-setup/internal/images/prebuilt.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ func (p *Prebuilt) ResolveBytes(ctx context.Context, manifest []byte) ([]byte, e
// and leaves the reference legible in `kubectl get`.
func (p *Prebuilt) pin(ctx context.Context, image string) (string, error) {
tagged := p.src.Repo + "/" + image + ":" + p.src.Tag
// A tag that already carries one is pinned as it stands. Looking it up
// would only append the same digest a second time, and the reference the
// caller wrote is the one they meant.
if strings.Contains(p.src.Tag, "@") {
return tagged, nil
}
if ref, ok := p.pinned[tagged]; ok {
return ref, nil
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/ate-setup/internal/images/prebuilt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ func TestPrebuiltResolveBytes(t *testing.T) {
in: "spec:\n workerImage: ko://github.com/agent-substrate/substrate/cmd/ateom-gvisor\n",
want: "spec:\n workerImage: example.com/substrate/ateom-gvisor:v1.2.3" + digestSuffix + "\n",
},
{
// A tag can carry its own digest, and then there is nothing to look
// up. The stub would answer with testDigest a second time, so the
// expected output is also what catches a redundant lookup.
name: "tag already carries a digest",
Comment thread
annapendleton marked this conversation as resolved.
src: images.Source{Repo: "example.com/substrate", Tag: "v1.2.3" + digestSuffix},
in: "image: ko://github.com/agent-substrate/substrate/cmd/ateapi\n",
want: "image: example.com/substrate/ateapi:v1.2.3" + digestSuffix + "\n",
},
{
name: "nested package maps to its image name",
in: "image: ko://github.com/agent-substrate/substrate/demos/multi-template/fspersist\n",
Expand Down
Loading