Skip to content

Commit

Permalink
image-copy-gcr: use receiver.New (#118)
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Hall <jason@chainguard.dev>
  • Loading branch information
imjasonh authored Nov 23, 2023
1 parent 53e2921 commit 14b3206
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 37 deletions.
47 changes: 10 additions & 37 deletions image-copy-gcr/cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ import (
"log"
"net/http"
"path/filepath"
"strings"

"chainguard.dev/sdk/pkg/events"
"chainguard.dev/sdk/pkg/events/registry"
"cloud.google.com/go/compute/metadata"
"github.com/chainguard-dev/enforce-events/pkg/receiver"
cloudevents "github.com/cloudevents/sdk-go/v2"
cehttp "github.com/cloudevents/sdk-go/v2/protocol/http"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/name"
Expand Down Expand Up @@ -62,41 +61,8 @@ func main() {
log.Printf("location: %s", location)
log.Printf("sa: %s", sa)

c, err := cloudevents.NewClientHTTP(cloudevents.WithPort(env.Port),
// We need to infuse the request onto context, so we can
// authenticate requests.
cehttp.WithRequestDataAtContextMiddleware())
if err != nil {
log.Fatalf("failed to create client, %v", err)
}
ctx := context.Background()

// Construct a verifier that ensures tokens are issued by the Chainguard
// issuer we expect and are intended for a customer webhook.
provider, err := oidc.NewProvider(ctx, env.Issuer)
if err != nil {
log.Fatalf("failed to create provider: %v", err)
}
verifier := provider.Verifier(&oidc.Config{
ClientID: "customer",
})

receiver := func(ctx context.Context, event cloudevents.Event) error {
// We expect Chainguard webhooks to pass an Authorization header.
auth := strings.TrimPrefix(cehttp.RequestDataFromContext(ctx).Header.Get("Authorization"), "Bearer ")
if auth == "" {
return cloudevents.NewHTTPResult(http.StatusUnauthorized, "Unauthorized")
}

// Verify that the token is well-formed, and in fact intended for us!
if tok, err := verifier.Verify(ctx, auth); err != nil {
return cloudevents.NewHTTPResult(http.StatusForbidden, "unable to verify token: %w", err)
} else if !strings.HasPrefix(tok.Subject, "webhook:") {
return cloudevents.NewHTTPResult(http.StatusForbidden, "subject should be from the Chainguard webhook component, got: %s", tok.Subject)
} else if group := strings.TrimPrefix(tok.Subject, "webhook:"); group != env.Group {
return cloudevents.NewHTTPResult(http.StatusForbidden, "this token is intended for %s, wanted one for %s", group, env.Group)
}

receiver := receiver.New(ctx, env.Issuer, env.Group, func(ctx context.Context, event cloudevents.Event) error {
// We are handling a specific event type, so filter the rest.
if event.Type() != registry.PushedEventType {
return nil
Expand Down Expand Up @@ -125,8 +91,15 @@ func main() {
}
log.Println("Copied!")
return nil
}
})

c, err := cloudevents.NewClientHTTP(cloudevents.WithPort(env.Port),
// We need to infuse the request onto context, so we can
// authenticate requests.
cehttp.WithRequestDataAtContextMiddleware())
if err != nil {
log.Fatalf("failed to create client, %v", err)
}
if err := c.StartReceiver(ctx, func(ctx context.Context, event cloudevents.Event) error {
// This thunk simply wraps the main receiver in one that logs any errors
// we encounter.
Expand Down
1 change: 1 addition & 0 deletions image-copy-gcr/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ replace github.com/chainguard-dev/enforce-events => ../
require (
chainguard.dev/sdk v0.1.0
cloud.google.com/go/compute/metadata v0.2.3
github.com/chainguard-dev/enforce-events v0.0.0-20231121174021-bd68cdb48f4f
github.com/cloudevents/sdk-go/v2 v2.14.0
github.com/coreos/go-oidc/v3 v3.6.0
github.com/google/go-containerregistry v0.16.1
Expand Down

0 comments on commit 14b3206

Please sign in to comment.