Merge pull request #13 from docker/feat--add-attest-sign/verify

feat: add attest sign/verify
This commit is contained in:
Joel Kamp
2024-04-30 16:29:09 -05:00
committed by GitHub
70 changed files with 1710 additions and 19 deletions

130
README.md
View File

@@ -1,2 +1,130 @@
# attest
Library to create, verify, and evaluate policy for attestations on container images
library to create, verify, and evaluate policy for attestations on container images
# usage
## verifying attestations
1. create a TUF client
* using OCI registry for TUF
```go
tufOutputPath = "/.docker/tuf"
metadataURI = "docker/tuf-metadata:latest"
targetsURI = "docker/tuf-targets"
tufClient, err := tuf.NewTufClient(embed.DefaultRoot, tufOutputPath, metadataURI, targetsURI)
```
* using HTTPS for TUF
```go
tufOutputPath = "/.docker/tuf"
metadataURI = "https://docker.github.io/tuf/metadata"
targetsURI = "https://docker.github.io/tuf/targets"
tufClient, err := tuf.NewTufClient(embed.DefaultRoot, tufOutputPath, metadataURI, targetsURI)
```
1. configure an attestation resolver
* using OCI registry
```go
var resolver oci.AttestationResolver
resolver = &oci.RegistryResolver{
Image: image, // path to image index in OCI registry containing image attestations (e.g. docker/nginx:latest)
Platform: platform, // platform of subject image (image that attestations are being verified against)
}
```
* using local OCI layout
```go
var resolver oci.AttestationResolver
resolver = &oci.OCILayoutResolver{
Path: path, // file path to OCI layout containing image attestations (e.g. /myimage)
Platform: platform, // platform of subject image (image that attestations are being verified against)
}
```
1. configure policy options
```go
opts := &policy.PolicyOptions{
TufClient: tufClient,
LocalTargetsDir: "/.docker/policy", // location to store policy files downloaded from TUF
LocalPolicyDir: "", // overrides TUF policy for local policy files
}
```
1. verify attestations
```go
policy, err := attest.Verify(ctx, opts, resolver)
if err != nil {
return false // failed policy or attestation signature verification
}
if policy {
return true // passed policy
}
return true // no policy for image
```
## signing attestations
1. generate an image with intoto Statements (optional)
```sh
docker buildx build <PATH TO DOCKERFILE> --sbom true --provenance true --output type=oci,tar=false,name=<REPO>:<TAG>,dest=<OUTPUT DIR>
```
1. confgiure a `dsse.SignerVerifier`
```go
var signer dsse.SignerVerifier
signer, err = signerverifier.GetAWSSigner(cmd.Context(), aws_arn, aws_region)
```
1. configure signing options
```go
opts := &attest.SigningOptions{
Replace: true, // replace unsigned intoto statements with signed intoto attestations, otherwise leave in place
}
```
* add [Verification Summary Attestation (VSA)](https://slsa.dev/spec/v1.0/verification_summary) for all intoto attestations (optional)
```go
opts.VSAOptions = &attestation.VSAOptions{
BuildLevel: "SLSA_BUILD_LEVEL_" + slsaBuildLevel,
PolicyURI: slsaPolicyUri,
VerifierID: slsaVerifierId,
}
```
1. load attestations
* oci registry
```go
ref := "docker/attest:latest"
att, err := oci.AttestationIndexFromRemote(ref)
```
* local filepath
```go
path := "/test-image"
att, err := oci.AttestationIndexFromPath(path)
```
1. sign attestations
```go
signedImageIndex, err := attest.Sign(ctx, att, signer, opts)
```
`attest.Sign()` iterates over attestation manifests in the image index and signs all intoto statements (optionally generates a VSA), returning a mutated ImageIndex with all intoto statements signed as attestations.
1. save output (optional)
* push to oci registry
```go
err = mirror.PushToRegistry(signedImageIndex, ref)
```
* save to local filesystem
```go
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: signedImageIndex,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
oci.OciReferenceTarget: att.Name,
},
},
})
err = mirror.SaveAsOCILayout(idx, path)
```
## mirroring TUF repositories
TODO: write content for this outline
### mirroring TUF metadata to OCI
#### delegated metadata
### mirroring TUF targets to OCI
#### delegated targets
### using `go-tuf` OCI registry client

View File

@@ -2,13 +2,22 @@ package test
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"os"
"strings"
"testing"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/docker/attest/pkg/signerverifier"
"github.com/docker/attest/pkg/tlog"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/google/go-containerregistry/pkg/v1/partial"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
@@ -77,10 +86,121 @@ func GetMockSigner(ctx context.Context) (dsse.SignerVerifier, error) {
return signerverifier.GenKeyPair()
}
type MockPolicyEvaluator struct {
EvaluateFunc func(ctx context.Context, resolver oci.AttestationResolver, policy []*policy.PolicyFile, input *policy.PolicyInput) error
}
func (pe *MockPolicyEvaluator) Evaluate(ctx context.Context, resolver oci.AttestationResolver, policy []*policy.PolicyFile, input *policy.PolicyInput) error {
if pe.EvaluateFunc != nil {
return pe.EvaluateFunc(ctx, resolver, policy, input)
}
return nil
}
func GetMockPolicy() policy.PolicyEvaluator {
return &policy.MockPolicyEvaluator{
return &MockPolicyEvaluator{
EvaluateFunc: func(ctx context.Context, resolver oci.AttestationResolver, policy []*policy.PolicyFile, input *policy.PolicyInput) error {
return nil
},
}
}
type AnnotatedStatement struct {
OCIDescriptor *v1.Descriptor
InTotoStatement *intoto.Statement
Annotations map[string]string
}
func ExtractAnnotatedStatements(path string, mediaType string) ([]*AnnotatedStatement, error) {
idx, err := layout.ImageIndexFromPath(path)
if err != nil {
return nil, fmt.Errorf("failed to load image index: %w", err)
}
idxm, err := idx.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to get digest: %w", err)
}
idxDigest := idxm.Manifests[0].Digest
mfs, err := idx.ImageIndex(idxDigest)
if err != nil {
return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", idxDigest.String(), err)
}
mfs2, err := mfs.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err)
}
var statements []*AnnotatedStatement
for _, mf := range mfs2.Manifests {
if mf.Annotations["vnd.docker.reference.type"] != "attestation-manifest" {
continue
}
attestationImage, err := mfs.Image(mf.Digest)
if err != nil {
return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", mf.Digest.String(), err)
}
layers, err := attestationImage.Layers()
if err != nil {
return nil, fmt.Errorf("failed to extract layers from attestation image: %w", err)
}
for _, layer := range layers {
// parse layer blob as json
mt, err := layer.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get layer media type: %w", err)
}
if string(mt) != mediaType {
continue
}
r, err := layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("failed to get layer contents: %w", err)
}
defer r.Close()
var intotoStatement = new(intoto.Statement)
var desc *v1.Descriptor
if strings.HasSuffix(string(mt), "+dsse") {
var env = new(attestation.Envelope)
err = json.NewDecoder(r).Decode(env)
if err != nil {
return nil, fmt.Errorf("failed to decode env: %w", err)
}
payload, err := base64.StdEncoding.Strict().DecodeString(env.Payload)
if err != nil {
return nil, fmt.Errorf("failed to decode payload: %w", err)
}
err = json.Unmarshal([]byte(payload), intotoStatement)
if err != nil {
return nil, fmt.Errorf("failed to decode %s statement: %w", mediaType, err)
}
} else {
desc := new(v1.Descriptor)
err = json.NewDecoder(r).Decode(desc)
if err != nil {
return nil, fmt.Errorf("failed to decode statement: %w", err)
}
}
layerDesc, err := partial.Descriptor(layer)
if err != nil {
return nil, fmt.Errorf("failed to get descriptor for layer: %w", err)
}
annotations := make(map[string]string)
for k, v := range layerDesc.Annotations {
annotations[k] = v
}
statements = append(statements, &AnnotatedStatement{
OCIDescriptor: desc,
InTotoStatement: intotoStatement,
Annotations: annotations,
})
}
}
return statements, nil
}

View File

@@ -0,0 +1,23 @@
package test
import (
"path/filepath"
"testing"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/stretchr/testify/assert"
)
var (
UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
)
const (
ExpectedStatements = 4
)
func TestExtractAnnotatedStatements(t *testing.T) {
statements, err := ExtractAnnotatedStatements(UnsignedTestImage, intoto.PayloadType)
assert.NoError(t, err)
assert.Equalf(t, len(statements), ExpectedStatements, "expected %d statement, got %d", ExpectedStatements, len(statements))
}

139
pkg/attest/sign.go Normal file
View File

@@ -0,0 +1,139 @@
package attest
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/attest/pkg/attestation"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/match"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/partial"
"github.com/google/go-containerregistry/pkg/v1/static"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
func Sign(ctx context.Context, idx v1.ImageIndex, signer dsse.SignerVerifier, opts *SigningOptions) (v1.ImageIndex, error) {
// extract attestation manifests from index
attestationManifests, err := attestation.GetAttestationManifestsFromIndex(idx)
if err != nil {
return nil, fmt.Errorf("failed to get attestation manifests: %w", err)
}
// sign every attestation layer in each manifest
for _, manifest := range attestationManifests {
attestationLayers, err := attestation.GetAttestationsFromImage(manifest.Attestation.Image)
if err != nil {
return nil, fmt.Errorf("failed to get attestations from image: %w", err)
}
signedLayers, err := signLayers(ctx, attestationLayers, signer)
if err != nil {
return nil, fmt.Errorf("failed to sign attestations: %w", err)
}
if opts.VSAOptions != nil {
newLayer, err := generateVSA(ctx, manifest, signer, opts)
if err != nil {
return nil, fmt.Errorf("failed to generate VSA: %w", err)
}
signedLayers = append(signedLayers, *newLayer)
}
newImg, err := addSignedLayers(signedLayers, manifest, opts)
if err != nil {
return nil, fmt.Errorf("failed to add signed layers: %w", err)
}
newDesc, err := partial.Descriptor(newImg)
if err != nil {
return nil, fmt.Errorf("failed to get descriptor: %w", err)
}
cf, err := manifest.Attestation.Image.ConfigFile()
if err != nil {
return nil, fmt.Errorf("failed to get config file: %w", err)
}
newDesc.Platform = cf.Platform()
newDesc.MediaType = manifest.MediaType
newDesc.Annotations = manifest.Annotations
idx = mutate.RemoveManifests(idx, match.Digests(manifest.Digest))
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: newImg,
Descriptor: *newDesc,
})
}
return idx, nil
}
// signLayers signs each intoto attestation layer with the given signer
func signLayers(ctx context.Context, layers []attestation.AttestationLayer, signer dsse.SignerVerifier) ([]mutate.Addendum, error) {
var signedLayers []mutate.Addendum
for _, layer := range layers {
// only sign intoto layers
if layer.MediaType != types.MediaType(intoto.PayloadType) {
continue
}
// mark attestation as experimental
layer.Annotations[InTotoReferenceLifecycleStage] = LifecycleStageExperimental
// sign the statement
payload, err := json.Marshal(layer.Statement)
if err != nil {
return nil, fmt.Errorf("failed to marshal statement: %w", err)
}
env, err := attestation.SignDSSE(ctx, payload, intoto.PayloadType, signer)
if err != nil {
return nil, fmt.Errorf("failed to sign statement: %w", err)
}
mediaType, err := attestation.DSSEMediaType(layer.Statement.PredicateType)
if err != nil {
return nil, fmt.Errorf("failed to get DSSE media type: %w", err)
}
data, err := json.Marshal(env)
if err != nil {
return nil, fmt.Errorf("failed to marshal envelope: %w", err)
}
newLayer := static.NewLayer(data, types.MediaType(mediaType))
withAnnotations := mutate.Addendum{
Layer: newLayer,
Annotations: layer.Annotations,
}
signedLayers = append(signedLayers, withAnnotations)
}
return signedLayers, nil
}
// addSignedLayers adds signed layers to a new or existing attestation image
func addSignedLayers(signedLayers []mutate.Addendum, manifest attestation.AttestationManifest, opts *SigningOptions) (v1.Image, error) {
var err error
if opts.Replace {
// create a new attestation image with only signed layers
newImg := empty.Image
newImg = mutate.MediaType(newImg, manifest.MediaType)
newImg = mutate.ConfigMediaType(newImg, "application/vnd.oci.image.config.v1+json")
for _, layer := range signedLayers {
newImg, err = mutate.Append(newImg, layer)
if err != nil {
return nil, fmt.Errorf("failed to append signed layer: %w", err)
}
}
// add any existing unsigned (non-intoto) layers to the new image
for _, layer := range manifest.Attestation.Layers {
if layer.MediaType != types.MediaType(intoto.PayloadType) {
newImg, err = mutate.AppendLayers(newImg, layer.Layer)
if err != nil {
return nil, fmt.Errorf("failed to append unsigned layer: %w", err)
}
}
}
return newImg, nil
}
// Add signed layers to the existing image
for _, layer := range signedLayers {
manifest.Attestation.Image, err = mutate.Append(manifest.Attestation.Image, layer)
if err != nil {
return nil, fmt.Errorf("failed to append layer: %w", err)
}
}
return manifest.Attestation.Image, nil
}

165
pkg/attest/sign_test.go Normal file
View File

@@ -0,0 +1,165 @@
package attest
import (
"encoding/json"
"path/filepath"
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/static"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
"github.com/stretchr/testify/assert"
)
var (
UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
NoProvenanceImage = filepath.Join("..", "..", "test", "testdata", "no-provenance-image")
LocalPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy")
TestTempDir = "attest-sign-test"
)
func TestSignVerifyOCILayout(t *testing.T) {
ctx, signer := test.Setup(t)
testCases := []struct {
name string
TestImage string
expectedStatements int
expectedAttestations int
replace bool
}{
{"signed replaced (does nothing)", UnsignedTestImage, 0, 6, true},
{"without replace", UnsignedTestImage, 4, 6, false},
// image without provenance doesn't fail
{"no provenance (replace)", NoProvenanceImage, 0, 4, true},
{"no provenance (no replace)", NoProvenanceImage, 2, 4, false},
}
policyResolver := &policy.PolicyOptions{
LocalPolicyDir: LocalPolicyDir,
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tempDir := test.CreateTempDir(t, "", TestTempDir)
outputLayout := tempDir
opts := &SigningOptions{
Replace: tc.replace,
VSAOptions: &attestation.VSAOptions{
BuildLevel: "SLSA_BUILD_LEVEL_3",
PolicyURI: "https://docker.com/attest/policy",
VerifierID: "https://docker.com",
},
}
attIdx, err := oci.AttestationIndexFromPath(tc.TestImage)
assert.NoError(t, err)
signedIndex, err := Sign(ctx, attIdx.Index, signer, opts)
assert.NoError(t, err)
// output signed attestations
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: signedIndex,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
oci.OciReferenceTarget: attIdx.Name,
},
},
})
_, err = layout.Write(outputLayout, idx)
assert.NoError(t, err)
resolver := &oci.OCILayoutResolver{
Path: outputLayout,
Platform: "",
}
policy, err := Verify(ctx, policyResolver, resolver)
assert.NoError(t, err)
assert.Truef(t, policy, "Policy should have been found")
mt, _ := attestation.DSSEMediaType(attestation.VSAPredicateType)
vsas, err := test.ExtractAnnotatedStatements(tempDir, mt)
assert.NoError(t, err)
assert.Equalf(t, len(vsas), 2, "expected %d vsa statement, got %d", 2, len(vsas))
var allEnvelopes []*test.AnnotatedStatement
for _, predicate := range []string{intoto.PredicateSPDX, v02.PredicateSLSAProvenance, attestation.VSAPredicateType} {
mt, _ := attestation.DSSEMediaType(predicate)
statements, err := test.ExtractAnnotatedStatements(tempDir, mt)
assert.NoError(t, err)
allEnvelopes = append(allEnvelopes, statements...)
for _, stmt := range statements {
assert.Equalf(t, predicate, stmt.Annotations[oci.InTotoPredicateType], "expected predicate-type annotation to be set to %s, got %s", predicate, stmt.Annotations[oci.InTotoPredicateType])
assert.Equalf(t, LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage], "expected reference lifecycle stage annotation to be set to %s, got %s", LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage])
}
}
assert.Equalf(t, tc.expectedAttestations, len(allEnvelopes), "expected %d attestations, got %d", tc.expectedAttestations, len(allEnvelopes))
statements, err := test.ExtractAnnotatedStatements(tempDir, intoto.PayloadType)
assert.NoError(t, err)
assert.Equalf(t, tc.expectedStatements, len(statements), "expected %d statement, got %d", tc.expectedStatements, len(statements))
})
}
}
func TestAddSignedLayerAnnotations(t *testing.T) {
testCases := []struct {
name string
replace bool
}{
{"replaced", true},
{"not replaced", false},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
data := []byte("signed")
signedLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType))
signedLayers := []mutate.Addendum{
{
Layer: signedLayer,
Annotations: map[string]string{"test": "test"},
},
}
data = []byte("test")
testLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType))
mediaType := types.OCIManifestSchema1
opts := &SigningOptions{
Replace: tc.replace,
}
manifest := attestation.AttestationManifest{
MediaType: mediaType,
Attestation: attestation.AttestationImage{
Image: empty.Image,
Layers: []attestation.AttestationLayer{
{
Layer: testLayer,
Statement: &intoto.Statement{},
},
},
},
}
newImg, err := addSignedLayers(signedLayers, manifest, opts)
assert.NoError(t, err)
mf, _ := newImg.RawManifest()
type Annotations struct {
Annotations map[string]string `json:"annotations"`
}
type Layers struct {
Layers []Annotations `json:"layers"`
}
l := &Layers{}
err = json.Unmarshal(mf, l)
assert.NoError(t, err)
_, ok := l.Layers[0].Annotations["test"]
assert.Truef(t, ok, "missing annotations")
})
}
}

15
pkg/attest/types.go Normal file
View File

@@ -0,0 +1,15 @@
package attest
import (
"github.com/docker/attest/pkg/attestation"
)
const (
InTotoReferenceLifecycleStage = "vnd.docker.lifecycle-stage"
LifecycleStageExperimental = "experimental"
)
type SigningOptions struct {
Replace bool
VSAOptions *attestation.VSAOptions
}

55
pkg/attest/verify.go Normal file
View File

@@ -0,0 +1,55 @@
package attest
import (
"context"
"fmt"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
)
func VerifyAttestations(ctx context.Context, resolver oci.AttestationResolver, files []*policy.PolicyFile) error {
digest, err := resolver.ImageDigest(ctx)
if err != nil {
return fmt.Errorf("failed to get image digest: %w", err)
}
name, err := resolver.ImageName(ctx)
if err != nil {
return fmt.Errorf("failed to get image name: %w", err)
}
purl, canonical, err := oci.RefToPURL(name, resolver.ImagePlatformStr())
if err != nil {
return fmt.Errorf("failed to convert ref to purl: %w", err)
}
input := &policy.PolicyInput{
Digest: digest,
Purl: purl,
IsCanonical: canonical,
}
evaluator, err := policy.GetPolicyEvaluator(ctx)
if err != nil {
return err
}
err = evaluator.Evaluate(ctx, resolver, files, input)
if err != nil {
return fmt.Errorf("policy evaluation failed: %w", err)
}
return nil
}
func Verify(ctx context.Context, opts *policy.PolicyOptions, resolver oci.AttestationResolver) (policyFound bool, err error) {
policyFiles, err := policy.ResolvePolicy(ctx, resolver, opts)
if err != nil {
return false, fmt.Errorf("failed to resolve policy: %w", err)
}
// no policy for image -> success
if policyFiles == nil {
return false, nil
}
// policy found -> verify
return true, VerifyAttestations(ctx, resolver, policyFiles)
}

61
pkg/attest/verify_test.go Normal file
View File

@@ -0,0 +1,61 @@
package attest
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/stretchr/testify/assert"
)
var (
ExampleAttestation = filepath.Join("..", "..", "test", "testdata", "example_attestation.json")
)
func TestVerifyAttestations(t *testing.T) {
ex, err := os.ReadFile(ExampleAttestation)
assert.NoError(t, err)
var env = new(attestation.Envelope)
err = json.Unmarshal(ex, env)
assert.NoError(t, err)
resolver := &oci.MockResolver{
Envs: []*attestation.Envelope{env},
}
testCases := []struct {
name string
policyEvaluationError error
expectedError error
}{
{"policy ok", nil, nil},
{"policy error", fmt.Errorf("policy error"), fmt.Errorf("policy evaluation failed: policy error")},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockPE := test.MockPolicyEvaluator{
EvaluateFunc: func(ctx context.Context, resolver oci.AttestationResolver, pfs []*policy.PolicyFile, input *policy.PolicyInput) error {
return tc.policyEvaluationError
},
}
ctx := policy.WithPolicyEvaluator(context.Background(), &mockPE)
err = VerifyAttestations(ctx, resolver, nil)
if tc.expectedError != nil {
assert.Error(t, err)
assert.Equal(t, tc.expectedError.Error(), err.Error())
} else {
assert.NoError(t, err)
}
})
}
}

96
pkg/attest/vsa.go Normal file
View File

@@ -0,0 +1,96 @@
package attest
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/static"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
// generateVSA generates a VSA from the attestation manifest
// TODO: remove signing logic and move generateVSA to attestation/vsa.go
func generateVSA(ctx context.Context, manifest attestation.AttestationManifest, signer dsse.SignerVerifier, opts *SigningOptions) (*mutate.Addendum, error) {
if len(manifest.Attestation.Layers) == 0 {
return nil, fmt.Errorf("no attestations found to generate VSA from")
}
sub := manifest.Attestation.Layers[0].Statement.Subject[0]
stype := manifest.Attestation.Layers[0].Statement.Type
uri, err := attestation.ToVSAResourceURI(sub)
if err != nil {
return nil, fmt.Errorf("failed to generate VSA resource URI: %w", err)
}
inputs := make([]attestation.VSAInputAttestation, 0, len(manifest.Attestation.Layers))
for _, att := range manifest.Attestation.Layers {
mt, err := att.Layer.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get layer media type: %w", err)
}
if !strings.HasSuffix(string(mt), "+dsse") {
continue
}
dgst, err := att.Layer.Digest()
if err != nil {
return nil, fmt.Errorf("failed to get layer digest: %w", err)
}
inputs = append(inputs, attestation.VSAInputAttestation{
Digest: map[string]string{"sha256": dgst.Hex},
MediaType: string(mt),
})
}
vsaStatement := &intoto.Statement{
StatementHeader: intoto.StatementHeader{
PredicateType: attestation.VSAPredicateType,
Type: stype,
Subject: manifest.Attestation.Layers[0].Statement.Subject,
},
Predicate: attestation.VSAPredicate{
Verifier: attestation.VSAVerifier{
ID: opts.VSAOptions.VerifierID,
},
TimeVerified: time.Now().UTC().Format(time.RFC3339),
ResourceUri: uri,
Policy: attestation.VSAPolicy{URI: opts.VSAOptions.PolicyURI},
VerificationResult: "PASSED",
VerifiedLevels: []string{opts.VSAOptions.BuildLevel},
InputAttestations: inputs,
},
}
payload, err := json.Marshal(vsaStatement)
if err != nil {
return nil, fmt.Errorf("failed to marshal statement: %w", err)
}
env, err := attestation.SignDSSE(ctx, payload, intoto.PayloadType, signer)
if err != nil {
return nil, fmt.Errorf("failed to sign statement: %w", err)
}
mediaType, err := attestation.DSSEMediaType(vsaStatement.PredicateType)
if err != nil {
return nil, fmt.Errorf("failed to get DSSE media type: %w", err)
}
data, err := json.Marshal(env)
if err != nil {
return nil, fmt.Errorf("failed to marshal envelope: %w", err)
}
mt := types.MediaType(mediaType)
newLayer := static.NewLayer(data, mt)
ann := make(map[string]string)
ann[InTotoReferenceLifecycleStage] = LifecycleStageExperimental
ann[oci.InTotoPredicateType] = attestation.VSAPredicateType
withAnnotations := mutate.Addendum{
Layer: newLayer,
Annotations: ann,
}
return &withAnnotations, nil
}

View File

@@ -0,0 +1,82 @@
package attestation
import (
"encoding/json"
"fmt"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/partial"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
)
// GetAttestationManifestsFromIndex extracts all attestation manifests from an index
func GetAttestationManifestsFromIndex(index v1.ImageIndex) ([]AttestationManifest, error) {
idx, err := index.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err)
}
var attestationManifests []AttestationManifest
for _, manifest := range idx.Manifests {
if manifest.Annotations[DockerReferenceType] == AttestationManifestType {
attestationImage, err := index.Image(manifest.Digest)
if err != nil {
return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", manifest.Digest.String(), err)
}
attestationLayers, err := GetAttestationsFromImage(attestationImage)
if err != nil {
return nil, fmt.Errorf("failed to get attestations from image: %w", err)
}
attestationManifests = append(attestationManifests,
AttestationManifest{
Manifest: manifest,
Attestation: AttestationImage{
Layers: attestationLayers,
Image: attestationImage},
MediaType: manifest.MediaType,
Annotations: manifest.Annotations,
Digest: manifest.Digest})
}
}
return attestationManifests, nil
}
// GetAttestationsFromImage extracts all attestation layers from an image
func GetAttestationsFromImage(image v1.Image) ([]AttestationLayer, error) {
layers, err := image.Layers()
if err != nil {
return nil, fmt.Errorf("failed to extract layers from image: %w", err)
}
var attestationLayers []AttestationLayer
for _, layer := range layers {
// parse layer blob as json
r, err := layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("failed to get layer contents: %w", err)
}
defer r.Close()
mt, err := layer.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get layer media type: %w", err)
}
layerDesc, err := partial.Descriptor(layer)
if err != nil {
return nil, fmt.Errorf("failed to get descriptor for layer: %w", err)
}
// copy original annotations
ann := make(map[string]string)
for k, v := range layerDesc.Annotations {
ann[k] = v
}
// only decode intoto statements
var stmt = new(intoto.Statement)
if mt == types.MediaType(intoto.PayloadType) {
err = json.NewDecoder(r).Decode(&stmt)
if err != nil {
return nil, fmt.Errorf("failed to decode statement layer contents: %w", err)
}
}
attestationLayers = append(attestationLayers, AttestationLayer{Layer: layer, MediaType: mt, Statement: stmt, Annotations: ann})
}
return attestationLayers, nil
}

View File

@@ -1,14 +1,46 @@
package attestation
import "encoding/base64"
import (
"encoding/base64"
"fmt"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
)
const (
DockerDsseExtKind = "application/vnd.docker.attestation-verification.v1+json"
RekorTlExtKind = "Rekor"
DockerReferenceType = "vnd.docker.reference.type"
AttestationManifestType = "attestation-manifest"
DockerDsseExtKind = "application/vnd.docker.attestation-verification.v1+json"
RekorTlExtKind = "Rekor"
OCIDescriptorDSSEMediaType = ociv1.MediaTypeDescriptor + "+dsse"
)
var base64Encoding = base64.StdEncoding.Strict()
type AttestationLayer struct {
Statement *intoto.Statement
Layer v1.Layer
MediaType types.MediaType
Annotations map[string]string
}
type AttestationImage struct {
Layers []AttestationLayer
Image v1.Image
}
type AttestationManifest struct {
Manifest v1.Descriptor
Attestation AttestationImage
MediaType types.MediaType
Annotations map[string]string
Digest v1.Hash
}
// the following types are needed until https://github.com/secure-systems-lab/dsse/pull/61 is merged
type Envelope struct {
PayloadType string `json:"payloadType"`
@@ -33,3 +65,20 @@ type DockerTlExtension struct {
Kind string `json:"kind"`
Data any `json:"data"`
}
func DSSEMediaType(predicateType string) (string, error) {
var predicateName string
switch predicateType {
case v02.PredicateSLSAProvenance:
predicateName = "provenance"
case intoto.PredicateSPDX:
predicateName = "spdx"
case VSAPredicateType:
predicateName = "verification_summary"
default:
return "", fmt.Errorf("unknown predicate type %q", predicateType)
}
return fmt.Sprintf("application/vnd.in-toto.%s+dsse", predicateName), nil
}

55
pkg/attestation/vsa.go Normal file
View File

@@ -0,0 +1,55 @@
package attestation
import (
"fmt"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/package-url/packageurl-go"
)
const (
VSAPredicateType = "https://slsa.dev/verification_summary/v1"
)
type VSAPredicate struct {
Verifier VSAVerifier `json:"verifier"`
TimeVerified string `json:"timeVerified"`
ResourceUri string `json:"resourceUri"`
Policy VSAPolicy `json:"policy"`
InputAttestations []VSAInputAttestation `json:"inputAttestations"`
VerificationResult string `json:"verificationResult"`
VerifiedLevels []string `json:"verifiedLevels"`
}
type VSAVerifier struct {
ID string `json:"id"`
}
type VSAPolicy struct {
URI string `json:"uri"`
}
type VSAInputAttestation struct {
Digest map[string]string `json:"digest"`
MediaType string `json:"mediaType"`
}
type VSAOptions struct {
BuildLevel string
PolicyURI string
VerifierID string
}
func ToVSAResourceURI(sub intoto.Subject) (string, error) {
//parse purl
purl, err := packageurl.FromString(sub.Name)
if err != nil {
return "", fmt.Errorf("failed to parse package url: %w", err)
}
quals := purl.Qualifiers.Map()
if quals["digest"] == "" {
quals["digest"] = "sha256:" + sub.Digest["sha256"]
}
purl.Qualifiers = packageurl.QualifiersFromMap(quals)
return purl.String(), nil
}

View File

@@ -48,7 +48,9 @@ func PushToRegistry(image any, imageName string) error {
return fmt.Errorf("failed to push image index %s: %w", imageName, err)
}
default:
return fmt.Errorf("unknown image type: %T", image)
if err := remote.WriteIndex(ref, image.(v1.ImageIndex), remote.WithAuth(auth)); err != nil {
return fmt.Errorf("failed to push image index %s: %w", imageName, err)
}
}
return nil
}
@@ -76,7 +78,10 @@ func SaveAsOCILayout(image any, path string) error {
return fmt.Errorf("failed to create index: %w", err)
}
default:
return fmt.Errorf("unknown image type: %T", image)
_, err := layout.Write(path, image.(v1.ImageIndex))
if err != nil {
return fmt.Errorf("failed to create index: %w", err)
}
}
return nil
}

View File

@@ -1,8 +1,69 @@
package oci
import (
"fmt"
"log"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/google/go-containerregistry/pkg/v1/remote"
)
const (
DockerReferenceType = "vnd.docker.reference.type"
DockerReferenceDigest = "vnd.docker.reference.digest"
AttestationManifestType = "attestation-manifest"
InTotoPredicateType = "in-toto.io/predicate-type"
OciReferenceTarget = "org.opencontainers.image.ref.name"
)
type AttestationIndex struct {
Index v1.ImageIndex
Name string
}
func AttestationIndexFromPath(path string) (*AttestationIndex, error) {
wrapperIdx, err := layout.ImageIndexFromPath(path)
if err != nil {
return nil, fmt.Errorf("failed to load image index: %w", err)
}
idxm, err := wrapperIdx.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to get digest: %w", err)
}
imageName := idxm.Manifests[0].Annotations[OciReferenceTarget]
idxDigest := idxm.Manifests[0].Digest
idx, err := wrapperIdx.ImageIndex(idxDigest)
if err != nil {
return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", idxDigest.String(), err)
}
return &AttestationIndex{
Index: idx,
Name: imageName,
}, nil
}
func AttestationIndexFromRemote(image string) (*AttestationIndex, error) {
ref, err := name.ParseReference(image)
if err != nil {
log.Fatalf("Failed to parse image name: %v", err)
}
// Get the authenticator from the default Docker keychain
auth, err := authn.DefaultKeychain.Resolve(ref.Context())
if err != nil {
log.Fatalf("Failed to get authenticator: %v", err)
}
// Pull the image from the registry
idx, err := remote.Index(ref, remote.WithAuth(auth))
if err != nil {
return nil, fmt.Errorf("failed to pull image %s: %w", image, err)
}
return &AttestationIndex{
Index: idx,
Name: image,
}, nil
}

View File

@@ -28,14 +28,3 @@ func GetPolicyEvaluator(ctx context.Context) (PolicyEvaluator, error) {
type PolicyEvaluator interface {
Evaluate(ctx context.Context, resolver oci.AttestationResolver, policy []*PolicyFile, input *PolicyInput) error
}
type MockPolicyEvaluator struct {
EvaluateFunc func(ctx context.Context, resolver oci.AttestationResolver, policy []*PolicyFile, input *PolicyInput) error
}
func (pe *MockPolicyEvaluator) Evaluate(ctx context.Context, resolver oci.AttestationResolver, policy []*PolicyFile, input *PolicyInput) error {
if pe.EvaluateFunc != nil {
return pe.EvaluateFunc(ctx, resolver, policy, input)
}
return nil
}

View File

@@ -98,7 +98,6 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
policyFiles, err := policy.ResolvePolicy(ctx, tc.resolver, tc.policy)
assert.NoErrorf(t, err, "failed to resolve policy")
err = re.Evaluate(ctx, tc.resolver, policyFiles, tc.input)
if tc.expectSuccess {
assert.NoErrorf(t, err, "Evaluate failed")
} else {

View File

@@ -23,6 +23,7 @@ import (
type regoEvaluator struct {
debug bool
query string
}
func NewRegoEvaluator(debug bool) PolicyEvaluator {

45
scripts/gen-testdata.sh Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash
set -eo pipefail
echo "Starting the process to generate testdata..."
# Define functions
function check_command () {
command -v "$1" >/dev/null 2>&1 || { echo >&2 "This script requires $1 but it's not installed. Aborting."; exit 1; }
}
function cleanup_testdata () {
echo "Cleaning up existing testdata..."
rm -rf "${TESTDATA_PATH:?}/${UNSIGNED_IMAGE_DIR:?}"
rm -rf "${TESTDATA_PATH:?}/${NO_PROVENANCE_IMAGE_DIR:?}"
}
function build_unsigned_image () {
echo "Building $UNSIGNED_IMAGE_DIR..."
docker buildx build "$TEST_IMAGE_DOCKERFILE_PATH" --sbom true --provenance true --platform linux/amd64,linux/arm64 \
--output type=oci,tar=false,name="$TEST_IMAGE_REPO:$TEST_IMAGE_TAG",dest="$TESTDATA_PATH/$UNSIGNED_IMAGE_DIR"
}
function build_no_provenance_image () {
echo "Building unsigned $NO_PROVENANCE_IMAGE_DIR..."
docker buildx build "$TEST_IMAGE_DOCKERFILE_PATH" --sbom true --provenance false --platform linux/amd64,linux/arm64 \
--output type=oci,tar=false,name="$TEST_IMAGE_REPO:$TEST_IMAGE_TAG",dest="$TESTDATA_PATH/$NO_PROVENANCE_IMAGE_DIR"
}
# Check required commands
check_command docker
TESTDATA_PATH="../test/testdata"
TEST_IMAGE_DOCKERFILE_PATH="../test"
TEST_IMAGE_REPO="test-image"
TEST_IMAGE_TAG="test"
UNSIGNED_IMAGE_DIR="unsigned-test-image"
NO_PROVENANCE_IMAGE_DIR="no-provenance-image"
ATTESTATION_PAYLOADTYPE="application/vnd.in-toto+json"
# Run steps
cleanup_testdata
build_unsigned_image
build_no_provenance_image
echo "Process completed successfully."

5
test/Dockerfile Normal file
View File

@@ -0,0 +1,5 @@
FROM alpine AS build
RUN echo "hello world" > /tmp/hello.txt
FROM scratch
COPY --from=build /tmp/hello.txt /

View File

@@ -0,0 +1 @@
{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}}

View File

@@ -0,0 +1,50 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"size": 476,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"size": 476,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:2aaebbb079957470e7c0adddbb054b2b4c01f717d408efba753da2bf6e8905da",
"size": 558,
"annotations": {
"vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:9b009d6b84b1ed941070b3f919823446286a674ad669d0baa8ab2c358aeb3a82",
"size": 558,
"annotations": {
"vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
}
]
}

View File

@@ -0,0 +1,19 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:b6ef78de3633e45d1c08019fbabb4464fabd6dd32e82c67ea2b2a3c4e8bacdf5",
"size": 167
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
}
]
}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e"]}}

View File

@@ -0,0 +1,16 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460",
"size": 453
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad",
"size": 116
}
]
}

View File

@@ -0,0 +1,19 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:2e82727457f04f320b643cb6e13bcbafb8e0dc0adc0443f1a25666f9518c5071",
"size": 167
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
}
]
}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850"]}}

View File

@@ -0,0 +1 @@
{"architecture":"arm64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}}

View File

@@ -0,0 +1,16 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe",
"size": 453
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad",
"size": 116
}
]
}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:1effe3a77c594e579388dc4553dbbe762e4457a099ab8b706e67f5f9fc934701","size":1607,"annotations":{"org.opencontainers.image.created":"2024-04-29T10:23:48Z","org.opencontainers.image.ref.name":"docker.io/library/test-image:test"}}]}

View File

@@ -0,0 +1 @@
{"imageLayoutVersion":"1.0.0"}

View File

@@ -0,0 +1,50 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"size": 476,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"size": 476,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:aeca14119e3242c51633a899438518217417e01414d18189a3cf71c07f2a02c3",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:6658b8ba1e1221a6288bf50cd7813f814e2baad70141a3e315b7c3476b0f476f",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
}
]
}

View File

@@ -0,0 +1 @@
{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:2953164d6cc6c8bb8271f78f9fb2003318350a8026ea082b63a249cfa60918a3",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:c6dd08ccc92ab60a87648a6b61fbf88d9287a936b285a8b4dde8893a1f4ffedf",
"size": 3944,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:c6dd08ccc92ab60a87648a6b61fbf88d9287a936b285a8b4dde8893a1f4ffedf"]}}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:8f94b6e2a8be82e2e5b562d73212578bb3a02e8c0da7fc175c79045e73519375"]}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"jckf4dzdrb4i99ygsshezjtsq","buildStartedOn":"2024-04-29T10:23:45.125886079Z","buildFinishedOn":"2024-04-29T10:23:46.287890106Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:4efcb3fab1b18d9764b436e8f9430f56dd8fee0f811ae064f8ec051e7ac5dec4":"step0","sha256:5c08b537da7192a6909348620c571138948f7874016718afc6d6d4e1569453d3":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:2a9b671f3fc9bc5ca967b616d96cbbdb6493e32d4f6abd8f7a191990e8efb289",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:8f94b6e2a8be82e2e5b562d73212578bb3a02e8c0da7fc175c79045e73519375",
"size": 3944,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:8f2f55fc493890c2482a1220844157f4b0c8a6445d220af741e9fee8099bf532"]}}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:c01e5307ec84299048d76f162abec6f8bee4c463103161ab772c774e7ae9dd6d"]}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"nkbtpuurp2ogre7j5hlfdrvma","buildStartedOn":"2024-04-26T14:24:49.386895737Z","buildFinishedOn":"2024-04-26T14:24:50.962885799Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"77b839051c1796c77a5383f1570585c7f3ff70ea","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:41e476230918469ca0be3275c43594cc0a909d01fdf0fe8b73f59c50d2c2d1b9":"step0","sha256:f1bd0b5d897e59fc7a5775b7082658676e06cc12674666e1713b56c38f7d1c0a":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:fed2c8841731e2cf1ceb53c49c6440fcd6d565a8658141914a8a07c127e00d7e",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:92d3311aa91737ff81e2a4c8e269e78c3c95df611b44580426c384d3f5057776",
"size": 3944,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1,50 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"size": 476,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"size": 476,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:9638ca53d2795806cf51b7461575c51e4a626a091dc2842b35cac18c787ff80f",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:8049aa9ad3479085066b31d02b74310803129c3eb1e22d2e62279f8c72340b55",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
}
]
}

View File

@@ -0,0 +1,16 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460",
"size": 453
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad",
"size": 116
}
]
}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:f634c4c53b03bf8ff917b61165631fda0cfe691a383e7b333269a53bf9a79c34",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:9fe102c03d71d47a24cd7fc7db8e7affc05fd9bf98eb027038b7daf176861e85",
"size": 3943,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"4sdluz1285kjezq148xqo3fcr","buildStartedOn":"2024-04-29T10:20:54.451240475Z","buildFinishedOn":"2024-04-29T10:20:56.48203241Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:8c30f94c18660dd82452640583d991e007708a353546172a422418107a360f48":"step1","sha256:e1d9e97f2a2942f94811bc5453568509de77e86328036ef73562ba0b56137db6":"step0"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"nkbtpuurp2ogre7j5hlfdrvma","buildStartedOn":"2024-04-26T14:24:49.386895737Z","buildFinishedOn":"2024-04-26T14:24:50.962885799Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"77b839051c1796c77a5383f1570585c7f3ff70ea","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:41e476230918469ca0be3275c43594cc0a909d01fdf0fe8b73f59c50d2c2d1b9":"step0","sha256:f1bd0b5d897e59fc7a5775b7082658676e06cc12674666e1713b56c38f7d1c0a":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"oufyhd0aciw714m1i5y6l09xz","buildStartedOn":"2024-04-19T16:25:04.209111656Z","buildFinishedOn":"2024-04-19T16:25:05.831440763Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"5914df2930aba701d6ddc3ba9272a5732dfe8ab4","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:18b166b594df5270bf6a4aa8dcd0a96b3635d0a23106d819620cbab2f3f5cf22":"step0","sha256:31d6cbba3f437cfb5933e60d5f4d2be69109c2fae9ed5ffe04da16931a459cca":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:3e64f9d2888ed9211fbf2c6b5853ea559248fdb4ab711bcea34b65c62f0e026b",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:8f2f55fc493890c2482a1220844157f4b0c8a6445d220af741e9fee8099bf532",
"size": 3943,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1,50 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"size": 476,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"size": 476,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:3883faf6acc3cae029364ed17ec2ce917fc9a500aab72f813d26fed8404e7162",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:f2b95cecafef9c22a5d059fac8f20e3645a45370e52abf9581dd4eedd152fce0",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
}
]
}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"4sdluz1285kjezq148xqo3fcr","buildStartedOn":"2024-04-29T10:20:54.451240475Z","buildFinishedOn":"2024-04-29T10:20:56.48203241Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:8c30f94c18660dd82452640583d991e007708a353546172a422418107a360f48":"step1","sha256:e1d9e97f2a2942f94811bc5453568509de77e86328036ef73562ba0b56137db6":"step0"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:371954672cfaa92735d6fbd70a787aac618a41d4c8ec8d6e12bd12d0cc601706"]}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:4e5988d06eee647cb901d4435830fbf13cf3ab1ae27ec91246b280514e6a7b33",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:c01e5307ec84299048d76f162abec6f8bee4c463103161ab772c774e7ae9dd6d",
"size": 3944,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"oufyhd0aciw714m1i5y6l09xz","buildStartedOn":"2024-04-19T16:25:04.209111656Z","buildFinishedOn":"2024-04-19T16:25:05.831440763Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"5914df2930aba701d6ddc3ba9272a5732dfe8ab4","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:18b166b594df5270bf6a4aa8dcd0a96b3635d0a23106d819620cbab2f3f5cf22":"step0","sha256:31d6cbba3f437cfb5933e60d5f4d2be69109c2fae9ed5ffe04da16931a459cca":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"jckf4dzdrb4i99ygsshezjtsq","buildStartedOn":"2024-04-29T10:23:45.125886079Z","buildFinishedOn":"2024-04-29T10:23:46.287890106Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:4efcb3fab1b18d9764b436e8f9430f56dd8fee0f811ae064f8ec051e7ac5dec4":"step0","sha256:5c08b537da7192a6909348620c571138948f7874016718afc6d6d4e1569453d3":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:5171425b78a2aedb43eb4e95083e64d3764c798507596ceded776c4ab038c224"]}}

View File

@@ -0,0 +1 @@
{"architecture":"arm64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}}

View File

@@ -0,0 +1 @@
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}}

View File

@@ -0,0 +1,16 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe",
"size": 453
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad",
"size": 116
}
]
}

View File

@@ -0,0 +1,50 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"size": 476,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"size": 476,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:26da286bbc886aa14d191808db8fcbbd5d8ec68cf0047f954133e76d8e73d71c",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:e0a9b9404ac2691b9b1c9ef217f22bb1e106efd5ee791640411764e1cf39ea2c",
"size": 836,
"annotations": {
"vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
}
]
}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:a4cf4b24f3fa8cd49a59e8fd4ef5ce285f0aa928d2651f7ec3d5a78276249dec",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:371954672cfaa92735d6fbd70a787aac618a41d4c8ec8d6e12bd12d0cc601706",
"size": 3944,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1,27 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:c9f436179969b60ec0bbd406b1340c501e59376a658b14b53c1828924c0ac668",
"size": 241
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"
}
},
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:5171425b78a2aedb43eb4e95083e64d3764c798507596ceded776c4ab038c224",
"size": 3944,
"annotations": {
"in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
}
}
]
}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:9fe102c03d71d47a24cd7fc7db8e7affc05fd9bf98eb027038b7daf176861e85"]}}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:92d3311aa91737ff81e2a4c8e269e78c3c95df611b44580426c384d3f5057776"]}}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:db8f2a6e112ea6396f57d073269ecfac61e8dcdad3a4a643dcb577522492f898","size":1607,"annotations":{"org.opencontainers.image.created":"2024-04-29T10:23:46Z","org.opencontainers.image.ref.name":"docker.io/library/test-image:test"}}]}

View File

@@ -0,0 +1 @@
{"imageLayoutVersion":"1.0.0"}