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
29 changes: 5 additions & 24 deletions app/cli/pkg/action/attestation_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ func (action *AttestationPush) Run(ctx context.Context, attestationID string, ru

workflow := crafter.CraftingState.Attestation.GetWorkflow()

attestationResult.Digest, err = pushToControlPlane(ctx, action.CPConnection, envelope, bundle, workflow.GetWorkflowRunId(), workflow.GetVersion().GetMarkAsReleased())
attestationResult.Digest, err = pushToControlPlane(ctx, action.CPConnection, bundle, workflow.GetWorkflowRunId(), workflow.GetVersion().GetMarkAsReleased())
if err != nil {
return nil, fmt.Errorf("pushing to control plane: %w", err)
}
Expand Down Expand Up @@ -303,32 +303,17 @@ func (action *AttestationPush) saveBundle(bundle *protobundle.Bundle) error {
return nil
}

func pushToControlPlane(ctx context.Context, conn *grpc.ClientConn, envelope *dsse.Envelope, bundle *protobundle.Bundle, workflowRunID string, markVersionAsReleased bool) (string, error) {
encodedBundle, err := encodeBundle(bundle)
if err != nil {
return "", fmt.Errorf("encoding attestation: %w", err)
}

client := pb.NewAttestationServiceClient(conn)

// if endpoint doesn't accept the bundle, we still send the plain attestation for backwards compatibility
encodedAttestation, err := encodeEnvelope(envelope)
if err != nil {
return "", fmt.Errorf("encoding attestation: %w", err)
}

func pushToControlPlane(ctx context.Context, conn *grpc.ClientConn, bundle *protobundle.Bundle, workflowRunID string, markVersionAsReleased bool) (string, error) {
// remove additional base64 encoding in signature. See https://github.com/chainloop-dev/chainloop/issues/1832
attestation.FixSignatureInBundle(bundle)
encodedFixedBundle, err := encodeBundle(bundle)
encodedBundle, err := encodeBundle(bundle)
if err != nil {
return "", fmt.Errorf("encoding attestation: %w", err)
}

// Store bundle next versions will perform this in a single call)
client := pb.NewAttestationServiceClient(conn)
resp, err := client.Store(ctx, &pb.AttestationServiceStoreRequest{
Attestation: encodedAttestation,
Bundle: encodedBundle,
AttestationBundle: encodedFixedBundle,
AttestationBundle: encodedBundle,
WorkflowRunId: workflowRunID,
MarkVersionAsReleased: &markVersionAsReleased,
})
Expand All @@ -339,10 +324,6 @@ func pushToControlPlane(ctx context.Context, conn *grpc.ClientConn, envelope *ds
return resp.Result.Digest, nil
}

func encodeEnvelope(e *dsse.Envelope) ([]byte, error) {
return json.Marshal(e)
}

func encodeBundle(b *protobundle.Bundle) ([]byte, error) {
return protojson.Marshal(b)
}
Expand Down
34 changes: 4 additions & 30 deletions app/controlplane/api/controlplane/v1/workflow_run.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 4 additions & 5 deletions app/controlplane/api/controlplane/v1/workflow_run.proto
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2024-2025 The Chainloop Authors.
// Copyright 2024-2026 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.
Expand Down Expand Up @@ -157,16 +157,15 @@ message AttestationServiceInitResponse {
}

message AttestationServiceStoreRequest {
// encoded DSEE envelope
bytes attestation = 1 [deprecated = true];
// deprecated because of https://github.com/chainloop-dev/chainloop/issues/1832
bytes bundle = 4 [deprecated = true];
// encoded Sigstore attestation bundle
bytes attestation_bundle = 5;

string workflow_run_id = 2 [(buf.validate.field).string = {min_len: 1}];
// mark the associated version as released
optional bool mark_version_as_released = 3;

reserved 1, 4;
reserved "attestation", "bundle";
}

message AttestationServiceStoreResponse {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 7 additions & 17 deletions app/controlplane/internal/service/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,7 @@ func (s *AttestationService) Store(ctx context.Context, req *cpAPI.AttestationSe

bundle := req.GetAttestationBundle()
if bundle == nil {
bundle = req.GetBundle()
}

if req.GetAttestation() == nil && bundle == nil {
return nil, errors.BadRequest("input required", "DSSE envelope or attestation bundle is required")
return nil, errors.BadRequest("input required", "attestation bundle is required")
}

// This will make sure the provided workflowRunID belongs to the org encoded in the robot account
Expand All @@ -274,7 +270,7 @@ func (s *AttestationService) Store(ctx context.Context, req *cpAPI.AttestationSe
return nil, errors.NotFound("not found", "workflow run has no CAS backend")
}

digest, err := s.storeAttestation(ctx, req.GetAttestation(), bundle, robotAccount, wf, wRun, req.MarkVersionAsReleased)
digest, err := s.storeAttestation(ctx, bundle, robotAccount, wf, wRun, req.MarkVersionAsReleased)
if err != nil {
return nil, handleUseCaseErr(err, s.log)
}
Expand All @@ -284,19 +280,19 @@ func (s *AttestationService) Store(ctx context.Context, req *cpAPI.AttestationSe
}, nil
}

// Stores and process a DSSE Envelope with a Chainloop attestation
func (s *AttestationService) storeAttestation(ctx context.Context, envelope []byte, bundle []byte, robotAccount *usercontext.RobotAccount, wf *biz.Workflow, wfRun *biz.WorkflowRun, markAsReleased *bool) (*v1.Hash, error) {
// storeAttestation stores and processes a Sigstore attestation bundle.
func (s *AttestationService) storeAttestation(ctx context.Context, bundle []byte, robotAccount *usercontext.RobotAccount, wf *biz.Workflow, wfRun *biz.WorkflowRun, markAsReleased *bool) (*v1.Hash, error) {
workflowRunID := wfRun.ID.String()
casBackend := wfRun.CASBackends[0]

// extract structured envelope for integrations
dsseEnv, err := attestation.DSSEEnvelopeFromRaw(bundle, envelope)
dsseEnv, err := attestation.DSSEEnvelopeFromBundleBytes(bundle)
if err != nil {
return nil, handleUseCaseErr(err, s.log)
}

// Store the attestation
digest, err := s.wrUseCase.SaveAttestation(ctx, workflowRunID, envelope, bundle)
digest, err := s.wrUseCase.SaveAttestation(ctx, workflowRunID, bundle)
if err != nil {
return nil, handleUseCaseErr(err, s.log)
}
Expand All @@ -315,15 +311,9 @@ func (s *AttestationService) storeAttestation(ctx context.Context, envelope []by
b.MaxElapsedTime = 1 * time.Minute
err := backoff.Retry(
func() error {
rawContent := bundle
if rawContent == nil {
rawContent = envelope
}

// reset context
ctx := context.Background()
var err error
if err = s.attestationUseCase.UploadAttestationToCAS(ctx, rawContent, casBackend, workflowRunID, *digest); err != nil {
if err := s.attestationUseCase.UploadAttestationToCAS(ctx, bundle, casBackend, workflowRunID, *digest); err != nil {
return err
}

Expand Down
Loading
Loading