Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions pkg/attestation/crafter/api/attestation/v1/crafting_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import (
"strings"

v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/attestation"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/jacoco"
materialsjunit "github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/junit"
intoto "github.com/in-toto/attestation/go/v1"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
"google.golang.org/protobuf/types/known/structpb"
)

Expand Down Expand Up @@ -110,9 +110,10 @@ func (m *Attestation_Material) GetEvaluableContent(value string) ([]byte, error)

// special case for ATTESTATION materials, the statement needs to be extracted from the dsse wrapper.
if m.MaterialType == v1.CraftingSchema_Material_ATTESTATION {
var envelope dsse.Envelope
if err := json.Unmarshal(rawMaterial, &envelope); err != nil {
return nil, fmt.Errorf("failed to unmarshal attestation material: %w", err)
// support both DSSE envelope and Sigstore bundle
envelope, err := attestation.ExtractDSSEEnvelope(rawMaterial)
if err != nil {
return nil, fmt.Errorf("failed to extract DSSE envelope: %w", err)
}

rawMaterial, err = envelope.DecodeB64Payload()
Expand Down
47 changes: 21 additions & 26 deletions pkg/attestation/crafter/materials/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ package materials

import (
"context"
"encoding/json"
"fmt"
"os"
"path"

schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/pkg/attestation"
api "github.com/chainloop-dev/chainloop/pkg/attestation/crafter/api/attestation/v1"
attestation2 "github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/attestation"
"github.com/chainloop-dev/chainloop/pkg/attestation/renderer/chainloop"
"github.com/chainloop-dev/chainloop/pkg/casclient"
intoto "github.com/in-toto/attestation/go/v1"
"github.com/in-toto/in-toto-golang/in_toto"
"github.com/rs/zerolog"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
"google.golang.org/protobuf/encoding/protojson"
)

type AttestationCrafter struct {
Expand All @@ -54,37 +54,32 @@ func (i *AttestationCrafter) Craft(ctx context.Context, artifactPath string) (*a
if err != nil {
return nil, fmt.Errorf("artifact file cannot be read: %w", err)
}
var dsseEnvelope dsse.Envelope
if err := json.Unmarshal(data, &dsseEnvelope); err != nil {
return nil, fmt.Errorf("artifact is not a valid DSEE Envelope: %w", err)
}

predicate, err := chainloop.ExtractPredicate(&dsseEnvelope)
// extract the DSSE envelope (from the bundle if needed)
dsseEnvelope, err := attestation2.ExtractDSSEEnvelope(data)
if err != nil {
return nil, fmt.Errorf("the provided file does not seem to be a chainloop-generated attestation: %w", err)
return nil, fmt.Errorf("failed to parse the provided file as a DSSE envelope: %w", err)
}

// regenerate the json from the parsed data, just to remove any formating from the incoming json and preserve
// the digest
jsonContent, _, err := attestation.JSONEnvelopeWithDigest(&dsseEnvelope)
if err != nil {
return nil, fmt.Errorf("creating CAS payload: %w", err)
// run some validations
if dsseEnvelope.PayloadType != in_toto.PayloadType {
return nil, fmt.Errorf("the payload %q is not of type in-toto", dsseEnvelope.PayloadType)
}

// Create a temp file with this content and upload to the CAS
dir := os.TempDir()
filename := fmt.Sprintf("%s-%s-attestation.json", predicate.GetMetadata().Name, predicate.GetMetadata().WorkflowRunID)

file, err := os.Create(path.Join(dir, filename))
dec, err := dsseEnvelope.DecodeB64Payload()
if err != nil {
return nil, fmt.Errorf("failed to create temp file: %w", err)
return nil, fmt.Errorf("failed to decode the DSSE payload: %w", err)
}
defer file.Close()
defer os.Remove(file.Name())

if _, err := file.Write(jsonContent); err != nil {
return nil, fmt.Errorf("failed to write JSON payload: %w", err)
// decode the intoto payload
var intotoStatement intoto.Statement
if err = protojson.Unmarshal(dec, &intotoStatement); err != nil {
return nil, fmt.Errorf("failed to parse the DSSE payload as an in-toto statement: %w", err)
}
// check if the statement predicate is of expected type
if intotoStatement.PredicateType != chainloop.PredicateTypeV02 {
return nil, fmt.Errorf("the provided predicate is not a valid chainloop attestation: found=%q", intotoStatement.PredicateType)
}

return uploadAndCraft(ctx, i.input, i.backend, file.Name(), i.logger)
return uploadAndCraft(ctx, i.input, i.backend, artifactPath, i.logger)
}
42 changes: 42 additions & 0 deletions pkg/attestation/crafter/materials/attestation/attestation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Copyright 2025 The Chainloop Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package attestation

import (
"encoding/json"
"fmt"

"github.com/chainloop-dev/chainloop/pkg/attestation"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1"
"google.golang.org/protobuf/encoding/protojson"
)

func ExtractDSSEEnvelope(data []byte) (*dsse.Envelope, error) {
var dsseEnvelope dsse.Envelope
var bundle protobundle.Bundle
if err := protojson.Unmarshal(data, &bundle); err == nil && bundle.GetMediaType() != "" {
// if it has a media type, we can confirm it's a bundle
env := attestation.DSSEEnvelopeFromBundle(&bundle)
dsseEnvelope = *env
} else {
// try to parse it as a DSSE envelope
if err = json.Unmarshal(data, &dsseEnvelope); err != nil {
return nil, fmt.Errorf("failed to parse the provided file as a DSSE envelope: %w", err)
}
}
return &dsseEnvelope, nil
}
85 changes: 60 additions & 25 deletions pkg/attestation/crafter/materials/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package materials_test

import (
"context"
"path"
"testing"

"code.cloudfoundry.org/bytefmt"
Expand Down Expand Up @@ -94,42 +95,76 @@ func TestInvalidAttestation(t *testing.T) {
t.Run("wrong in-toto statement", func(_ *testing.T) {
// Invalid payload
_, err := crafter.Craft(context.TODO(), "./testdata/attestation-invalid-intoto.json")
assert.Contains(err.Error(), "un-marshaling predicate")
assert.Contains(err.Error(), "failed to parse the DSSE payload")
})
}

func TestAttestationCraft(t *testing.T) {
assert := assert.New(t)
schema := &contractAPI.CraftingSchema_Material{
Name: "test",
Type: contractAPI.CraftingSchema_Material_ATTESTATION,
var testCases = []struct {
name string
filePath string
digest string
expectErr bool
}{
{
name: "DSSE envelope",
filePath: "./testdata/attestation-dsse.json",
digest: "sha256:3911ab20e43d801d35459c53168f6cba66d50af99dcc9e12aeb84a95c0d231df",
},
{
name: "Sigstore bundle",
filePath: "./testdata/attestation-bundle.json",
digest: "sha256:fa7165a16cc1efdd24457a12dda613bbbfc903d3a2538a5ce8779b157d39b04c",
},
{
name: "Invalid payload type",
filePath: "./testdata/attestation-dsse-invalidtype.json",
expectErr: true,
},
}

assert := assert.New(t)
l := zerolog.Nop()

// Mock uploader
uploader := mUploader.NewUploader(t)
uploader.On("UploadFile", context.TODO(), mock.Anything).
Return(&casclient.UpDownStatus{
Digest: "deadbeef",
Filename: "attestation.json",
}, nil)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
schema := &contractAPI.CraftingSchema_Material{
Name: "test",
Type: contractAPI.CraftingSchema_Material_ATTESTATION,
}

backend := &casclient.CASBackend{Uploader: uploader}
// Mock uploader
uploader := mUploader.NewUploader(t)
if !tc.expectErr {
uploader.On("UploadFile", context.Background(), mock.Anything).
Return(&casclient.UpDownStatus{
Digest: "deadbeef",
Filename: "attestation.json",
}, nil)
}

crafter, err := materials.NewAttestationCrafter(schema, backend, &l)
require.NoError(t, err)
backend := &casclient.CASBackend{Uploader: uploader}

got, err := crafter.Craft(context.TODO(), "./testdata/attestation.json")
assert.NoError(err)
assert.Equal(contractAPI.CraftingSchema_Material_ATTESTATION.String(), got.MaterialType.String())
assert.True(got.UploadedToCas)
crafter, err := materials.NewAttestationCrafter(schema, backend, &l)
require.NoError(t, err)

// The result includes the digest reference
assert.Equal("test", got.GetArtifact().Id)
assert.Equal("sha256:30f98082cf71a990787755b360443711735de4041f27bf4a49d61bb8e6f29e92", got.GetArtifact().Digest)
got, err := crafter.Craft(context.Background(), tc.filePath)
if tc.expectErr {
assert.Error(err)
return
}
assert.NoError(err)
assert.Equal(contractAPI.CraftingSchema_Material_ATTESTATION.String(), got.MaterialType.String())
assert.True(got.UploadedToCas)

// The result includes the name and digest reference
assert.Equal(path.Base(tc.filePath), got.GetArtifact().GetName())
assert.Equal(tc.digest, got.GetArtifact().GetDigest())

uploader.AssertExpectations(t)
})
}

uploader.AssertExpectations(t)
}

func TestAttestationCraftInline(t *testing.T) {
Expand All @@ -146,7 +181,7 @@ func TestAttestationCraftInline(t *testing.T) {
crafter, err := materials.NewAttestationCrafter(schema, backend, &l)
require.NoError(t, err)

got, err := crafter.Craft(context.TODO(), "./testdata/attestation.json")
got, err := crafter.Craft(context.TODO(), "./testdata/attestation-dsse.json")
assert.NoError(err)

assert.NotNil(got)
Expand All @@ -160,7 +195,7 @@ func TestAttestationCraftInline(t *testing.T) {
crafter, err := materials.NewAttestationCrafter(schema, backend, &l)
require.NoError(t, err)

_, err = crafter.Craft(context.TODO(), "./testdata/attestation.json")
_, err = crafter.Craft(context.TODO(), "./testdata/attestation-dsse.json")
assert.Error(err)
})
}
2 changes: 1 addition & 1 deletion pkg/attestation/crafter/materials/slsaprovenance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestInvalidSLSAProvenance(t *testing.T) {

t.Run("is not a sigstore bundle but a DSSE envelope", func(_ *testing.T) {
// Invalid payload
_, err := crafter.Craft(context.TODO(), "./testdata/attestation.json")
_, err := crafter.Craft(context.TODO(), "./testdata/attestation-dsse.json")
assert.Contains(err.Error(), "failed to unmarshal bundle")
})

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"mediaType":"application/vnd.dev.sigstore.bundle+json;version=0.3", "verificationMaterial":{"certificate":{"rawBytes":"MIIDtzCCAZ+gAwIBAgIUExUKwhEfwQO1JugYpz7hLoY0Nh0wDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCRVMxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAoMCUNoYWlubG9vcDESMBAGA1UECwwJY2hhaW5sb29wMRIwEAYDVQQDDAljaGFpbmxvb3AwHhcNMjUwNDMwMTQwNDMzWhcNMjUwNDMwMTQxNDMzWjAvMS0wKwYDVQQKEyQxOGMzZjc4Mi00OTM2LTQ2MzAtYWI4ZC0yMGI1MTEzNjY2OTkwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT/qneSDx6m5z/jbYcOwZc5sq8Hdl2zhjLXHZn0PAm+I1SAaarmpefoXvNxa6kkR1xomQBhSLdUeX1RWTGjw51po2cwZTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFK8ii3t6Pzv8ZtEz0ZZnJ8djo/14MB8GA1UdIwQYMBaAFKDk5Tdk8eOOMf/+GDw+62HNH6XKMA0GCSqGSIb3DQEBCwUAA4ICAQCH9wCAEemv7UPnXw+EkF1yx/83Q5GghOy0EvTHPxLqUltlbcDXyH34nogTgSZcl5bvWP/sQei1p0k76s6ZdwF2+5NUCHI+B4WcO7fyNMZZ+e1QT9mIc58TW17NmIGBXMBh1cjsEWXwlwpaghCtbRw+A6L8xwsfw4ocV1b8DRk855JrzQJmRZu0x5nnVcvp4CS6vI0W6QPva6t9Hyh9g1+5Pz49kw84vfKXsc428BXQTwEaLMRG89oYY4ERLva1XQYwL9z+U0F59wVRgcVCSyOL7rabQicfLjrer44R2yJ6BpSkHIncctTK1F9y8LVUcUVdWOKYc2vTYHT8bt41cSHnGCMYrrbEy1/IkbdqbuE2V3pEe0h0p6c6YQESAiipHqlJJOogw/WNlkeeFkvZRwc+jDAGRhC3GdbwPQO146A6NVekDj6b+Tw7dWV7Rqc35D6V78FrXxZ5/MrpN53Lkb4wPczln6t7AmM5/M57/z4NWxA3iny3HgEoqI/J4plGJJ+rjYyjF4jC51axoF6Pp2yAgx0/DwN4pgAmsNNH3oIiHGyy6CpBQ6LN9rrlgCE7iANaCdiipPnxLRJ99cQSBXVrvrENyNM+v1quRBWNJCHj2Jvy7LoPtB3z8Ik1/HtLiMPbkkplAX12Pi0IXCEJnJNM+DB5ebxW8qd1oxQ8dnBouA=="}}, "dsseEnvelope":{"payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCAic3ViamVjdCI6W3sibmFtZSI6ImNoYWlubG9vcC53b3JrZmxvdy5teXdmIiwgImRpZ2VzdCI6eyJzaGEyNTYiOiJiODI1ZTRjYzc5ZjcwNDcyZGNlMWQ0MjM1ODkzYTk4N2Q3YzA3Y2ZlNzlmN2RiM2YxYjcwNDVhNjUwNzBmM2Y5In19LCB7Im5hbWUiOiJnaXQuaGVhZCIsICJkaWdlc3QiOnsic2hhMSI6ImJmODY3NWEzODQwNTM4MzU4NGI4YzQ2OWRmODAzYTk0NWQ3NWQzN2YifSwgImFubm90YXRpb25zIjp7ImF1dGhvci5lbWFpbCI6ImppcGFyaXNAY2hhaW5sb29wLmRldiIsICJhdXRob3IubmFtZSI6Ikpvc2UgSS4gUGFyaXMiLCAiZGF0ZSI6IjIwMjUtMDQtMzBUMTM6NDY6NDFaIiwgIm1lc3NhZ2UiOiJleHBvc2Ugc2lnbmluZyBvcHRpb25zIGluIGF0dGVzdGF0aW9uXG5cblNpZ25lZC1vZmYtYnk6IEpvc2UgSS4gUGFyaXMgPGppcGFyaXNAY2hhaW5sb29wLmRldj5cbiIsICJyZW1vdGVzIjpbeyJuYW1lIjoib3JpZ2luIiwgInVybCI6ImdpdEBnaXRodWIuY29tOmppcGFyaXMvY2hhaW5sb29wLmdpdCJ9LCB7Im5hbWUiOiJ1cHN0cmVhbSIsICJ1cmwiOiJnaXRAZ2l0aHViLmNvbTpjaGFpbmxvb3AtZGV2L2NoYWlubG9vcC5naXQifSwgeyJuYW1lIjoibWlndWUiLCAidXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL21pZ21hcnRyaS9jaGFpbmxvb3AvIn0sIHsibmFtZSI6ImphdmkiLCAidXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL2phdmlybG4vY2hhaW5sb29wIn1dLCAic2lnbmF0dXJlIjoiLS0tLS1CRUdJTiBQR1AgU0lHTkFUVVJFLS0tLS1cblxuaVFJekJBQUJDQUFkRmlFRWpINTFITVdrQ05ZMmRoWndvSXR5Q2srbTN0NEZBbWdTS2NnQUNna1FvSXR5Q2srbVxuM3Q3azB3Ly9UelluVVdNSElDVW9OeXhiMDVuaXo0Q04vRlgrSkhPZmFjb0FkaWJIaTNaV1ZIdnNmZ3NEd3FZelxuTmliaGp0ejB5VUpKL0VMaVdudlp6QWJqY0ZEczlrM3hNVndzQXZiNUIxYkdxTjFBMTdXM2p2T2tKVm9OZ2pNYlxuRitkMytDeExVaVdyOXgyNnc3MjFxZHBDUU9TUlBTTEI3TE5NZWVXbyszU0hyM2duY2VKV0JqQTVZS1RIeTRGMlxuRTE3cTVBc2N3azhZdTFoMFBuR2pDcm1WZU0wTmtNalY2a2JIS0hiL2tsL3c2MTlrZ1FNbzkwWjZDb0FDcXAwQ1xuYWJpMUpIbWZMOWJiaVk4MkxJZlZNRk1wZVovaTlYYjJrbUtWdDNnTWRmNWJvK1owYWkzdlJTeEl6N1JmR0s5VFxuUGJjTjE5aVd0NHJvMFZLMWJmQnJPWC9wNndjemF4cGhLcE5Sc0FoWWZUbFFGaEczU3RGWUhtb3Q2UFlqdXdaeFxuN0VhTUFlTkdGSWJ0NEFGb1MzK3hmQUI2L1JnQTFNczJ0cVhrd2ZZc21yTlNHaW90ZHNyejE2cWZrdUJLc1NvRFxueGRIV1lCNXd5OWp5V3FoRkdiOVhhYWhQVTB3czlxd09KcVlJYUtidnI2Z2pJMFIxTTBkV0tja1dVMnB3cGRRVlxucXFvTlo0YkIwNnQ2WHFFbkZFMmtrcnVEMEtwaW9oUit4YU9oM1U2OCtlSkU4L0pObUdxUDQ4Vzh5UU0yUW1NYlxuWm9WdmZUcHk0amY4UmNxR052TUhmQitMaVAySVc0VHNEWFYrUVlYZko2MU15cjBFVHdvOEZaNUdvVzZlZDNXcVxudHpzUnp4RzVjd2c5QlZiSXk2bzMwUlVTRmRYdCtIdFVCQWVFaUtuUHl3RXRlR2tGLytZPVxuPUdrVW5cbi0tLS0tRU5EIFBHUCBTSUdOQVRVUkUtLS0tLVxuIn19XSwgInByZWRpY2F0ZVR5cGUiOiJjaGFpbmxvb3AuZGV2L2F0dGVzdGF0aW9uL3YwLjIiLCAicHJlZGljYXRlIjp7ImJ1aWxkVHlwZSI6ImNoYWlubG9vcC5kZXYvd29ya2Zsb3dydW4vdjAuMSIsICJidWlsZGVyIjp7ImlkIjoiY2hhaW5sb29wLmRldi9jbGkvZGV2QHNoYTI1Njo5MDk1OTBhZjAxZTA0ZDM2ZDg2MWY1Y2Y0ZWI1ZDg4YTE2OWZlOGQ0ZGY5MDU3YmUwYjBhMTY1ODZkYzQyNTQzIn0sICJtYXRlcmlhbHMiOlt7ImFubm90YXRpb25zIjp7ImNoYWlubG9vcC5tYXRlcmlhbC5jYXMiOnRydWUsICJjaGFpbmxvb3AubWF0ZXJpYWwubmFtZSI6Im1hdGVyaWFsLTE3NDYwMjE3ODQxNjkwNTkwMDAiLCAiY2hhaW5sb29wLm1hdGVyaWFsLnR5cGUiOiJBUlRJRkFDVCJ9LCAiZGlnZXN0Ijp7InNoYTI1NiI6ImE4N2FhNTE2OThlMzJkNzcwYzIyMTRmZmVjNzllYjdiZGRlMzFjZGZkN2YyMTM1ZjgxZDNlOTU4ODM0ZGJkYTUifSwgIm5hbWUiOiJidW5kbGUuanNvbiJ9XSwgIm1ldGFkYXRhIjp7ImNvbnRyYWN0TmFtZSI6Im15cHJvamVjdC1teXdmIiwgImNvbnRyYWN0VmVyc2lvbiI6Ijk3IiwgImZpbmlzaGVkQXQiOiIyMDI1LTA0LTMwVDE0OjA0OjMxLjkwNTkwMVoiLCAiaW5pdGlhbGl6ZWRBdCI6IjIwMjUtMDQtMzBUMTQ6MDI6NDcuNzM3MzAyWiIsICJuYW1lIjoibXl3ZiIsICJvcmdhbml6YXRpb24iOiJteS1vcmciLCAicHJvamVjdCI6Im15cHJvamVjdCIsICJwcm9qZWN0VmVyc2lvbiI6InYxLjAuMC1yYy4xMyIsICJwcm9qZWN0VmVyc2lvblByZXJlbGVhc2UiOnRydWUsICJ0ZWFtIjoiIiwgIndvcmtmbG93SUQiOiI5NWYxYjU5Ny0yMGUxLTQ5OGMtYjkzMS1mYzZkNzMzMTg2MGUiLCAid29ya2Zsb3dSdW5JRCI6ImUxY2ExM2NhLTliOGEtNGM2OC1iMTc2LTBmNzZiMjE5YWI1NSJ9LCAicG9saWN5QXR0QmxvY2tlZCI6ZmFsc2UsICJwb2xpY3lCbG9ja0J5cGFzc0VuYWJsZWQiOmZhbHNlLCAicG9saWN5Q2hlY2tCbG9ja2luZ1N0cmF0ZWd5IjoiQURWSVNPUlkiLCAicG9saWN5RXZhbHVhdGlvbnMiOnsiQ0hBSU5MT09QLkFUVEVTVEFUSU9OIjpbeyJhbm5vdGF0aW9ucyI6eyJjYXRlZ29yeSI6InNlY3VyaXR5LCBDVkUifSwgImRlc2NyaXB0aW9uIjoiQ2hlY2tzIHRoYXQgYSBzdXBwb3J0ZWQgU0NBIHNjYW4gbWF0ZXJpYWwgaXMgcHJlc2VudCBpbiB0aGUgYXR0ZXN0YXRpb24iLCAibmFtZSI6InZ1bG5lcmFiaWxpdHktc2Nhbi1wcmVzZW50IiwgInBvbGljeVJlZmVyZW5jZSI6eyJhbm5vdGF0aW9ucyI6eyJuYW1lIjoidnVsbmVyYWJpbGl0eS1zY2FuLXByZXNlbnQiLCAib3JnYW5pemF0aW9uIjoiIn0sICJkaWdlc3QiOnsic2hhMjU2IjoiMTEzOWJlMjVjOTEzYmY0OTg4NmIyOGU1NGJlZTEwMmRlZTJmODk5MjYyZTk2NTIxOGI1MDNjZWIzYWQ3OWE3ZSJ9LCAibmFtZSI6InZ1bG5lcmFiaWxpdHktc2Nhbi1wcmVzZW50IiwgInVyaSI6ImNoYWlubG9vcDovL2xvY2FsaG9zdDo4MDAyL3Z1bG5lcmFiaWxpdHktc2Nhbi1wcmVzZW50In0sICJza2lwcGVkIjpmYWxzZSwgInR5cGUiOiJBVFRFU1RBVElPTiIsICJ2aW9sYXRpb25zIjpbeyJtZXNzYWdlIjoibWlzc2luZyBTQ0Egc2NhbiBtYXRlcmlhbCIsICJzdWJqZWN0IjoidnVsbmVyYWJpbGl0eS1zY2FuLXByZXNlbnQifV19XX0sICJwb2xpY3lIYXNWaW9sYXRpb25zIjp0cnVlLCAicnVubmVyRW52aXJvbm1lbnQiOiJ1bmtub3duIiwgInJ1bm5lclR5cGUiOiJSVU5ORVJfVFlQRV9VTlNQRUNJRklFRCIsICJzaWduaW5nQ0EiOiJmaWxlQ0EifX0=", "payloadType":"application/vnd.in-toto+json", "signatures":[{"sig":"MEYCIQCg+mkg/6LbqytMIlfJVXUCo90CMhEH7Y4RdAMQBh4dBgIhAP9LEi8fVbIDVWS4ImT0o0rwrENMVLqv1f0H8OzOsND/"}]}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"payloadType": "application/vnd.othertype+json",
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiY2hhaW5sb29wLndvcmtmbG93LmNoYWlubG9vcC1jb2RlcWwiLCJkaWdlc3QiOnsic2hhMjU2IjoiYmNmNzlhNDgwMTFiNTEyZTliYjJlZmM5OWU5NGRhOGU0ODBmNWVjNWMwODg2NDNhN2JmZDJlODVhMmZmMTVlMSJ9fSx7Im5hbWUiOiJnaXQuaGVhZCIsImRpZ2VzdCI6eyJzaGExIjoiZWQ3YTY3ZDkwNjBjMjNhYzFmNjFmYWFjMDZjMjFjOGE5YTAzYzM1NyJ9LCJhbm5vdGF0aW9ucyI6eyJhdXRob3IuZW1haWwiOiJqYXZpZXJAY2hhaW5sb29wLmRldiIsImF1dGhvci5uYW1lIjoiSmF2aWVyIFJvZHLDrWd1ZXoiLCJkYXRlIjoiMjAyNC0wNC0yOVQwODo1ODozMVoiLCJtZXNzYWdlIjoiZmVhdChjaSk6IEFkZHMgY2hhaW5sb29wIHRvIGNvZGVxbCBwaXBlbGluZSAoIzcxMSlcblxuU2lnbmVkLW9mZi1ieTogSmF2aWVyIFJvZHJpZ3VleiA8amF2aWVyQGNoYWlubG9vcC5kZXY+IiwicmVtb3RlcyI6W3sibmFtZSI6Im9yaWdpbiIsInVybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9jaGFpbmxvb3AtZGV2L2NoYWlubG9vcCJ9XX19LHsibmFtZSI6ImdvLnNhcmlmIiwiZGlnZXN0Ijp7InNoYTI1NiI6ImQ5YTFlMmNiMTY4NGUxNDY1MjhkZjgzNWQyMjAwN2MyYWI2ZjMzMzgzNzdhY2RlYzlkZTEwYjhkMDdlYzkxNmQifSwiYW5ub3RhdGlvbnMiOnsiY2hhaW5sb29wLm1hdGVyaWFsLmNhcyI6dHJ1ZSwiY2hhaW5sb29wLm1hdGVyaWFsLm5hbWUiOiJzYXJpZi1yZXN1bHRzIiwiY2hhaW5sb29wLm1hdGVyaWFsLnR5cGUiOiJTQVJJRiJ9fV0sInByZWRpY2F0ZVR5cGUiOiJjaGFpbmxvb3AuZGV2L2F0dGVzdGF0aW9uL3YwLjIiLCJwcmVkaWNhdGUiOnsiYnVpbGRUeXBlIjoiY2hhaW5sb29wLmRldi93b3JrZmxvd3J1bi92MC4xIiwiYnVpbGRlciI6eyJpZCI6ImNoYWlubG9vcC5kZXYvY2xpLzAuODMuMEBzaGEyNTY6MGU4ODNhMmI5NGM3OTJiZWU0ZDc3YTI1OGFmM2ExOTIxZDQxNjliNWUwZGI0MTk1NzA5YzhkZjIwZGFjYjEyNiJ9LCJlbnYiOnsiR0lUSFVCX0FDVE9SIjoiamF2aXJsbiIsIkdJVEhVQl9SRUYiOiJyZWZzL2hlYWRzL21haW4iLCJHSVRIVUJfUkVQT1NJVE9SWSI6ImNoYWlubG9vcC1kZXYvY2hhaW5sb29wIiwiR0lUSFVCX1JFUE9TSVRPUllfT1dORVIiOiJjaGFpbmxvb3AtZGV2IiwiR0lUSFVCX1JVTl9JRCI6Ijg4NzU5MzQwNzEiLCJHSVRIVUJfU0hBIjoiZWQ3YTY3ZDkwNjBjMjNhYzFmNjFmYWFjMDZjMjFjOGE5YTAzYzM1NyIsIlJVTk5FUl9OQU1FIjoiR2l0SHViIEFjdGlvbnMgNDgzIiwiUlVOTkVSX09TIjoiTGludXgifSwibWF0ZXJpYWxzIjpbeyJhbm5vdGF0aW9ucyI6eyJjaGFpbmxvb3AubWF0ZXJpYWwuY2FzIjp0cnVlLCJjaGFpbmxvb3AubWF0ZXJpYWwubmFtZSI6InNhcmlmLXJlc3VsdHMiLCJjaGFpbmxvb3AubWF0ZXJpYWwudHlwZSI6IlNBUklGIn0sImRpZ2VzdCI6eyJzaGEyNTYiOiJkOWExZTJjYjE2ODRlMTQ2NTI4ZGY4MzVkMjIwMDdjMmFiNmYzMzM4Mzc3YWNkZWM5ZGUxMGI4ZDA3ZWM5MTZkIn0sIm5hbWUiOiJnby5zYXJpZiJ9XSwibWV0YWRhdGEiOnsiZmluaXNoZWRBdCI6IjIwMjQtMDQtMjlUMDk6MDI6NDQuMzE2ODg5OTIzWiIsImluaXRpYWxpemVkQXQiOiIyMDI0LTA0LTI5VDA4OjU4OjUzLjc0NjgxNzYzNFoiLCJuYW1lIjoiY2hhaW5sb29wLWNvZGVxbCIsIm9yZ2FuaXphdGlvbiI6InJlYWQtb25seS1kZW1vIiwicHJvamVjdCI6ImNoYWlubG9vcCIsInRlYW0iOiJjb3JlIiwid29ya2Zsb3dJRCI6IjIyMzg5N2U1LTE0YmItNGQyYy1hZjA5LWY1NTM4ODMwYzdkYiIsIndvcmtmbG93UnVuSUQiOiJlMjRhNTMzYy0wZTYwLTQ4NGMtOTI1MC05NzZhZjI1NGE1MDEifSwicnVubmVyVHlwZSI6IkdJVEhVQl9BQ1RJT04iLCJydW5uZXJVUkwiOiJodHRwczovL2dpdGh1Yi5jb20vY2hhaW5sb29wLWRldi9jaGFpbmxvb3AvYWN0aW9ucy9ydW5zLzg4NzU5MzQwNzEifX0=",
"signatures": [
{
"keyid": "",
"sig": "MEQCIHn+fRwh804+Hhd1CeFSrIvg6+QWagyXjrqb6LZxnufqAiAml2fu5UNufJJTnSRWwS6+P3Nu/4LoqF8uxElGT+WGnA=="
}
]
}
Loading
Loading