Skip to content

Commit bec4b2a

Browse files
authored
refactor(cli): modularize current state management code (#493)
Signed-off-by: Miguel Martinez Trivino <[email protected]>
1 parent 42d3262 commit bec4b2a

File tree

17 files changed

+530
-153
lines changed

17 files changed

+530
-153
lines changed

app/cli/cmd/attestation_add.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package cmd
1717

1818
import (
1919
"errors"
20+
"fmt"
2021

2122
"github.com/spf13/cobra"
2223
"github.com/spf13/viper"
@@ -37,21 +38,24 @@ func newAttestationAddCmd() *cobra.Command {
3738
useWorkflowRobotAccount: "true",
3839
},
3940
RunE: func(cmd *cobra.Command, args []string) error {
40-
a := action.NewAttestationAdd(
41+
a, err := action.NewAttestationAdd(
4142
&action.AttestationAddOpts{
4243
ActionsOpts: actionOpts,
4344
CASURI: viper.GetString(confOptions.CASAPI.viperKey),
4445
ConnectionInsecure: flagInsecure,
4546
},
4647
)
48+
if err != nil {
49+
return fmt.Errorf("failed to load action: %w", err)
50+
}
4751

4852
// Extract annotations
4953
annotations, err := extractAnnotations(annotationsFlag)
5054
if err != nil {
5155
return err
5256
}
5357

54-
if err := a.Run(name, value, annotations); err != nil {
58+
if err := a.Run("", name, value, annotations); err != nil {
5559
if errors.Is(err, action.ErrAttestationNotInitialized) {
5660
return err
5761
}

app/cli/cmd/attestation_init.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626

2727
func newAttestationInitCmd() *cobra.Command {
2828
var (
29-
replaceRun bool
3029
contractRevision int
3130
attestationDryRun bool
3231
)
@@ -38,16 +37,18 @@ func newAttestationInitCmd() *cobra.Command {
3837
useWorkflowRobotAccount: "true",
3938
},
4039
RunE: func(cmd *cobra.Command, args []string) error {
41-
a := action.NewAttestationInit(
40+
a, err := action.NewAttestationInit(
4241
&action.AttestationInitOpts{
4342
ActionsOpts: actionOpts,
44-
Override: replaceRun,
4543
DryRun: attestationDryRun,
4644
},
4745
)
46+
if err != nil {
47+
return fmt.Errorf("failed to initialize attestation: %w", err)
48+
}
4849

4950
// Initialize it
50-
err := a.Run(contractRevision)
51+
err = a.Run(contractRevision)
5152
if err != nil {
5253
if errors.Is(err, action.ErrAttestationAlreadyExist) {
5354
return err
@@ -61,7 +62,12 @@ func newAttestationInitCmd() *cobra.Command {
6162
logger.Info().Msg("Attestation initialized! now you can check its status or add materials to it")
6263

6364
// Show the status information
64-
res, err := action.NewAttestationStatus(&action.AttestationStatusOpts{ActionsOpts: actionOpts}).Run()
65+
statusAction, err := action.NewAttestationStatus(&action.AttestationStatusOpts{ActionsOpts: actionOpts})
66+
if err != nil {
67+
return newGracefulError(err)
68+
}
69+
70+
res, err := statusAction.Run("")
6571
if err != nil {
6672
return newGracefulError(err)
6773
}
@@ -70,7 +76,6 @@ func newAttestationInitCmd() *cobra.Command {
7076
},
7177
}
7278

73-
cmd.Flags().BoolVarP(&replaceRun, "replace", "f", false, "replace any existing run")
7479
cmd.Flags().BoolVar(&attestationDryRun, "dry-run", false, "do not record attestation in the control plane, useful for development")
7580
cmd.Flags().IntVar(&contractRevision, "contract-revision", 0, "revision of the contract to retrieve, \"latest\" by default")
7681

app/cli/cmd/attestation_push.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,19 @@ func newAttestationPushCmd() *cobra.Command {
6161
if err != nil {
6262
return fmt.Errorf("getting executable information: %w", err)
6363
}
64-
a := action.NewAttestationPush(&action.AttestationPushOpts{
64+
a, err := action.NewAttestationPush(&action.AttestationPushOpts{
6565
ActionsOpts: actionOpts, KeyPath: pkPath, CLIVersion: info.Version, CLIDigest: info.Digest,
6666
})
67+
if err != nil {
68+
return fmt.Errorf("failed to load action: %w", err)
69+
}
6770

6871
annotations, err := extractAnnotations(annotationsFlag)
6972
if err != nil {
7073
return err
7174
}
7275

73-
res, err := a.Run(annotations)
76+
res, err := a.Run("", annotations)
7477
if err != nil {
7578
if errors.Is(err, action.ErrAttestationNotInitialized) {
7679
return err

app/cli/cmd/attestation_reset.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ func newAttestationResetCmd() *cobra.Command {
4141
return nil
4242
},
4343
RunE: func(cmd *cobra.Command, args []string) error {
44-
a := action.NewAttestationReset(actionOpts)
44+
a, err := action.NewAttestationReset(actionOpts)
45+
if err != nil {
46+
return fmt.Errorf("failed to load action: %w", err)
47+
}
4548

46-
if err := a.Run(trigger, reason); err != nil {
49+
if err := a.Run("", trigger, reason); err != nil {
4750
return newGracefulError(err)
4851
}
4952

app/cli/cmd/attestation_status.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ func newAttestationStatusCmd() *cobra.Command {
3434
Use: "status",
3535
Short: "check the status of the current attestation process",
3636
RunE: func(cmd *cobra.Command, args []string) error {
37-
a := action.NewAttestationStatus(
37+
a, err := action.NewAttestationStatus(
3838
&action.AttestationStatusOpts{
3939
ActionsOpts: actionOpts,
4040
},
4141
)
42+
if err != nil {
43+
return fmt.Errorf("failed to load action: %w", err)
44+
}
4245

43-
res, err := a.Run()
46+
res, err := a.Run("")
4447
if err != nil {
4548
return err
4649
}

app/cli/internal/action/action.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@
1616
package action
1717

1818
import (
19+
"fmt"
20+
"os"
21+
"path/filepath"
1922
"time"
2023

24+
"github.com/chainloop-dev/chainloop/internal/attestation/crafter"
25+
"github.com/chainloop-dev/chainloop/internal/attestation/crafter/statemanager/filesystem"
2126
"github.com/rs/zerolog"
2227
"google.golang.org/grpc"
2328
)
@@ -30,3 +35,15 @@ type ActionsOpts struct {
3035
func toTimePtr(t time.Time) *time.Time {
3136
return &t
3237
}
38+
39+
// load a crafter with local state manager
40+
// TODO: We'll enable the ability to load a crafter that relies on a remote state manager
41+
func newCrafter(_ *grpc.ClientConn, logger *zerolog.Logger) (*crafter.Crafter, error) {
42+
statePath := filepath.Join(os.TempDir(), "chainloop-attestation.tmp.json")
43+
localStateManager, err := filesystem.New(statePath)
44+
if err != nil {
45+
return nil, fmt.Errorf("failed to create local state manager: %w", err)
46+
}
47+
48+
return crafter.NewCrafter(localStateManager, crafter.WithLogger(logger))
49+
}

app/cli/internal/action/attestation_add.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,28 @@ type AttestationAdd struct {
4141
connectionInsecure bool
4242
}
4343

44-
func NewAttestationAdd(cfg *AttestationAddOpts) *AttestationAdd {
44+
func NewAttestationAdd(cfg *AttestationAddOpts) (*AttestationAdd, error) {
45+
c, err := newCrafter(cfg.CPConnection, &cfg.Logger)
46+
if err != nil {
47+
return nil, fmt.Errorf("failed to load crafter: %w", err)
48+
}
49+
4550
return &AttestationAdd{
46-
ActionsOpts: cfg.ActionsOpts,
47-
c: crafter.NewCrafter(
48-
crafter.WithLogger(&cfg.Logger),
49-
),
51+
ActionsOpts: cfg.ActionsOpts,
52+
c: c,
5053
casURI: cfg.CASURI,
5154
connectionInsecure: cfg.ConnectionInsecure,
52-
}
55+
}, nil
5356
}
5457

5558
var ErrAttestationNotInitialized = errors.New("attestation not yet initialized")
5659

57-
func (action *AttestationAdd) Run(k, v string, annotations map[string]string) error {
58-
if initialized := action.c.AlreadyInitialized(); !initialized {
60+
func (action *AttestationAdd) Run(attestationID, materialName, materialValue string, annotations map[string]string) error {
61+
if initialized := action.c.AlreadyInitialized(attestationID); !initialized {
5962
return ErrAttestationNotInitialized
6063
}
6164

62-
if err := action.c.LoadCraftingState(); err != nil {
65+
if err := action.c.LoadCraftingState(attestationID); err != nil {
6366
action.Logger.Err(err).Msg("loading existing attestation")
6467
return err
6568
}
@@ -98,7 +101,7 @@ func (action *AttestationAdd) Run(k, v string, annotations map[string]string) er
98101
casBackend.Uploader = casclient.New(artifactCASConn, casclient.WithLogger(action.Logger))
99102
}
100103

101-
if err := action.c.AddMaterial(k, v, casBackend, annotations); err != nil {
104+
if err := action.c.AddMaterial(attestationID, materialName, materialValue, casBackend, annotations); err != nil {
102105
return fmt.Errorf("adding material: %w", err)
103106
}
104107

app/cli/internal/action/attestation_init.go

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ import (
2828

2929
type AttestationInitOpts struct {
3030
*ActionsOpts
31-
Override, DryRun bool
31+
DryRun bool
3232
}
3333

3434
type AttestationInit struct {
3535
*ActionsOpts
36-
override, dryRun bool
37-
c *crafter.Crafter
36+
dryRun bool
37+
c *crafter.Crafter
3838
}
3939

4040
// ErrAttestationAlreadyExist means that there is an attestation in progress
@@ -48,20 +48,20 @@ func (e ErrRunnerContextNotFound) Error() string {
4848
return fmt.Sprintf("The contract expects the attestation to be crafted in a runner of type %q but couldn't be detected", e.RunnerType)
4949
}
5050

51-
func NewAttestationInit(cfg *AttestationInitOpts) *AttestationInit {
51+
func NewAttestationInit(cfg *AttestationInitOpts) (*AttestationInit, error) {
52+
c, err := newCrafter(cfg.CPConnection, &cfg.Logger)
53+
if err != nil {
54+
return nil, fmt.Errorf("failed to load crafter: %w", err)
55+
}
56+
5257
return &AttestationInit{
5358
ActionsOpts: cfg.ActionsOpts,
54-
override: cfg.Override,
55-
c: crafter.NewCrafter(crafter.WithLogger(&cfg.Logger)),
59+
c: c,
5660
dryRun: cfg.DryRun,
57-
}
61+
}, nil
5862
}
5963

6064
func (action *AttestationInit) Run(contractRevision int) error {
61-
if initialized := action.c.AlreadyInitialized(); initialized && !action.override {
62-
return ErrAttestationAlreadyExist
63-
}
64-
6565
action.Logger.Debug().Msg("Retrieving attestation definition")
6666
client := pb.NewAttestationServiceClient(action.ActionsOpts.CPConnection)
6767
// get information of the workflow
@@ -92,6 +92,9 @@ func (action *AttestationInit) Run(contractRevision int) error {
9292
return ErrRunnerContextNotFound{runnerContext.String()}
9393
}
9494

95+
// Identifier of this attestation instance
96+
var attestationID string
97+
9598
// Init in the control plane if needed including the runner context
9699
if !action.dryRun {
97100
runResp, err := client.Init(
@@ -108,27 +111,29 @@ func (action *AttestationInit) Run(contractRevision int) error {
108111
workflowRun := runResp.GetResult().GetWorkflowRun()
109112
workflowMeta.WorkflowRunId = workflowRun.GetId()
110113
action.Logger.Debug().Str("workflow-run-id", workflowRun.GetId()).Msg("attestation initialized in the control plane")
114+
attestationID = workflowRun.GetId()
111115
}
112116

113117
// Initialize the local attestation crafter
114118
// NOTE: important to run this initialization here since workflowMeta is populated
115119
// with the workflowRunId that comes from the control plane
116120
initOpts := &crafter.InitOpts{
117121
WfInfo: workflowMeta, SchemaV1: contractVersion.GetV1(),
118-
DryRun: action.dryRun,
122+
DryRun: action.dryRun,
123+
AttestationID: attestationID,
119124
}
120125

121126
if err := action.c.Init(initOpts); err != nil {
122127
return err
123128
}
124129

125130
// Load the env variables both the system populated and the user predefined ones
126-
if err := action.c.ResolveEnvVars(); err != nil {
131+
if err := action.c.ResolveEnvVars(attestationID); err != nil {
127132
if action.dryRun {
128133
return nil
129134
}
130135

131-
_ = action.c.Reset()
136+
_ = action.c.Reset(attestationID)
132137
return err
133138
}
134139

app/cli/internal/action/attestation_push.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,27 @@ type AttestationPush struct {
4545
keyPath, cliVersion, cliDigest string
4646
}
4747

48-
func NewAttestationPush(cfg *AttestationPushOpts) *AttestationPush {
48+
func NewAttestationPush(cfg *AttestationPushOpts) (*AttestationPush, error) {
49+
c, err := newCrafter(cfg.CPConnection, &cfg.Logger)
50+
if err != nil {
51+
return nil, fmt.Errorf("failed to load crafter: %w", err)
52+
}
53+
4954
return &AttestationPush{
5055
ActionsOpts: cfg.ActionsOpts,
51-
c: crafter.NewCrafter(crafter.WithLogger(&cfg.Logger)),
56+
c: c,
5257
keyPath: cfg.KeyPath,
5358
cliVersion: cfg.CLIVersion,
5459
cliDigest: cfg.CLIDigest,
55-
}
60+
}, nil
5661
}
5762

58-
func (action *AttestationPush) Run(runtimeAnnotations map[string]string) (*AttestationResult, error) {
59-
if initialized := action.c.AlreadyInitialized(); !initialized {
63+
func (action *AttestationPush) Run(attestationID string, runtimeAnnotations map[string]string) (*AttestationResult, error) {
64+
if initialized := action.c.AlreadyInitialized(attestationID); !initialized {
6065
return nil, ErrAttestationNotInitialized
6166
}
6267

63-
if err := action.c.LoadCraftingState(); err != nil {
68+
if err := action.c.LoadCraftingState(attestationID); err != nil {
6469
action.Logger.Err(err).Msg("loading existing attestation")
6570
return nil, err
6671
}
@@ -128,7 +133,7 @@ func (action *AttestationPush) Run(runtimeAnnotations map[string]string) (*Attes
128133
if action.c.CraftingState.DryRun {
129134
action.Logger.Info().Msg("dry-run completed, push skipped")
130135
// We are done, remove the existing att state
131-
if err := action.c.Reset(); err != nil {
136+
if err := action.c.Reset(attestationID); err != nil {
132137
return nil, err
133138
}
134139

@@ -143,7 +148,7 @@ func (action *AttestationPush) Run(runtimeAnnotations map[string]string) (*Attes
143148
action.Logger.Info().Msg("push completed")
144149

145150
// We are done, remove the existing att state
146-
if err := action.c.Reset(); err != nil {
151+
if err := action.c.Reset(attestationID); err != nil {
147152
return nil, err
148153
}
149154

0 commit comments

Comments
 (0)