Skip to content

Commit

Permalink
add image-diff example (#133)
Browse files Browse the repository at this point in the history
* WIP: add image-diff example

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

* use different digests

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

* support real auth, not just public images

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

* try new example

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

* use real creds to exchange for public identity

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

---------

Signed-off-by: Jason Hall <jason@chainguard.dev>
  • Loading branch information
imjasonh authored Dec 6, 2023
1 parent f0bf14f commit 1e80168
Show file tree
Hide file tree
Showing 5 changed files with 501 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This repo holds a number of example apps demonstrating various [Chainguard Event
- [GCR Image Copier](./image-copy-gcr/) - copies images to Google Container Registry when an image is pushed to cgr.dev
- [ECR Image Copier](./image-copy-ecr/) - copies images to Amazon Elastic Container Registry when an image is pushed to cgr.dev
- [AWS Auth Example](./aws-auth/) - demonstrates configuration of an AWS assumable Chainguard identity, as well as calling the Chainguard API from a Lambda function
- [Tag History Example](./tag-history/) - demonstrates how to use the Chainguard API to track tag history for images in a registry
- [Image Diff Example](./image-diff/) - demonstrates how to use the Chainguard API to compare images in a registry

> [!NOTE]
> These examples are intended to be used as a reference for building your own Chainguard platform integrations.
Expand Down
14 changes: 14 additions & 0 deletions image-diff/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# `image-diff`

This demonstrates how to query diffs of Chainguard Images.

Along with Tag History, you can use this to show the evolution of an image over time, or the difference between packages in a `:latest` and a `:latest-dev` image tag.

### Usage

```sh
reponame=go
left=sha256:a62aded9da72d0f4ad2f6eb751f3ce3fff2f5d0d30d93dcd245c0cd650d5028a # :latest
right=sha256:9d49f4b2d67988d5345419a35533762e72eaaa8162d4b43a1e3d41869d1f845e # :latest-dev
go run ./cmd/app $reponame $left $right
```
134 changes: 134 additions & 0 deletions image-diff/cmd/app/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
Copyright 2023 Chainguard, Inc.
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"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()
var group string
flag.StringVar(&group, "group", "chainguard", "group to query")
flag.Parse()

if len(flag.Args()) != 3 {
log.Fatalf("requires 3 arguments: repo name, and previous and current image to diff")
}
if _, err := name.NewDigest("example.com/foo@" + flag.Arg(1)); err != nil {
log.Fatalf("invalid digest: %v", err)
}
if _, err := name.NewDigest("example.com/foo@" + flag.Arg(2)); err != nil {
log.Fatalf("invalid digest: %v", err)
}
repo, left, right := flag.Arg(0), flag.Arg(1), flag.Arg(2)

// Get the Chainguard auth token.
var tok string
audience := "https://console-api.enforce.dev"
{
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)

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"
tok, err = sts.New(issuer, audience,
sts.WithIdentity("720909c9f5279097d847ad02a2f24ba8f59de36a/a033a6fabe0bfa0d")).
Exchange(ctx, tok)
if err != nil {
log.Fatalf("exchanging token: %v", err)
}
}
}

// 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 diff for the digests.
resp, err := regc.Registry().DiffImage(ctx, &registry.DiffImageRequest{
RepoId: repoUIDP,
FromDigest: left,
ToDigest: right,
})
if err != nil {
log.Fatalf("diff: %v", err)
}

b, err := json.MarshalIndent(resp, "", " ")
if err != nil {
log.Fatalf("marshaling response: %v", err)
}
fmt.Println(string(b))
}
62 changes: 62 additions & 0 deletions image-diff/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
module github.com/chainguard-dev/enforce-events/image-diff

go 1.21

toolchain go1.21.0

require (
chainguard.dev/sdk v0.1.1
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 1e80168

Please sign in to comment.