Skip to content

Commit 56abb1d

Browse files
authored
feat(integrations): refactor FanOut plugins (#2441)
Signed-off-by: Jose I. Paris <[email protected]>
1 parent 7b62a50 commit 56abb1d

File tree

19 files changed

+634
-559
lines changed

19 files changed

+634
-559
lines changed

app/controlplane/internal/dispatcher/dispatcher_test.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ func (s *dispatcherTestSuite) TestLoadInputsEnvelope() {
5353
envelope, err := testEnvelope("testdata/attestation.json")
5454
require.NoError(s.T(), err)
5555

56+
s.ociIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "CONTAINER_IMAGE").Return(true)
57+
s.ociIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "SBOM_CYCLONEDX_JSON").Return(false)
58+
s.ociIntegrationBackend.(*mockedSDK.FanOut).On("String").Return("mocked-integration")
59+
5660
err = s.dispatcher.loadInputs(context.TODO(), queue, envelope, "backend-type", "secret-name")
5761
assert.NoError(s.T(), err)
5862

@@ -84,6 +88,15 @@ func (s *dispatcherTestSuite) TestLoadInputsMaterials() {
8488
integrationInfoBuilder(s.cdxIntegrationBackend),
8589
}
8690

91+
s.ociIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "CONTAINER_IMAGE").Return(false)
92+
s.ociIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "SBOM_CYCLONEDX_JSON").Return(false)
93+
s.containerIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "CONTAINER_IMAGE").Return(true)
94+
s.containerIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "SBOM_CYCLONEDX_JSON").Return(false)
95+
s.containerIntegrationBackend.(*mockedSDK.FanOut).On("String").Return("mocked-integration")
96+
s.cdxIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "CONTAINER_IMAGE").Return(false)
97+
s.cdxIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", "SBOM_CYCLONEDX_JSON").Return(true)
98+
s.cdxIntegrationBackend.(*mockedSDK.FanOut).On("String").Return("mocked-integration")
99+
87100
envelope, err := testEnvelope("testdata/attestation.json")
88101
require.NoError(s.T(), err)
89102

@@ -178,12 +191,18 @@ func (s *dispatcherTestSuite) TestInitDispatchQueue() {
178191
integrationInfoBuilder(s.cdxIntegrationBackend), integrationInfoBuilder(s.cdxIntegrationBackend),
179192
}
180193

194+
s.containerIntegrationBackend.(*mockedSDK.FanOut).On("String", mock.Anything).Return("mocked-integration")
195+
s.cdxIntegrationBackend.(*mockedSDK.FanOut).On("String", mock.Anything).Return("mocked-integration")
196+
s.ociIntegrationBackend.(*mockedSDK.FanOut).On("String", mock.Anything).Return("mocked-integration")
181197
q, err := s.dispatcher.initDispatchQueue(context.TODO(), s.org.ID, s.workflow.ID.String())
182198
require.NoError(t, err)
183199

184200
// There are 4 integrations attached
185201
require.Len(t, q, 4)
186202

203+
s.containerIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", mock.Anything).Return(true)
204+
s.cdxIntegrationBackend.(*mockedSDK.FanOut).On("IsSubscribedTo", mock.Anything).Return(true)
205+
187206
for i, tc := range []struct{ id, subscribedMaterial string }{
188207
{"OCI_INTEGRATION", ""},
189208
{"CONTAINER_INTEGRATION", "CONTAINER_IMAGE"},
@@ -228,9 +247,6 @@ func (s *dispatcherTestSuite) SetupTest() {
228247
s.emptyWorkflow, err = s.Workflow.Create(ctx, &biz.WorkflowCreateOpts{Name: "empty-workflow", OrgID: s.org.ID, Project: "test-project"})
229248
assert.NoError(s.T(), err)
230249

231-
customImplementation := mockedSDK.NewFanOutPlugin(s.T())
232-
customImplementation.On("Register", ctx, mock.Anything).Return(&sdk.RegistrationResponse{Configuration: []byte("deadbeef")}, nil)
233-
customImplementation.On("Attach", ctx, mock.Anything).Return(&sdk.AttachmentResponse{Configuration: []byte("deadbeef")}, nil)
234250
type schema struct {
235251
TestProperty string
236252
}
@@ -246,11 +262,13 @@ func (s *dispatcherTestSuite) SetupTest() {
246262
sdk.WithInputMaterial(v1.CraftingSchema_Material_SBOM_CYCLONEDX_JSON),
247263
)
248264
require.NoError(s.T(), err)
265+
customImplementation := s.newMock(ctx)
266+
customImplementation.On("Describe").Return(b.Describe())
249267

250268
// Registration configuration
251269
config, _ := structpb.NewStruct(map[string]interface{}{"TestProperty": "testValue"})
252270

253-
s.cdxIntegrationBackend = &mockedIntegration{FanOutPlugin: customImplementation, FanOutIntegration: b}
271+
s.cdxIntegrationBackend = customImplementation
254272
s.cdxIntegration, err = s.Integration.RegisterAndSave(ctx, s.org.ID, "sbom-integration", "", s.cdxIntegrationBackend, config)
255273
require.NoError(s.T(), err)
256274

@@ -263,8 +281,10 @@ func (s *dispatcherTestSuite) SetupTest() {
263281
sdk.WithInputMaterial(v1.CraftingSchema_Material_CONTAINER_IMAGE),
264282
)
265283
require.NoError(s.T(), err)
284+
customImplementation = s.newMock(ctx)
285+
customImplementation.On("Describe").Return(b.Describe())
266286

267-
s.containerIntegrationBackend = &mockedIntegration{FanOutPlugin: customImplementation, FanOutIntegration: b}
287+
s.containerIntegrationBackend = customImplementation
268288
s.containerIntegration, err = s.Integration.RegisterAndSave(ctx, s.org.ID, "container-integration", "", s.containerIntegrationBackend, config)
269289
require.NoError(s.T(), err)
270290

@@ -277,8 +297,10 @@ func (s *dispatcherTestSuite) SetupTest() {
277297
},
278298
)
279299
require.NoError(s.T(), err)
300+
customImplementation = s.newMock(ctx)
301+
customImplementation.On("Describe").Return(b.Describe())
280302

281-
s.ociIntegrationBackend = &mockedIntegration{FanOutPlugin: customImplementation, FanOutIntegration: b}
303+
s.ociIntegrationBackend = customImplementation
282304
s.ociIntegration, err = s.Integration.RegisterAndSave(ctx, s.org.ID, "oci-integration", "", s.ociIntegrationBackend, config)
283305
require.NoError(s.T(), err)
284306

@@ -316,9 +338,12 @@ func (s *dispatcherTestSuite) SetupTest() {
316338
s.dispatcher = New(s.Integration, nil, nil, nil, s.casClient, registeredIntegrations, l)
317339
}
318340

319-
type mockedIntegration struct {
320-
*sdk.FanOutIntegration
321-
*mockedSDK.FanOutPlugin
341+
func (s *dispatcherTestSuite) newMock(ctx context.Context) *mockedSDK.FanOut {
342+
customImplementation := mockedSDK.NewFanOut(s.T())
343+
customImplementation.On("Register", ctx, mock.Anything).Return(&sdk.RegistrationResponse{Configuration: []byte("deadbeef")}, nil)
344+
customImplementation.On("Attach", ctx, mock.Anything).Return(&sdk.AttachmentResponse{Configuration: []byte("deadbeef")}, nil)
345+
346+
return customImplementation
322347
}
323348

324349
// Utility struct to hold the test suite

app/controlplane/internal/service/integration.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func (s *IntegrationsService) ListAvailable(_ context.Context, _ *pb.Integration
5353
d := i.Describe()
5454

5555
var subscribedMaterials = make([]string, 0)
56-
for _, m := range d.SubscribedMaterials {
56+
for _, m := range i.GetSubscribedMaterials() {
5757
subscribedMaterials = append(subscribedMaterials, m.Type.String())
5858
}
5959

app/controlplane/pkg/biz/integration.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func (uc *IntegrationUseCase) RegisterAndSave(ctx context.Context, orgID, name,
130130
}
131131

132132
// 2 - validate JSON against the schema
133-
if err := i.ValidateRegistrationRequest(pluginRequest); err != nil {
133+
if err := sdk.ValidateRegistrationRequest(i, pluginRequest); err != nil {
134134
return nil, NewErrValidation(err)
135135
}
136136

@@ -227,7 +227,7 @@ func (uc *IntegrationUseCase) AttachToWorkflow(ctx context.Context, opts *Attach
227227
}
228228

229229
// 2 - validate JSON against the schema
230-
if err := opts.FanOutIntegration.ValidateAttachmentRequest(pluginRequest); err != nil {
230+
if err := sdk.ValidateAttachmentRequest(opts.FanOutIntegration, pluginRequest); err != nil {
231231
return nil, NewErrValidation(err)
232232
}
233233

app/controlplane/pkg/biz/integration_test.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,23 @@ func (s *testSuite) TestCreate() {
3939

4040
// Mocked integration that will return both generic configuration and credentials
4141
integration := integrationMocks.NewFanOut(s.T())
42+
type schema struct {
43+
FirstName string `json:"firstName"`
44+
}
45+
46+
fanOutSchemas := &sdk.InputSchema{Registration: schema{}, Attachment: schema{}}
47+
48+
b, err := sdk.NewFanOut(
49+
&sdk.NewParams{
50+
ID: kind,
51+
Version: "1.0",
52+
InputSchema: fanOutSchemas,
53+
},
54+
)
55+
assert.NoError(err)
4256

57+
integration.On("Describe").Return(b.Describe()).Maybe()
4358
ctx := context.Background()
44-
integration.On("Describe").Return(&sdk.IntegrationInfo{ID: kind}).Maybe()
45-
integration.On("ValidateRegistrationRequest", mock.Anything).Maybe().Return(nil)
4659
integration.On("Register", ctx, mock.Anything).Return(&sdk.RegistrationResponse{
4760
Configuration: s.config, Credentials: &sdk.Credentials{
4861
Password: "key", URL: "host"},
@@ -182,7 +195,6 @@ func (s *testSuite) TestAttachWorkflow() {
182195
s.fanOutIntegration.On("Attach", ctx, mock.Anything).Return(&sdk.AttachmentResponse{
183196
Configuration: s.config,
184197
}, nil).Once()
185-
s.fanOutIntegration.On("ValidateAttachmentRequest", mock.Anything).Return(nil)
186198

187199
got, err := s.Integration.AttachToWorkflow(ctx, &biz.AttachOpts{
188200
OrgID: s.org.ID,
@@ -207,7 +219,6 @@ func (s *testSuite) TestAttachWorkflow() {
207219
s.Run("attachment fails", func() {
208220
ctx := context.Background()
209221
s.fanOutIntegration.On("Attach", ctx, mock.Anything).Return(nil, errors.New("invalid attachment options")).Once()
210-
s.fanOutIntegration.On("ValidateAttachmentRequest", mock.Anything).Return(nil)
211222

212223
_, err := s.Integration.AttachToWorkflow(ctx, &biz.AttachOpts{
213224
OrgID: s.org.ID,
@@ -228,7 +239,6 @@ func (s *testSuite) TestListAttachments() {
228239
s.fanOutIntegration.On("Attach", ctx, mock.Anything).Return(&sdk.AttachmentResponse{
229240
Configuration: s.config,
230241
}, nil).Once()
231-
s.fanOutIntegration.On("ValidateAttachmentRequest", mock.Anything).Return(nil)
232242

233243
// Attach the integration to the workflow
234244
_, err := s.Integration.AttachToWorkflow(ctx, &biz.AttachOpts{
@@ -289,8 +299,22 @@ func (s *testSuite) SetupTest() {
289299

290300
// Mocked fanOut that will return both generic configuration and credentials
291301
fanOut := integrationMocks.NewFanOut(s.T())
292-
fanOut.On("Describe").Return(&sdk.IntegrationInfo{})
293-
fanOut.On("ValidateRegistrationRequest", mock.Anything).Return(nil)
302+
type schema struct {
303+
FirstName string `json:"firstName"`
304+
}
305+
306+
fanOutSchemas := &sdk.InputSchema{Registration: schema{}, Attachment: schema{}}
307+
308+
b, err := sdk.NewFanOut(
309+
&sdk.NewParams{
310+
ID: "integration",
311+
Version: "1.0",
312+
InputSchema: fanOutSchemas,
313+
},
314+
)
315+
assert.NoError(err)
316+
317+
fanOut.On("Describe").Return(b.Describe())
294318
fanOut.On("Register", ctx, mock.Anything).Return(&sdk.RegistrationResponse{Configuration: s.config}, nil)
295319
s.fanOutIntegration = fanOut
296320

app/controlplane/pkg/biz/organization_integration_test.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,22 @@ func (s *OrgIntegrationTestSuite) SetupTest() {
258258
// Integration
259259
// Mocked integration that will return both generic configuration and credentials
260260
integration := integrationMocks.NewFanOut(s.T())
261-
integration.On("Describe").Return(&sdk.IntegrationInfo{})
262-
integration.On("ValidateRegistrationRequest", mock.Anything).Return(nil)
261+
type schema struct {
262+
FirstName string `json:"firstName"`
263+
}
264+
265+
fanOutSchemas := &sdk.InputSchema{Registration: schema{}, Attachment: schema{}}
266+
267+
b, err := sdk.NewFanOut(
268+
&sdk.NewParams{
269+
ID: "integration",
270+
Version: "1.0",
271+
InputSchema: fanOutSchemas,
272+
},
273+
)
274+
assert.NoError(err)
275+
276+
integration.On("Describe").Return(b.Describe())
263277
integration.On("Register", ctx, mock.Anything).Return(&sdk.RegistrationResponse{
264278
Configuration: []byte("deadbeef")}, nil)
265279

app/controlplane/plugins/core/dependency-track/v1/extension_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func TestValidateRegistrationInput(t *testing.T) {
6767
t.Run(tc.name, func(t *testing.T) {
6868
payload, err := json.Marshal(tc.input)
6969
require.NoError(t, err)
70-
err = integration.ValidateRegistrationRequest(payload)
70+
err = sdk.ValidateRegistrationRequest(integration, payload)
7171
if tc.errMsg != "" {
7272
assert.ErrorContains(t, err, tc.errMsg)
7373
} else {
@@ -211,7 +211,7 @@ func TestValidateAttachmentInput(t *testing.T) {
211211
t.Run(tc.name, func(t *testing.T) {
212212
payload, err := json.Marshal(tc.input)
213213
require.NoError(t, err)
214-
err = integration.ValidateAttachmentRequest(payload)
214+
err = sdk.ValidateAttachmentRequest(integration, payload)
215215
if tc.errMsg != "" {
216216
assert.ErrorContains(t, err, tc.errMsg)
217217
} else {
@@ -244,8 +244,7 @@ func TestValidateExecuteOpts(t *testing.T) {
244244
{
245245
name: "invalid - invalid material",
246246
opts: &sdk.ExecutionRequest{
247-
Input: &sdk.ExecuteInput{Materials: []*sdk.ExecuteMaterial{{NormalizedMaterial: &chainloop.NormalizedMaterial{Type: "invalid"}, Content: []byte("content")}}},
248-
},
247+
Input: &sdk.ExecuteInput{Materials: []*sdk.ExecuteMaterial{{NormalizedMaterial: &chainloop.NormalizedMaterial{Type: "invalid"}, Content: []byte("content")}}}},
249248
errMsg: "invalid input type",
250249
},
251250
{

app/controlplane/plugins/core/discord-webhook/v1/discord_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"encoding/json"
2020
"testing"
2121

22+
"github.com/chainloop-dev/chainloop/app/controlplane/plugins/sdk/v1"
2223
"github.com/stretchr/testify/assert"
2324
"github.com/stretchr/testify/require"
2425
)
@@ -76,7 +77,7 @@ func TestValidateRegistrationInput(t *testing.T) {
7677
payload, err := json.Marshal(tc.input)
7778
require.NoError(t, err)
7879

79-
err = integration.ValidateRegistrationRequest(payload)
80+
err = sdk.ValidateRegistrationRequest(integration, payload)
8081
if tc.errMsg != "" {
8182
assert.ErrorContains(t, err, tc.errMsg)
8283
} else {

app/controlplane/plugins/core/slack-webhook/v1/slack_webhook_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"encoding/json"
2020
"testing"
2121

22+
"github.com/chainloop-dev/chainloop/app/controlplane/plugins/sdk/v1"
2223
"github.com/stretchr/testify/assert"
2324
"github.com/stretchr/testify/require"
2425
)
@@ -67,7 +68,7 @@ func TestValidateRegistrationInput(t *testing.T) {
6768
payload, err := json.Marshal(tc.input)
6869
require.NoError(t, err)
6970

70-
err = integration.ValidateRegistrationRequest(payload)
71+
err = sdk.ValidateRegistrationRequest(integration, payload)
7172
if tc.errMsg != "" {
7273
assert.ErrorContains(t, err, tc.errMsg)
7374
} else {

app/controlplane/plugins/core/smtp/v1/extension_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"encoding/json"
2020
"testing"
2121

22+
"github.com/chainloop-dev/chainloop/app/controlplane/plugins/sdk/v1"
2223
"github.com/stretchr/testify/assert"
2324
"github.com/stretchr/testify/require"
2425
)
@@ -52,7 +53,7 @@ func TestValidateRegistrationInput(t *testing.T) {
5253
t.Run(tc.name, func(t *testing.T) {
5354
payload, err := json.Marshal(tc.input)
5455
require.NoError(t, err)
55-
err = integration.ValidateRegistrationRequest(payload)
56+
err = sdk.ValidateRegistrationRequest(integration, payload)
5657
if tc.errMsg != "" {
5758
assert.ErrorContains(t, err, tc.errMsg)
5859
} else {
@@ -90,7 +91,7 @@ func TestValidateAttachmentInput(t *testing.T) {
9091
t.Run(tc.name, func(t *testing.T) {
9192
payload, err := json.Marshal(tc.input)
9293
require.NoError(t, err)
93-
err = integration.ValidateAttachmentRequest(payload)
94+
err = sdk.ValidateAttachmentRequest(integration, payload)
9495
if tc.errMsg != "" {
9596
assert.ErrorContains(t, err, tc.errMsg)
9697
} else {

app/controlplane/plugins/sdk/readme-generator/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func updateIntegrationsIndex(plugins sdk.AvailablePlugins) error {
8383
info := p.Describe()
8484
// Load the materials
8585
var subscribedMaterials = make([]string, 0)
86-
for _, m := range info.SubscribedMaterials {
86+
for _, m := range p.GetSubscribedMaterials() {
8787
subscribedMaterials = append(subscribedMaterials, m.Type.String())
8888
}
8989

0 commit comments

Comments
 (0)