Skip to content

Commit

Permalink
add history inspect attachment command
Browse files Browse the repository at this point in the history
Signed-off-by: Tonis Tiigi <[email protected]>
  • Loading branch information
tonistiigi committed Jan 10, 2025
1 parent 18e8e55 commit 6489c8f
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 0 deletions.
4 changes: 4 additions & 0 deletions commands/history/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ func inspectCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
ValidArgsFunction: completion.Disable,
}

cmd.AddCommand(
attachmentCmd(dockerCli, rootOpts),
)

// flags := cmd.Flags()

return cmd
Expand Down
152 changes: 152 additions & 0 deletions commands/history/inspect_attachment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package history

import (
"context"
"io"
"slices"

"github.com/containerd/containerd/content/proxy"
"github.com/containerd/platforms"
"github.com/docker/buildx/builder"
"github.com/docker/buildx/util/cobrautil/completion"
"github.com/docker/cli/cli/command"
intoto "github.com/in-toto/in-toto-golang/in_toto"
slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
"github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

type attachmentOptions struct {
builder string
typ string
platform string
ref string
digest digest.Digest
}

func runAttachment(ctx context.Context, dockerCli command.Cli, opts attachmentOptions) error {
b, err := builder.New(dockerCli, builder.WithName(opts.builder))
if err != nil {
return err
}

nodes, err := b.LoadNodes(ctx)
if err != nil {
return err
}
for _, node := range nodes {
if node.Err != nil {
return node.Err
}
}

recs, err := queryRecords(ctx, opts.ref, nodes)
if err != nil {
return err
}

if len(recs) == 0 {
if opts.ref == "" {
return errors.New("no records found")
}
return errors.Errorf("no record found for ref %q", opts.ref)
}

if opts.ref == "" {
slices.SortFunc(recs, func(a, b historyRecord) int {
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
})
}

rec := &recs[0]

c, err := rec.node.Driver.Client(ctx)
if err != nil {
return err
}

store := proxy.NewContentStore(c.ContentClient())

if opts.digest != "" {
ra, err := store.ReaderAt(ctx, ocispecs.Descriptor{Digest: opts.digest})
if err != nil {
return err
}
_, err = io.Copy(dockerCli.Out(), io.NewSectionReader(ra, 0, ra.Size()))
return err
}

attachments, err := allAttachments(ctx, store, *rec)
if err != nil {
return err
}

typ := opts.typ
switch typ {
case "index":
typ = ocispecs.MediaTypeImageIndex
case "manifest":
typ = ocispecs.MediaTypeImageManifest
case "image":
typ = ocispecs.MediaTypeImageConfig
case "provenance":
typ = slsa02.PredicateSLSAProvenance
case "sbom":
typ = intoto.PredicateSPDX
}

for _, a := range attachments {
if opts.platform != "" && (a.platform == nil || platforms.FormatAll(*a.platform) != opts.platform) {
continue
}
if typ != "" && descrType(a.descr) != typ {
continue
}
ra, err := store.ReaderAt(ctx, a.descr)
if err != nil {
return err
}
_, err = io.Copy(dockerCli.Out(), io.NewSectionReader(ra, 0, ra.Size()))
return err
}

return errors.Errorf("no matching attachment found for ref %q", opts.ref)
}

func attachmentCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
var options attachmentOptions

cmd := &cobra.Command{
Use: "attachment [OPTIONS] REF [DIGEST]",
Short: "Inspect a build attachment",
Args: cobra.RangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
options.ref = args[0]
}
if len(args) > 1 {
dgst, err := digest.Parse(args[1])
if err != nil {
return errors.Wrapf(err, "invalid digest %q", args[1])
}
options.digest = dgst
}

if options.digest == "" && options.platform == "" && options.typ == "" {
return errors.New("at least one of --type, --platform or DIGEST must be specified")
}

options.builder = *rootOpts.Builder
return runAttachment(cmd.Context(), dockerCli, options)
},
ValidArgsFunction: completion.Disable,
}

flags := cmd.Flags()
flags.StringVar(&options.typ, "type", "", "Type of attachment")
flags.StringVar(&options.platform, "platform", "", "Platform of attachment")

return cmd
}
7 changes: 7 additions & 0 deletions docs/reference/buildx_history_inspect.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
<!---MARKER_GEN_START-->
Inspect a build

### Subcommands

| Name | Description |
|:-----------------------------------------------------|:---------------------------|
| [`attachment`](buildx_history_inspect_attachment.md) | Inspect a build attachment |


### Options

| Name | Type | Default | Description |
Expand Down
17 changes: 17 additions & 0 deletions docs/reference/buildx_history_inspect_attachment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# docker buildx history inspect attachment

<!---MARKER_GEN_START-->
Inspect a build attachment

### Options

| Name | Type | Default | Description |
|:----------------|:---------|:--------|:-----------------------------------------|
| `--builder` | `string` | | Override the configured builder instance |
| `-D`, `--debug` | `bool` | | Enable debug logging |
| `--platform` | `string` | | Platform of attachment |
| `--type` | `string` | | Type of attachment |


<!---MARKER_GEN_END-->

0 comments on commit 6489c8f

Please sign in to comment.