Skip to content

Commit

Permalink
add tag history example (#132)
Browse files Browse the repository at this point in the history
* add tag history example

Signed-off-by: Jason Hall <jason@chainguard.dev>

* use justtrustme to get a token

Signed-off-by: Jason Hall <jason@chainguard.dev>

---------

Signed-off-by: Jason Hall <jason@chainguard.dev>
  • Loading branch information
imjasonh authored Nov 30, 2023
1 parent aeae99f commit 74721dc
Show file tree
Hide file tree
Showing 4 changed files with 540 additions and 0 deletions.
9 changes: 9 additions & 0 deletions tag-history/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# `tag-history`

This demonstrates how to query the history of a tag for a Chainguard Image.

### Usage

```sh
go run ./cmd/app --tag=cgr.dev/customer.biz/go:latest
```
175 changes: 175 additions & 0 deletions tag-history/cmd/app/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
Copyright 2022 Chainguard, Inc.
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
"context"
"encoding/json"
"flag"
"io"
"log"
"net/http"
"strings"
"time"

"chainguard.dev/sdk/auth/token"
common "chainguard.dev/sdk/proto/platform/common/v1"
iam "chainguard.dev/sdk/proto/platform/iam/v1"
registry "chainguard.dev/sdk/proto/platform/registry/v1"
"chainguard.dev/sdk/sts"
"github.com/google/go-containerregistry/pkg/name"
)

func main() {
ctx := context.Background()
tag := flag.String("tag", "cgr.dev/chainguard/static:latest-glibc", "tag to query")
flag.Parse()

t, err := name.ParseReference(*tag)
if err != nil {
log.Fatalf("parsing tag: %v", err)
}
reg := t.Context().RegistryStr()
fullrepo := t.Context().RepositoryStr()
group, repo, ok := strings.Cut(fullrepo, "/")
if !ok {
log.Fatalf("invalid repo: %s", fullrepo)
}
tagstr := t.Identifier()
log.Printf("registry: %s, group: %s, repo: %s, tag: %s", reg, group, repo, tagstr)

if reg != "cgr.dev" {
log.Fatalf("must be in cgr.dev registry")
}

// Get the Chainguard auth token.
var tok string
audience := "https://console-api.enforce.dev"
{
if group == "chainguard" {
// This group is special, since anybody can access it by assuming a
// broadly-assumable identity with permission to view/pull.

issuer := "https://issuer.enforce.dev"
resp, err := http.Get("https://justtrustme.dev/token?aud=" + issuer)
if err != nil {
log.Fatalf("getting justtrustme token: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatalf("getting justtrustme token: %v", resp.Status)
}
all, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("reading justtrustme token: %v", err)
}
var r struct {
Token string `json:"token"`
}
if err := json.Unmarshal(all, &r); err != nil {
log.Fatalf("decoding justtrustme token: %v", err)
}
tok = r.Token

tok, err = sts.New(issuer, audience,
sts.WithIdentity("720909c9f5279097d847ad02a2f24ba8f59de36a/a033a6fabe0bfa0d")).
Exchange(ctx, tok)
if err != nil {
log.Fatalf("exchanging token: %v", err)
}
} else {
if token.RemainingLife(audience, time.Minute) < 0 {
// TODO: do a browser flow here.
log.Fatalf("token has expired, please run `chainctl auth login`")
}
tokb, err := token.Load(audience)
if err != nil {
log.Fatalf("loading token: %v", err)
}
tok = string(tokb)
}
}

// Set up clients.
iamc, err := iam.NewClients(ctx, audience, tok)
if err != nil {
log.Fatalf("creating IAM clients: %v", err)
}
regc, err := registry.NewClients(ctx, audience, tok)
if err != nil {
log.Fatalf("creating Registry clients: %v", err)
}

// Get the group UIDP.
var groupUIDP string
{
if group == "chainguard" {
// This group is special, we'll just hard-code the UIDP.
groupUIDP = "720909c9f5279097d847ad02a2f24ba8f59de36a"
} else {
resp, err := iamc.Groups().List(ctx, &iam.GroupFilter{
Name: group,
})
if err != nil {
log.Fatalf("listing groups: %v", err)
}
if len(resp.Items) != 1 {
log.Fatalf("expected 1 group, got %d", len(resp.Items))
}
groupUIDP = resp.Items[0].Id
}
}
log.Println("group UIDP", groupUIDP)

// Get the repo UIDP.
var repoUIDP string
{
resp, err := regc.Registry().ListRepos(ctx, &registry.RepoFilter{
Uidp: &common.UIDPFilter{
ChildrenOf: groupUIDP,
},
Name: repo,
})
if err != nil {
log.Fatalf("listing repos: %v", err)
}
if len(resp.Items) != 1 {
log.Fatalf("expected 1 repo, got %d", len(resp.Items))
}
repoUIDP = resp.Items[0].Id
}
log.Println("repo UIDP", repoUIDP)

// Get the tag UIDP.
var tagUIDP string
{
resp, err := regc.Registry().ListTags(ctx, &registry.TagFilter{
Uidp: &common.UIDPFilter{
ChildrenOf: repoUIDP,
},
Name: tagstr,
})
if err != nil {
log.Fatalf("listing tags: %v", err)
}
if len(resp.Items) != 1 {
log.Fatalf("expected 1 tag, got %d", len(resp.Items))
}
tagUIDP = resp.Items[0].Id
}
log.Println("tag UIDP", tagUIDP)

// List tag history for the tag.
resp, err := regc.Registry().ListTagHistory(ctx, &registry.TagHistoryFilter{
ParentId: tagUIDP,
})
if err != nil {
log.Fatalf("listing tag history: %v", err)
}
for _, i := range resp.Items {
log.Printf("time: %s digest: %s", i.UpdateTimestamp.AsTime(), i.Digest)
}
}
65 changes: 65 additions & 0 deletions tag-history/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module github.com/chainguard-dev/enforce-events/tag-history

go 1.21

toolchain go1.21.0

replace github.com/chainguard-dev/enforce-events => ../

require (
chainguard.dev/sdk v0.1.1
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/go-containerregistry v0.16.1
)

require (
chainguard.dev/go-grpc-kit v0.17.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.11.0 // indirect
github.com/blendle/zapdriver v1.3.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 // indirect
go.opentelemetry.io/otel v1.20.0 // indirect
go.opentelemetry.io/otel/metric v1.20.0 // indirect
go.opentelemetry.io/otel/trace v1.20.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/oauth2 v0.14.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/api v0.28.4 // indirect
k8s.io/apimachinery v0.28.4 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect
knative.dev/pkg v0.0.0-20231101193506-b09d4f2a2845 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
)
Loading

0 comments on commit 74721dc

Please sign in to comment.