-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Creating and Getting GCP Integration #18
Changes from 2 commits
052a771
185e310
320640f
37c4d77
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,6 +5,61 @@ import ( | |||||||||||||||||||||||||||||
"strings" | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
type integrationType int | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const ( | ||||||||||||||||||||||||||||||
// awsCFG - AWS Config integration type | ||||||||||||||||||||||||||||||
// awsCFG integrationType = iota | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// awsCT - AWS CloudTrail integration type | ||||||||||||||||||||||||||||||
// awsCT | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// gcpCFG - GCP Config integration type | ||||||||||||||||||||||||||||||
gcpCFG integrationType = iota | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// gcpAT - GCP Audit Log integration type | ||||||||||||||||||||||||||||||
// gcpAT | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// azureCFG - Azure Config integration type | ||||||||||||||||||||||||||||||
// azureCFG | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// azureAL - Azure Activity Log integration type | ||||||||||||||||||||||||||||||
// azureAL | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
var integrationTypes = []string{ | ||||||||||||||||||||||||||||||
"AWS_CFG", | ||||||||||||||||||||||||||||||
"AWS_CT_SQS", | ||||||||||||||||||||||||||||||
"GCP_CFG", | ||||||||||||||||||||||||||||||
"GCP_AT_SES", | ||||||||||||||||||||||||||||||
"AZURE_CFG", | ||||||||||||||||||||||||||||||
"AZURE_AL_SEQ", | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
func (i integrationType) String() string { | ||||||||||||||||||||||||||||||
return integrationTypes[i] | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// gcpResourceLevel determines Project or Organization level integration | ||||||||||||||||||||||||||||||
type gcpResourceLevel int | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const ( | ||||||||||||||||||||||||||||||
// GcpProject level integration with GCP | ||||||||||||||||||||||||||||||
GcpProject gcpResourceLevel = iota | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// GcpOrganization level integration with GCP | ||||||||||||||||||||||||||||||
GcpOrganization | ||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||
Comment on lines
+46
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since all these are global constants, we should make sure to call them appropriately, I would propose:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let us do this in a further PR, I want us to keep iteration over this. Great work James! |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
var gcpResourceLevels = []string{ | ||||||||||||||||||||||||||||||
"PROJECT", | ||||||||||||||||||||||||||||||
"ORGANIZATION", | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
func (g gcpResourceLevel) String() string { | ||||||||||||||||||||||||||||||
return gcpResourceLevels[g] | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// GetIntegrations lists the external integrations available on the server | ||||||||||||||||||||||||||||||
func (c *Client) GetIntegrations() (response integrationsResponse, err error) { | ||||||||||||||||||||||||||||||
err = c.RequestDecoder("GET", apiIntegrations, nil, &response) | ||||||||||||||||||||||||||||||
|
@@ -21,6 +76,47 @@ func (c *Client) GetAWSIntegrations() (response awsIntegrationsResponse, err err | |||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// NewGCPIntegrationData returns an instance of gcpIntegrationData | ||||||||||||||||||||||||||||||
func NewGCPIntegrationData(name string, idType gcpResourceLevel) gcpIntegrationData { | ||||||||||||||||||||||||||||||
return gcpIntegrationData{ | ||||||||||||||||||||||||||||||
commonIntegrationData: commonIntegrationData{ | ||||||||||||||||||||||||||||||
Name: name, | ||||||||||||||||||||||||||||||
Type: gcpCFG.String(), | ||||||||||||||||||||||||||||||
Enabled: 1, | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
Data: gcpCfg{ | ||||||||||||||||||||||||||||||
IdType: idType.String(), | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// CreateGCPConfigIntegration creates a single integration on the server | ||||||||||||||||||||||||||||||
func (c *Client) CreateGCPConfigIntegration(data gcpIntegrationData) (response gcpIntegrationsResponse, err error) { | ||||||||||||||||||||||||||||||
err = c.createIntegration(data, &response) | ||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
func (c *Client) createIntegration(data interface{}, response interface{}) error { | ||||||||||||||||||||||||||||||
body, err := jsonReader(data) | ||||||||||||||||||||||||||||||
mjunglw marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||
return err | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
err = c.RequestDecoder("POST", apiIntegrations, body, response) | ||||||||||||||||||||||||||||||
return err | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// GetGCPConfigIntegration gets a single integration matching the integration guid available on the server | ||||||||||||||||||||||||||||||
func (c *Client) GetGCPConfigIntegration(intgGuid string) (response gcpIntegrationsResponse, err error) { | ||||||||||||||||||||||||||||||
err = c.getIntegration(intgGuid, &response) | ||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
func (c *Client) getIntegration(intgGuid string, response interface{}) error { | ||||||||||||||||||||||||||||||
apiPath := fmt.Sprintf(apiIntegrationByGUID, intgGuid) | ||||||||||||||||||||||||||||||
return c.RequestDecoder("GET", apiPath, nil, response) | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
type commonIntegrationData struct { | ||||||||||||||||||||||||||||||
IntgGuid string `json:"INTG_GUID"` | ||||||||||||||||||||||||||||||
Name string `json:"NAME"` | ||||||||||||||||||||||||||||||
|
@@ -76,10 +172,9 @@ type gcpIntegrationData struct { | |||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
type gcpCfg struct { | ||||||||||||||||||||||||||||||
ID string `json:"ID"` | ||||||||||||||||||||||||||||||
IdType string `json:"ID_TYPE"` | ||||||||||||||||||||||||||||||
IssueGrouping string `json:"ISSUE_GROUPING"` | ||||||||||||||||||||||||||||||
Credentials gcpCredentials `json:"CREDENTIALS"` | ||||||||||||||||||||||||||||||
ID string `json:"ID"` | ||||||||||||||||||||||||||||||
IdType string `json:"ID_TYPE"` | ||||||||||||||||||||||||||||||
Credentials gcpCredentials `json:"CREDENTIALS"` | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
type gcpCredentials struct { | ||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,123 @@ | ||
package api_test | ||
|
||
import "testing" | ||
import ( | ||
"fmt" | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/lacework/go-sdk/api" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetIntegrations(t *testing.T) { | ||
// TODO @afiune implement a mocked Lacework API server | ||
} | ||
|
||
func TestCreateGCPConfigIntegration(t *testing.T) { | ||
intgGUID := "12345" | ||
|
||
fakeAPI := NewLaceworkServer() | ||
fakeAPI.MockAPI("external/integrations", func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, ` | ||
{ | ||
"data": [ | ||
{ | ||
"INTG_GUID": "`+intgGUID+`", | ||
"NAME": "integration_name", | ||
"CREATED_OR_UPDATED_TIME": "2020-Mar-10 01:00:00 UTC", | ||
"CREATED_OR_UPDATED_BY": "[email protected]", | ||
"TYPE": "GCP_CFG", | ||
"ENABLED": 1, | ||
"STATE": { | ||
"ok": true, | ||
"lastUpdatedTime": "2020-Mar-10 01:00:00 UTC", | ||
"lastSuccessfulTime": "2020-Mar-10 01:00:00 UTC" | ||
}, | ||
"IS_ORG": 0, | ||
"DATA": { | ||
"CREDENTIALS": { | ||
"CLIENT_ID": "xxxxxxxxx", | ||
"CLIENT_EMAIL": "[email protected]", | ||
"PRIVATE_KEY_ID": "xxxxxxxxxxxxxxxx" | ||
}, | ||
"ID_TYPE": "PROJECT", | ||
"ID": "xxxxxxxxxx" | ||
}, | ||
"TYPE_NAME": "GCP Compliance" | ||
} | ||
], | ||
"ok": true, | ||
"message": "SUCCESS" | ||
} | ||
`) | ||
}) | ||
defer fakeAPI.Close() | ||
|
||
c, err := api.NewClient("test", api.WithToken("xxxxxx"), api.WithURL(fakeAPI.URL())) | ||
assert.Nil(t, err) | ||
|
||
data := api.NewGCPIntegrationData("integration_name", api.GcpProject) | ||
This conversation was marked as resolved.
Show resolved
Hide resolved
|
||
data.Data.ID = "xxxxxxxxxx" | ||
data.Data.Credentials.ClientId = "xxxxxxxxx" | ||
data.Data.Credentials.ClientEmail = "[email protected]" | ||
data.Data.Credentials.PrivateKeyId = "xxxxxxxxxxxxxxxx" | ||
|
||
response, err := c.CreateGCPConfigIntegration(data) | ||
assert.Nil(t, err) | ||
assert.NotNil(t, response) | ||
assert.True(t, response.Ok) | ||
assert.Equal(t, 1, len(response.Data)) | ||
assert.Equal(t, intgGUID, response.Data[0].IntgGuid) | ||
} | ||
|
||
func TestGetGCPConfigIntegration(t *testing.T) { | ||
intgGUID := "12345" | ||
apiPath := fmt.Sprintf("external/integrations/%s", intgGUID) | ||
|
||
fakeAPI := NewLaceworkServer() | ||
fakeAPI.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, ` | ||
{ | ||
"data": [ | ||
{ | ||
"INTG_GUID": "`+intgGUID+`", | ||
"NAME": "integration_name", | ||
"CREATED_OR_UPDATED_TIME": "2020-Mar-10 01:00:00 UTC", | ||
"CREATED_OR_UPDATED_BY": "[email protected]", | ||
"TYPE": "GCP_CFG", | ||
"ENABLED": 1, | ||
"STATE": { | ||
"ok": true, | ||
"lastUpdatedTime": "2020-Mar-10 01:00:00 UTC", | ||
"lastSuccessfulTime": "2020-Mar-10 01:00:00 UTC" | ||
}, | ||
"IS_ORG": 0, | ||
"DATA": { | ||
"CREDENTIALS": { | ||
"CLIENT_ID": "xxxxxxxxx", | ||
"CLIENT_EMAIL": "[email protected]", | ||
"PRIVATE_KEY_ID": "xxxxxxxxxxxxxxxx" | ||
}, | ||
"ID_TYPE": "PROJECT", | ||
"ID": "xxxxxxxxxx" | ||
}, | ||
"TYPE_NAME": "GCP Compliance" | ||
} | ||
], | ||
"ok": true, | ||
"message": "SUCCESS" | ||
} | ||
`) | ||
}) | ||
defer fakeAPI.Close() | ||
|
||
c, err := api.NewClient("test", api.WithToken("xxxxxx"), api.WithURL(fakeAPI.URL())) | ||
assert.Nil(t, err) | ||
|
||
response, err := c.GetGCPConfigIntegration(intgGUID) | ||
assert.Nil(t, err) | ||
assert.NotNil(t, response) | ||
assert.True(t, response.Ok) | ||
assert.Equal(t, 1, len(response.Data)) | ||
assert.Equal(t, intgGUID, response.Data[0].IntgGuid) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I think about it, you have to be very careful here, the fact that you add a single
constant with the keyword
iota
it means that you will have that constant set to0
(
gcpCFG = 0
)I bet you that this is a bug! if we call
gcpCFG.String()
it will returnAWS_CFG
That is why I always recommend using this pattern:
Mainly because you won't have to worry about the order of the array or index etc.
You just define them and it automatically works.
I would suggest implementing this pattern instead 👆🏽
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look at this shippable job link
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you were right. Now I see. For refactoring / adding new features, the map seems simpler.