Skip to content

Commit a5af520

Browse files
authored
feat(controlplane): verify that dependent attestations exist (#732)
Signed-off-by: Miguel Martinez Trivino <[email protected]>
1 parent 6e1bb33 commit a5af520

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

app/controlplane/internal/biz/workflowrun.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ import (
2424

2525
"github.com/chainloop-dev/chainloop/app/controlplane/internal/pagination"
2626
"github.com/chainloop-dev/chainloop/internal/attestation"
27+
"github.com/chainloop-dev/chainloop/internal/attestation/renderer/chainloop"
2728
"github.com/secure-systems-lab/go-securesystemslib/dsse"
2829

30+
schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
2931
"github.com/go-kratos/kratos/v2/log"
3032
v1 "github.com/google/go-containerregistry/pkg/v1"
3133
"github.com/google/uuid"
@@ -248,6 +250,26 @@ func (uc *WorkflowRunUseCase) SaveAttestation(ctx context.Context, id string, en
248250
return "", NewErrInvalidUUID(err)
249251
}
250252

253+
// extract statement to run some validations in the content
254+
predicate, err := chainloop.ExtractPredicate(envelope)
255+
if err != nil {
256+
return "", fmt.Errorf("extracting predicate: %w", err)
257+
}
258+
259+
// Run some validations on the predicate
260+
// Attestations can include dependent attestations and we want to make sure they exist in the system
261+
// Find any material of kind attestation and make sure they exist already
262+
for _, m := range predicate.GetMaterials() {
263+
if m.Type == schemaapi.CraftingSchema_Material_ATTESTATION.String() {
264+
run, err := uc.wfRunRepo.FindByAttestationDigest(ctx, m.Hash.String())
265+
if err != nil {
266+
return "", fmt.Errorf("finding attestation: %w", err)
267+
} else if run == nil {
268+
return "", NewErrValidation(fmt.Errorf("dependent attestation not found: %s", m.Hash))
269+
}
270+
}
271+
}
272+
251273
// Calculate the digest
252274
_, digest, err := attestation.JSONEnvelopeWithDigest(envelope)
253275
if err != nil {

app/controlplane/internal/biz/workflowrun_integration_test.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ package biz_test
1717

1818
import (
1919
"context"
20+
"encoding/json"
21+
"os"
2022
"testing"
2123

2224
schemav1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
@@ -31,6 +33,7 @@ import (
3133
"github.com/secure-systems-lab/go-securesystemslib/dsse"
3234
"github.com/stretchr/testify/assert"
3335
"github.com/stretchr/testify/mock"
36+
"github.com/stretchr/testify/require"
3437
"github.com/stretchr/testify/suite"
3538
)
3639

@@ -106,7 +109,7 @@ func (s *workflowRunIntegrationTestSuite) TestSaveAttestation() {
106109
assert := assert.New(s.T())
107110
ctx := context.Background()
108111

109-
validEnvelope := &dsse.Envelope{}
112+
validEnvelope := testEnvelope(s.T(), "testdata/attestations/full.json")
110113

111114
s.T().Run("non existing workflowRun", func(t *testing.T) {
112115
_, err := s.WorkflowRun.SaveAttestation(ctx, uuid.NewString(), validEnvelope)
@@ -122,7 +125,7 @@ func (s *workflowRunIntegrationTestSuite) TestSaveAttestation() {
122125

123126
d, err := s.WorkflowRun.SaveAttestation(ctx, run.ID.String(), validEnvelope)
124127
assert.NoError(err)
125-
wantDigest := "sha256:f845058d865c3d4d491c9019f6afe9c543ad2cd11b31620cc512e341fb03d3d8"
128+
wantDigest := "sha256:1a077137aef7ca208b80c339769d0d7eecacc2850368e56e834cda1750ce413a"
126129
assert.Equal(wantDigest, d)
127130

128131
// Retrieve attestation ref from storage and compare
@@ -309,6 +312,14 @@ type workflowRunTestData struct {
309312
digestAtt1, digestAttOrg2, digestAttPublic string
310313
}
311314

315+
func testEnvelope(t *testing.T, path string) *dsse.Envelope {
316+
attJSON, err := os.ReadFile(path)
317+
require.NoError(t, err)
318+
var envelope *dsse.Envelope
319+
require.NoError(t, json.Unmarshal(attJSON, &envelope))
320+
return envelope
321+
}
322+
312323
// extract this setup to a helper function so it can be used from other test suites
313324
func setupWorkflowRunTestData(t *testing.T, suite *testhelpers.TestingUseCases, s *workflowRunTestData) {
314325
var err error
@@ -346,7 +357,7 @@ func setupWorkflowRunTestData(t *testing.T, suite *testhelpers.TestingUseCases,
346357
WorkflowID: s.workflowOrg1.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevision: s.contractVersion, CASBackendID: s.casBackend.ID,
347358
})
348359
assert.NoError(err)
349-
s.digestAtt1, err = suite.WorkflowRun.SaveAttestation(ctx, s.runOrg1.ID.String(), &dsse.Envelope{PayloadType: "test"})
360+
s.digestAtt1, err = suite.WorkflowRun.SaveAttestation(ctx, s.runOrg1.ID.String(), testEnvelope(t, "testdata/attestations/full.json"))
350361

351362
assert.NoError(err)
352363

@@ -355,15 +366,15 @@ func setupWorkflowRunTestData(t *testing.T, suite *testhelpers.TestingUseCases,
355366
WorkflowID: s.workflowOrg2.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevision: s.contractVersion, CASBackendID: s.casBackend.ID,
356367
})
357368
assert.NoError(err)
358-
s.digestAttOrg2, err = suite.WorkflowRun.SaveAttestation(ctx, s.runOrg2.ID.String(), &dsse.Envelope{PayloadType: "test2"})
369+
s.digestAttOrg2, err = suite.WorkflowRun.SaveAttestation(ctx, s.runOrg2.ID.String(), testEnvelope(t, "testdata/attestations/empty.json"))
359370
assert.NoError(err)
360371

361372
s.runOrg2Public, err = suite.WorkflowRun.Create(ctx,
362373
&biz.WorkflowRunCreateOpts{
363374
WorkflowID: s.workflowPublicOrg2.ID.String(), RobotaccountID: s.robotAccount.ID.String(), ContractRevision: s.contractVersion, CASBackendID: s.casBackend.ID,
364375
})
365376
assert.NoError(err)
366-
s.digestAttPublic, err = suite.WorkflowRun.SaveAttestation(ctx, s.runOrg2Public.ID.String(), &dsse.Envelope{PayloadType: "test3"})
377+
s.digestAttPublic, err = suite.WorkflowRun.SaveAttestation(ctx, s.runOrg2Public.ID.String(), testEnvelope(t, "testdata/attestations/with-string.json"))
367378
assert.NoError(err)
368379
}
369380

0 commit comments

Comments
 (0)