@@ -18,15 +18,12 @@ package biz
18
18
import (
19
19
"context"
20
20
"encoding/json"
21
- "errors"
22
21
"fmt"
23
22
"io"
24
23
"time"
25
24
26
25
backend "github.com/chainloop-dev/chainloop/internal/blobmanager"
27
- "github.com/chainloop-dev/chainloop/internal/blobmanager/oci"
28
26
"github.com/chainloop-dev/chainloop/internal/credentials"
29
- "github.com/chainloop-dev/chainloop/internal/ociauth"
30
27
"github.com/chainloop-dev/chainloop/internal/servicelogger"
31
28
"github.com/go-kratos/kratos/v2/log"
32
29
"github.com/google/uuid"
@@ -47,7 +44,7 @@ type CASBackend struct {
47
44
ID uuid.UUID
48
45
Location , Description , SecretName string
49
46
CreatedAt , ValidatedAt * time.Time
50
- OrganizationID string
47
+ OrganizationID uuid. UUID
51
48
ValidationStatus CASBackendValidationStatus
52
49
// OCI, S3, ...
53
50
Provider CASBackendProvider
@@ -56,14 +53,14 @@ type CASBackend struct {
56
53
}
57
54
58
55
type CASBackendOpts struct {
56
+ OrgID uuid.UUID
59
57
Location , SecretName , Description string
60
58
Provider CASBackendProvider
61
59
Default bool
62
60
}
63
61
64
62
type CASBackendCreateOpts struct {
65
63
* CASBackendOpts
66
- OrgID uuid.UUID
67
64
}
68
65
69
66
type CASBackendUpdateOpts struct {
@@ -85,23 +82,23 @@ type CASBackendRepo interface {
85
82
86
83
type CASBackendReader interface {
87
84
FindDefaultBackend (ctx context.Context , orgID string ) (* CASBackend , error )
88
- FindByID (ctx context.Context , ID string ) (* CASBackend , error )
85
+ FindByIDInOrg (ctx context.Context , OrgID , ID string ) (* CASBackend , error )
89
86
PerformValidation (ctx context.Context , ID string ) error
90
87
}
91
88
92
89
type CASBackendUseCase struct {
93
- repo CASBackendRepo
94
- logger * log.Helper
95
- credsRW credentials.ReaderWriter
96
- ociBackendProvider backend.Provider
90
+ repo CASBackendRepo
91
+ logger * log.Helper
92
+ credsRW credentials.ReaderWriter
93
+ providers backend.Providers
97
94
}
98
95
99
- func NewCASBackendUseCase (repo CASBackendRepo , credsRW credentials.ReaderWriter , p backend.Provider , l log.Logger ) * CASBackendUseCase {
96
+ func NewCASBackendUseCase (repo CASBackendRepo , credsRW credentials.ReaderWriter , providers backend.Providers , l log.Logger ) * CASBackendUseCase {
100
97
if l == nil {
101
98
l = log .NewStdLogger (io .Discard )
102
99
}
103
100
104
- return & CASBackendUseCase {repo , servicelogger .ScopedHelper (l , "biz/CASBackend" ), credsRW , p }
101
+ return & CASBackendUseCase {repo , servicelogger .ScopedHelper (l , "biz/CASBackend" ), credsRW , providers }
105
102
}
106
103
107
104
func (uc * CASBackendUseCase ) List (ctx context.Context , orgID string ) ([]* CASBackend , error ) {
@@ -119,16 +116,7 @@ func (uc *CASBackendUseCase) FindDefaultBackend(ctx context.Context, orgID strin
119
116
return nil , NewErrInvalidUUID (err )
120
117
}
121
118
122
- return uc .repo .FindDefaultBackend (ctx , orgUUID )
123
- }
124
-
125
- func (uc * CASBackendUseCase ) FindByID (ctx context.Context , id string ) (* CASBackend , error ) {
126
- backendUUID , err := uuid .Parse (id )
127
- if err != nil {
128
- return nil , NewErrInvalidUUID (err )
129
- }
130
-
131
- backend , err := uc .repo .FindByID (ctx , backendUUID )
119
+ backend , err := uc .repo .FindDefaultBackend (ctx , orgUUID )
132
120
if err != nil {
133
121
return nil , err
134
122
} else if backend == nil {
@@ -138,75 +126,49 @@ func (uc *CASBackendUseCase) FindByID(ctx context.Context, id string) (*CASBacke
138
126
return backend , nil
139
127
}
140
128
141
- func validateAndExtractCredentials (provider CASBackendProvider , location string , credsJSON []byte ) (any , error ) {
142
- // TODO: (miguel) this logic (marshalling from struct + validation) will be moved to the actual backend implementation
143
- // This endpoint will support other backends in the future
144
- if provider != CASBackendOCI {
145
- return nil , NewErrValidation (errors .New ("unsupported provider" ))
146
- }
147
-
148
- var ociConfig = struct {
149
- Password string `json:"password"`
150
- Username string `json:"username"`
151
- }{}
152
-
153
- if err := json .Unmarshal (credsJSON , & ociConfig ); err != nil {
154
- return nil , NewErrValidation (err )
155
- }
156
-
157
- // Create and validate credentials
158
- k , err := ociauth .NewCredentials (location , ociConfig .Username , ociConfig .Password )
129
+ func (uc * CASBackendUseCase ) FindByIDInOrg (ctx context.Context , orgID , id string ) (* CASBackend , error ) {
130
+ orgUUID , err := uuid .Parse (orgID )
159
131
if err != nil {
160
- return nil , NewErrValidation (err )
132
+ return nil , NewErrInvalidUUID (err )
161
133
}
162
134
163
- // Check credentials
164
- b , err := oci .NewBackend (location , & oci.RegistryOptions {Keychain : k })
135
+ backendUUID , err := uuid .Parse (id )
165
136
if err != nil {
166
- return nil , fmt .Errorf ("checking credentials: %w" , err )
167
- }
168
-
169
- if err := b .CheckWritePermissions (context .TODO ()); err != nil {
170
- return nil , NewErrValidation (fmt .Errorf ("wrong credentials: %w" , err ))
137
+ return nil , NewErrInvalidUUID (err )
171
138
}
172
139
173
- // Validate and store the secret in the external secrets manager
174
- creds := & credentials.OCIKeypair {Repo : location , Username : ociConfig .Username , Password : ociConfig .Password }
175
- if err := creds .Validate (); err != nil {
176
- return nil , NewErrValidation (err )
140
+ backend , err := uc .repo .FindByIDInOrg (ctx , orgUUID , backendUUID )
141
+ if err != nil {
142
+ return nil , err
143
+ } else if backend == nil {
144
+ return nil , NewErrNotFound ("CAS Backend" )
177
145
}
178
146
179
- return creds , nil
147
+ return backend , nil
180
148
}
181
149
182
- func (uc * CASBackendUseCase ) Create (ctx context.Context , orgID , location , description string , provider CASBackendProvider , credsJSON [] byte , defaultB bool ) (* CASBackend , error ) {
150
+ func (uc * CASBackendUseCase ) Create (ctx context.Context , orgID , location , description string , provider CASBackendProvider , creds any , defaultB bool ) (* CASBackend , error ) {
183
151
orgUUID , err := uuid .Parse (orgID )
184
152
if err != nil {
185
153
return nil , NewErrInvalidUUID (err )
186
154
}
187
155
188
- // Validate and store the secret in the external secrets manager
189
- creds , err := validateAndExtractCredentials (provider , location , credsJSON )
190
- if err != nil {
191
- return nil , NewErrValidation (err )
192
- }
193
-
194
156
secretName , err := uc .credsRW .SaveCredentials (ctx , orgID , creds )
195
157
if err != nil {
196
158
return nil , fmt .Errorf ("storing the credentials: %w" , err )
197
159
}
198
160
199
161
return uc .repo .Create (ctx , & CASBackendCreateOpts {
200
- OrgID : orgUUID ,
201
162
CASBackendOpts : & CASBackendOpts {
202
163
Location : location , SecretName : secretName , Provider : provider , Default : defaultB ,
203
164
Description : description ,
165
+ OrgID : orgUUID ,
204
166
},
205
167
})
206
168
}
207
169
208
170
// Update will update credentials, description or default status
209
- func (uc * CASBackendUseCase ) Update (ctx context.Context , orgID , id , description string , credsJSON [] byte , defaultB bool ) (* CASBackend , error ) {
171
+ func (uc * CASBackendUseCase ) Update (ctx context.Context , orgID , id , description string , creds any , defaultB bool ) (* CASBackend , error ) {
210
172
orgUUID , err := uuid .Parse (orgID )
211
173
if err != nil {
212
174
return nil , NewErrInvalidUUID (err )
@@ -226,13 +188,7 @@ func (uc *CASBackendUseCase) Update(ctx context.Context, orgID, id, description
226
188
227
189
var secretName string
228
190
// We want to rotate credentials
229
- if credsJSON != nil {
230
- // Validate and store the secret in the external secrets manager
231
- creds , err := validateAndExtractCredentials (repo .Provider , repo .Location , credsJSON )
232
- if err != nil {
233
- return nil , NewErrValidation (err )
234
- }
235
-
191
+ if creds != nil {
236
192
secretName , err = uc .credsRW .SaveCredentials (ctx , orgID , creds )
237
193
if err != nil {
238
194
return nil , fmt .Errorf ("storing the credentials: %w" , err )
@@ -242,13 +198,11 @@ func (uc *CASBackendUseCase) Update(ctx context.Context, orgID, id, description
242
198
return uc .repo .Update (ctx , & CASBackendUpdateOpts {
243
199
ID : uuid ,
244
200
CASBackendOpts : & CASBackendOpts {
245
- SecretName : secretName , Default : defaultB , Description : description ,
201
+ SecretName : secretName , Default : defaultB , Description : description , OrgID : orgUUID ,
246
202
},
247
203
})
248
204
}
249
205
250
- // TODO(miguel): we need to think about the update mechanism and add some guardrails
251
- // for example, we might only allow updating credentials but not the repository itself or the provider
252
206
// Deprecated: use Create and update methods separately instead
253
207
func (uc * CASBackendUseCase ) CreateOrUpdate (ctx context.Context , orgID , name , username , password string , provider CASBackendProvider , defaultB bool ) (* CASBackend , error ) {
254
208
orgUUID , err := uuid .Parse (orgID )
@@ -284,10 +238,10 @@ func (uc *CASBackendUseCase) CreateOrUpdate(ctx context.Context, orgID, name, us
284
238
}
285
239
286
240
return uc .repo .Create (ctx , & CASBackendCreateOpts {
287
- OrgID : orgUUID ,
288
241
CASBackendOpts : & CASBackendOpts {
289
242
Location : name , SecretName : secretName , Provider : provider ,
290
243
Default : defaultB ,
244
+ OrgID : orgUUID ,
291
245
},
292
246
})
293
247
}
@@ -353,8 +307,6 @@ func (CASBackendValidationStatus) Values() (kinds []string) {
353
307
}
354
308
355
309
// Validate that the repository is valid and reachable
356
- // TODO: run this process periodically in the background
357
- // TODO: we need to support other kinds of repositories this is for the OCI type
358
310
func (uc * CASBackendUseCase ) PerformValidation (ctx context.Context , id string ) (err error ) {
359
311
validationStatus := CASBackendValidationFailed
360
312
@@ -370,10 +322,9 @@ func (uc *CASBackendUseCase) PerformValidation(ctx context.Context, id string) (
370
322
return NewErrNotFound ("CAS Backend" )
371
323
}
372
324
373
- // Currently this code is just for OCI repositories
374
- if backend .Provider != CASBackendOCI {
375
- uc .logger .Warnw ("msg" , "validation not supported for this provider" , "ID" , id , "provider" , backend .Provider )
376
- return nil
325
+ provider , ok := uc .providers [string (backend .Provider )]
326
+ if ! ok {
327
+ return fmt .Errorf ("CAS backend provider not found: %s" , backend .Provider )
377
328
}
378
329
379
330
defer func () {
@@ -390,14 +341,21 @@ func (uc *CASBackendUseCase) PerformValidation(ctx context.Context, id string) (
390
341
}()
391
342
392
343
// 1 - Retrieve the credentials from the external secrets manager
393
- b , err := uc . ociBackendProvider . FromCredentials ( ctx , backend . SecretName )
394
- if err != nil {
344
+ var creds any
345
+ if err := uc . credsRW . ReadCredentials ( ctx , backend . SecretName , & creds ); err != nil {
395
346
uc .logger .Infow ("msg" , "credentials not found or invalid" , "ID" , id )
396
347
return nil
397
348
}
398
349
399
- // 2 - Perform a write validation
400
- if err = b .CheckWritePermissions (context .TODO ()); err != nil {
350
+ credsJSON , err := json .Marshal (creds )
351
+ if err != nil {
352
+ uc .logger .Infow ("msg" , "credentials invalid" , "ID" , id )
353
+ return nil
354
+ }
355
+
356
+ // 2 - run validation
357
+ _ , err = provider .ValidateAndExtractCredentials (backend .Location , credsJSON )
358
+ if err != nil {
401
359
uc .logger .Infow ("msg" , "permissions validation failed" , "ID" , id )
402
360
return nil
403
361
}
0 commit comments