diff --git a/api/_examples/resource-groups/main.go b/api/_examples/resource-groups/main.go index 18e66d8ba..c1bce30f6 100644 --- a/api/_examples/resource-groups/main.go +++ b/api/_examples/resource-groups/main.go @@ -25,12 +25,7 @@ func main() { for _, account := range res.Data { var resourceGuid string resourceType := account.Type - - if account.Props != nil { - resourceGuid = account.ResourceGuid - } else { - resourceGuid = account.ResourceGroupGuid - } + resourceGuid = account.ResourceGroupGuid support := "Unsupported" switch resourceType { @@ -42,13 +37,15 @@ func main() { support = "Supported" case api.GcpResourceGroup.String(): support = "Supported" - case api.LwAccountResourceGroup.String(): - support = "Supported" case api.MachineResourceGroup.String(): support = "Supported" + case api.OciResourceGroup.String(): + support = "Supported" + case api.KubernetesResourceGroup.String(): + support = "Supported" } - // Output: RESOURCE_GUID:RESOURCE_TYPE:[Supported|Unsupported] + // Output: RESOURCE_GROUP_GUID:RESOURCE_TYPE:[Supported|Unsupported] fmt.Printf("%s:%s:%s\n", resourceGuid, resourceType, support) } @@ -74,7 +71,7 @@ func main() { }, } - myResourceGroupWithQuery := api.NewResourceGroupWithQuery( + myResourceGroupWithQuery := api.NewResourceGroup( "resource-group-with-query-from-golang", api.AwsResourceGroup, "Resource groups in `us` regions", @@ -91,9 +88,9 @@ func main() { fmt.Printf("Succesfully created resource group \n %+v\n", rgV2Resp) println("Updating v2 resource group name") - rgV2Resp.Data.NameV2 = "resource-group-with-query-from-golang-updated" + rgV2Resp.Data.Name = "resource-group-with-query-from-golang-updated" - updatedResponse, err := lacework.V2.ResourceGroups.UpdateAws(&rgV2Resp.Data) + updatedResponse, err := lacework.V2.ResourceGroups.Update(&rgV2Resp.Data) if err != nil { log.Fatal(err) @@ -106,32 +103,4 @@ func main() { log.Fatal(err) } println("Successfully deleted resource group") - - props := api.LwAccountResourceGroupProps{ - Description: "All Lacework accounts", - LwAccounts: []string{"tech-ally"}, - } - - myResourceGroup := api.NewResourceGroup( - "resource-group-from-golang", - api.LwAccountResourceGroup, - props, - ) - - // LW_ACCOUNT resource groups are only allowed at Organization level, - // copy the client to make it an org client - orgLwClient, err := api.CopyClient(lacework, - api.WithOrgAccess(), - ) - if err != nil { - log.Fatal(err) - } - - response, err := orgLwClient.V2.ResourceGroups.Create(myResourceGroup) - if err != nil { - log.Fatal(err) - } - - // Output: Resource Group created: RESOURCE_GUID - fmt.Printf("Resource Group created: %s", response.Data.ResourceGuid) } diff --git a/api/_templates/resource_groups/kubernetes.json b/api/_templates/resource_groups/kubernetes.json new file mode 100644 index 000000000..a91d047c0 --- /dev/null +++ b/api/_templates/resource_groups/kubernetes.json @@ -0,0 +1,49 @@ +{ + "filters": { + "filter1": { + "field": "AWS Account", + "operation": "EQUALS", + "values": [ + "123456789012" + ] + }, + "filter2": { + "field": "AWS Region", + "operation": "EQUALS", + "values": [ + "us-west-2" + ] + }, + "filter3": { + "field": "Cluster Name", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter4": { + "field": "Namespace", + "operation": "EQUALS", + "values": [ + "prod" + ] + } + }, + "expression": { + "operator": "OR", + "children": [ + { + "filterName": "filter1" + }, + { + "filterName": "filter2" + }, + { + "filterName": "filter3" + }, + { + "filterName": "filter4" + } + ] + } +} \ No newline at end of file diff --git a/api/feature_flags.go b/api/feature_flags.go index 22f341381..8fa897c6e 100644 --- a/api/feature_flags.go +++ b/api/feature_flags.go @@ -4,8 +4,6 @@ import ( "fmt" ) -const ApiV2CliFeatureFlag = "PUBLIC.rgv2.cli" - type FeatureFlagsService struct { client *Client } diff --git a/api/resource_groups.go b/api/resource_groups.go index 170843236..35b15aa9a 100644 --- a/api/resource_groups.go +++ b/api/resource_groups.go @@ -22,37 +22,11 @@ import ( _ "embed" "encoding/json" "fmt" - "strconv" "time" - "github.com/lacework/go-sdk/lwtime" "github.com/pkg/errors" ) -// ResourceGroupsService is the service that interacts with -// the ResourceGroups schema from the Lacework APIv2 Server -type ResourceGroupsService struct { - client *Client -} - -type ResourceGroupProps interface { - GetBaseProps() ResourceGroupPropsBase -} - -type ResourceGroupPropsBase struct { - Description string `json:"description"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated *lwtime.Epoch `json:"lastUpdated,omitempty"` -} - -type ResourceGroup interface { - ID() string - ResourceGroupType() resourceGroupType - ResetResourceGUID() - ResetRGV2Fields() - IsV2Group() bool -} - type resourceGroupType int const ( @@ -63,11 +37,8 @@ const ( ContainerResourceGroup GcpResourceGroup MachineResourceGroup - - // requires Org Access account client.WithOrgAccess() - LwAccountResourceGroup - OciResourceGroup + KubernetesResourceGroup ) // query templates @@ -82,10 +53,11 @@ var ( //go:embed _templates/resource_groups/gcp.json GcpResourceGroupQueryTemplate string //go:embed _templates/resource_groups/machine.json - MachineResourceGroupQueryTemplate string - LwAccountResourceGroupQueryTemplate string = "" + MachineResourceGroupQueryTemplate string //go:embed _templates/resource_groups/oci.json OciResourceGroupQueryTemplate string + //go:embed _templates/resource_groups/kubernetes.json + KubernetesResourceGroupQueryTemplate string ) type resourceGroupContext struct { @@ -95,53 +67,37 @@ type resourceGroupContext struct { // ResourceGroupTypes is the list of available Resource Group types var ResourceGroupTypes = map[resourceGroupType]resourceGroupContext{ - NoneResourceGroup: {resourceGroupType: "None", queryTemplate: NoneResourceGroupQueryTemplate}, - AwsResourceGroup: {resourceGroupType: "AWS", queryTemplate: AwsResourceGroupQueryTemplate}, - AzureResourceGroup: {resourceGroupType: "AZURE", queryTemplate: AzureResourceGroupQueryTemplate}, - ContainerResourceGroup: {resourceGroupType: "CONTAINER", queryTemplate: ContainerResourceGroupQueryTemplate}, - GcpResourceGroup: {resourceGroupType: "GCP", queryTemplate: GcpResourceGroupQueryTemplate}, - LwAccountResourceGroup: {resourceGroupType: "LW_ACCOUNT", queryTemplate: LwAccountResourceGroupQueryTemplate}, - MachineResourceGroup: {resourceGroupType: "MACHINE", queryTemplate: MachineResourceGroupQueryTemplate}, - OciResourceGroup: {resourceGroupType: "OCI", queryTemplate: OciResourceGroupQueryTemplate}, -} - -// String returns the string representation of a Resource Group type -func (i resourceGroupType) String() string { - return ResourceGroupTypes[i].resourceGroupType -} - -// QueryTemplate returns the resource group type's query template -func (i resourceGroupType) QueryTemplate() string { - return ResourceGroupTypes[i].queryTemplate + NoneResourceGroup: {resourceGroupType: "None", queryTemplate: NoneResourceGroupQueryTemplate}, + AwsResourceGroup: {resourceGroupType: "AWS", queryTemplate: AwsResourceGroupQueryTemplate}, + AzureResourceGroup: {resourceGroupType: "AZURE", queryTemplate: AzureResourceGroupQueryTemplate}, + ContainerResourceGroup: {resourceGroupType: "CONTAINER", queryTemplate: ContainerResourceGroupQueryTemplate}, + GcpResourceGroup: {resourceGroupType: "GCP", queryTemplate: GcpResourceGroupQueryTemplate}, + MachineResourceGroup: {resourceGroupType: "MACHINE", queryTemplate: MachineResourceGroupQueryTemplate}, + OciResourceGroup: {resourceGroupType: "OCI", queryTemplate: OciResourceGroupQueryTemplate}, + KubernetesResourceGroup: {resourceGroupType: "KUBERNETES", queryTemplate: KubernetesResourceGroupQueryTemplate}, } -// FindResourceGroupType looks up inside the list of available resource group types -// the matching type from the provided string, if none, returns NoneResourceGroup -func FindResourceGroupType(typ string) (resourceGroupType, bool) { - for i, ctx := range ResourceGroupTypes { - if typ == ctx.resourceGroupType { - return i, true - } +func NewResourceGroup(name string, iType resourceGroupType, + description string, query *RGQuery) ResourceGroupData { + return ResourceGroupData{ + Name: name, + Type: iType.String(), + Enabled: 1, + Query: query, + Description: description, } - return NoneResourceGroup, false } -// List returns a list of Resource Groups func (svc *ResourceGroupsService) List() (response ResourceGroupsResponse, err error) { - var rawResponse resourceGroupsWorkaroundResponse + var rawResponse ResourceGroupsResponse err = svc.client.RequestDecoder("GET", apiV2ResourceGroups, nil, &rawResponse) if err != nil { - return - } - response, err = setResourceGroupsResponse(rawResponse) - if err != nil { - return + return rawResponse, err } - return + return rawResponse, nil } -// Create creates a single Resource Group func (svc *ResourceGroupsService) Create(group ResourceGroupData) ( response ResourceGroupResponse, err error, @@ -150,8 +106,7 @@ func (svc *ResourceGroupsService) Create(group ResourceGroupData) ( return } -// Update updates a single ResourceGroup on the Lacework Server -func (svc *ResourceGroupsService) Update(data ResourceGroup) ( +func (svc *ResourceGroupsService) Update(data *ResourceGroupData) ( response ResourceGroupResponse, err error, ) { @@ -170,49 +125,15 @@ func (svc *ResourceGroupsService) Update(data ResourceGroup) ( return } -func castResourceGroupResponse(data resourceGroupWorkaroundData, response interface{}) error { - isDefault, err := strconv.Atoi(data.IsDefault) - if err != nil { - return err - } - group := ResourceGroupResponse{ - Data: ResourceGroupData{ - Guid: data.Guid, - IsDefault: isDefault, - ResourceGuid: data.ResourceGuid, - Name: data.Name, - Type: data.Type, - Enabled: data.Enabled, - Props: data.Props, - }, - } - - j, err := json.Marshal(group) - if err != nil { - return err - } - - err = json.Unmarshal(j, &response) - if err != nil { - return err - } - return nil -} - -func setResourceGroupsResponse(workaround resourceGroupsWorkaroundResponse) (ResourceGroupsResponse, error) { - var data []ResourceGroupData - for _, r := range workaround.Data { - group, err := setResourceGroupResponse(r) - if err != nil { - return ResourceGroupsResponse{}, err - } - data = append(data, group.Data) - } - - return ResourceGroupsResponse{Data: data}, nil +func (group *ResourceGroupData) ResetResourceGUID() { + group.ResourceGroupGuid = "" + group.UpdatedBy = "" + group.UpdatedTime = nil + group.CreatedBy = "" + group.CreatedTime = nil + group.IsDefaultBoolean = nil } -// Delete deletes a Resource Group that matches the provided resource guid func (svc *ResourceGroupsService) Delete(guid string) error { if guid == "" { return errors.New("specify a resourceGuid") @@ -226,22 +147,23 @@ func (svc *ResourceGroupsService) Delete(guid string) error { ) } -// Get returns a raw response of the Resource Group with the matching resource guid. -// -// To return a more specific Go struct of a Resource Group, use the proper -// method such as GetContainerResourceGroup() where the function name is composed by: -// -// Get(guid) -// -// Where is the Resource Group type. func (svc *ResourceGroupsService) Get(guid string, response interface{}) error { - var rawResponse resourceGroupWorkaroundResponse + var rawResponse ResourceGroupResponse err := svc.get(guid, &rawResponse) if err != nil { return err } - return castResourceGroupResponse(rawResponse.Data, &response) + j, err := json.Marshal(rawResponse) + if err != nil { + return err + } + + err = json.Unmarshal(j, &response) + if err != nil { + return err + } + return nil } func (svc *ResourceGroupsService) create(data interface{}, response interface{}) error { @@ -250,7 +172,7 @@ func (svc *ResourceGroupsService) create(data interface{}, response interface{}) func (svc *ResourceGroupsService) get(guid string, response interface{}) error { if guid == "" { - return errors.New("specify an resourceGuid") + return errors.New("specify an resource group guid") } apiPath := fmt.Sprintf(apiV2ResourceGroupsFromGUID, guid) return svc.client.RequestDecoder("GET", apiPath, nil, response) @@ -265,102 +187,76 @@ func (svc *ResourceGroupsService) update(guid string, data interface{}, response return svc.client.RequestEncoderDecoder("PATCH", apiPath, data, response) } -func (group ResourceGroupData) ResourceGroupType() resourceGroupType { - t, _ := FindResourceGroupType(group.Type) - return t +type ResourceGroupsService struct { + client *Client } -func (group ResourceGroupData) ID() string { - if !group.IsV2Group() { - return group.ResourceGuid - } else { - return group.ResourceGroupGuid - } +type RGExpression struct { + Operator string `json:"operator"` + Children []*RGChild `json:"children"` } -func (group *ResourceGroupData) ResetRGV2Fields() { - group.UpdatedBy = "" - group.UpdatedTime = nil - group.CreatedBy = "" - group.CreatedTime = nil - group.IsDefaultBoolean = nil - group.IsOrg = nil +type RGChild struct { + Operator string `json:"operator,omitempty"` + FilterName string `json:"filterName,omitempty"` + Children []*RGChild `json:"children,omitempty"` } -func (group *ResourceGroupData) ResetResourceGUID() { - group.ResourceGuid = "" - group.ResourceGroupGuid = "" - group.ResetRGV2Fields() +type RGFilter struct { + Field string `json:"field"` + Operation string `json:"operation"` + Values []string `json:"values"` + Key string `json:"key,omitempty"` } -func (group ResourceGroupData) Status() string { - if group.Enabled == 1 { - return "Enabled" - } - return "Disabled" +type RGQuery struct { + Filters map[string]*RGFilter `json:"filters"` + Expression *RGExpression `json:"expression"` } -func (group ResourceGroupData) IsV2Group() bool { - return group.Query != nil +// String returns the string representation of a Resource Group type +func (i resourceGroupType) String() string { + return ResourceGroupTypes[i].resourceGroupType } -type ResourceGroupResponse struct { - Data ResourceGroupData `json:"data"` +// QueryTemplate returns the resource group type's query template +func (i resourceGroupType) QueryTemplate() string { + return ResourceGroupTypes[i].queryTemplate } -type ResourceGroupsResponse struct { - Data []ResourceGroupData `json:"data"` +// FindResourceGroupType looks up inside the list of available resource group types +// the matching type from the provided string, if none, returns NoneResourceGroup +func FindResourceGroupType(typ string) (resourceGroupType, bool) { + for i, ctx := range ResourceGroupTypes { + if typ == ctx.resourceGroupType { + return i, true + } + } + return NoneResourceGroup, false } -type ResourceGroupData struct { - // RGv1 Fields - Guid string `json:"guid,omitempty"` - IsDefault int `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName,omitempty"` - Type string `json:"resourceType"` - Enabled int `json:"enabled"` - Props interface{} `json:"props,omitempty"` - - // RG v2 Fields. `Enabled` and `Type` fields are the same in RGv1 nd RGv2 - NameV2 string `json:"name,omitempty"` - Query *RGQuery `json:"query,omitempty"` - Description string `json:"description,omitempty"` - ResourceGroupGuid string `json:"resourceGroupGuid,omitempty"` - CreatedTime *time.Time `json:"lastUpdated,omitempty"` - CreatedBy string `json:"createdBy,omitempty"` - UpdatedTime *time.Time `json:"updatedTime,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty"` - IsDefaultBoolean *bool `json:"isDefaultBoolean,omitempty"` - IsOrg *bool `json:"isOrg,omitempty"` +func (group *ResourceGroupData) ID() string { + return group.ResourceGroupGuid } -// RAIN-21510 workaround -type resourceGroupWorkaroundResponse struct { - Data resourceGroupWorkaroundData `json:"data"` +type ResourceGroupResponse struct { + Data ResourceGroupData `json:"data"` } -type resourceGroupsWorkaroundResponse struct { - Data []resourceGroupWorkaroundData `json:"data"` +type ResourceGroupsResponse struct { + Data []ResourceGroupData `json:"data"` } -type resourceGroupWorkaroundData struct { - Guid string `json:"guid,omitempty"` - IsDefault string `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName"` - Type string `json:"resourceType"` - Enabled int `json:"enabled,omitempty"` - Props interface{} `json:"props"` - - NameV2 string `json:"name,omitempty"` +type ResourceGroupData struct { + Name string `json:"name,omitempty"` Query *RGQuery `json:"query,omitempty"` Description string `json:"description,omitempty"` ResourceGroupGuid string `json:"resourceGroupGuid,omitempty"` - CreatedTime *time.Time `json:"lastUpdated,omitempty"` + CreatedTime *time.Time `json:"createdTime,omitempty"` CreatedBy string `json:"createdBy,omitempty"` UpdatedTime *time.Time `json:"updatedTime,omitempty"` UpdatedBy string `json:"updatedBy,omitempty"` IsDefaultBoolean *bool `json:"isDefaultBoolean,omitempty"` - IsOrg *bool `json:"isOrg,omitempty"` + Type string `json:"resourceType"` + Enabled int `json:"enabled"` } diff --git a/api/resource_groups_aws.go b/api/resource_groups_aws.go deleted file mode 100644 index 96efcfe01..000000000 --- a/api/resource_groups_aws.go +++ /dev/null @@ -1,171 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "encoding/json" - "strconv" - - "github.com/lacework/go-sdk/lwtime" - "github.com/pkg/errors" -) - -// Wildcard values for selecting all aws accounts -var ( - AwsResourceGroupAllAccounts = []string{"*"} -) - -// GetAws gets a single Aws ResourceGroup matching the -// provided resource guid -func (svc *ResourceGroupsVersionService) GetAws(guid string) ( - response AwsResourceGroupResponse, - err error, -) { - var rawResponse resourceGroupWorkaroundResponse - err = svc.get(guid, &rawResponse) - if err != nil { - return - } - - return setAwsResourceGroupResponse(rawResponse) -} - -// UpdateAws updates a single Aws ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) UpdateAws(data ResourceGroup) ( - response AwsResourceGroupResponse, err error) { - - if data == nil { - err = errors.New("resource group must not be empty") - return - } - guid := data.ID() - data.ResetResourceGUID() - - err = svc.update(guid, data, &response) - if err != nil { - return - } - - return -} - -// CreateAws creates a single Aws ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) CreateAws(data ResourceGroup) ( - response AwsResourceGroupResponse, - err error, -) { - err = svc.create(data, &response) - return -} - -func setAwsResourceGroupResponse(response resourceGroupWorkaroundResponse) (aws AwsResourceGroupResponse, err error) { - var props AwsResourceJsonStringGroupProps - - isDefault, err := strconv.Atoi(response.Data.IsDefault) - if err != nil { - return - } - - aws = AwsResourceGroupResponse{ - Data: AwsResourceGroupData{ - Guid: response.Data.Guid, - IsDefault: isDefault, - ResourceGuid: response.Data.ResourceGuid, - Name: response.Data.Name, - Type: response.Data.Type, - Enabled: response.Data.Enabled, - }, - } - - propsString, ok := response.Data.Props.(string) - if !ok { - err = errors.New("unable to cast props field from API response") - return - } - - err = json.Unmarshal([]byte(propsString), &props) - if err != nil { - return - } - aws.Data.Props = AwsResourceGroupProps(props) - return -} - -type AwsResourceGroupResponse struct { - Data AwsResourceGroupData `json:"data"` -} - -type AwsResourceGroupData struct { - Guid string `json:"guid,omitempty"` - IsDefault int `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName"` - Type string `json:"resourceType"` - Enabled int `json:"enabled,omitempty"` - Props AwsResourceGroupProps `json:"props"` - - NameV2 string `json:"name"` - Query *RGQuery `json:"query"` - Description string `json:"description,omitempty"` - ResourceGroupGuid string `json:"resourceGroupGuid,omitempty"` - CreatedTime *lwtime.Epoch `json:"lastUpdated,omitempty"` - CreatedBy string `json:"createdBy,omitempty"` - UpdatedTime *lwtime.Epoch `json:"updatedTime,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty"` - IsDefaultBoolean *bool `json:"isDefaultBoolean,omitempty"` - IsOrg *bool `json:"isOrg,omitempty"` -} - -type AwsResourceGroupProps struct { - Description string `json:"description,omitempty"` - AccountIDs []string `json:"accountIds"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated *lwtime.Epoch `json:"lastUpdated,omitempty"` -} - -// Workaround for props being returned as a json string -type AwsResourceJsonStringGroupProps struct { - Description string `json:"DESCRIPTION,omitempty"` - AccountIDs []string `json:"ACCOUNT_IDS"` - UpdatedBy string `json:"UPDATED_BY,omitempty"` - LastUpdated *lwtime.Epoch `json:"LAST_UPDATED,omitempty"` -} - -func (props AwsResourceGroupProps) GetBaseProps() ResourceGroupPropsBase { - return ResourceGroupPropsBase{ - Description: props.Description, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated, - } -} - -func (props AwsResourceGroupProps) MarshalJSON() ([]byte, error) { - res := struct { - Description string `json:"description,omitempty"` - AccountIDs []string `json:"accountIds"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated string `json:"lastUpdated,omitempty"` - }{ - Description: props.Description, - AccountIDs: props.AccountIDs, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated.String(), - } - return json.Marshal(&res) -} diff --git a/api/resource_groups_aws_test.go b/api/resource_groups_aws_test.go deleted file mode 100644 index fb2ebf4dc..000000000 --- a/api/resource_groups_aws_test.go +++ /dev/null @@ -1,158 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api_test - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/lacework/go-sdk/api" - "github.com/lacework/go-sdk/internal/intgguid" - "github.com/lacework/go-sdk/internal/lacework" -) - -func TestResourceGroupAwsGet(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "GET", r.Method, "GetAwsResourceGroup() should be a GET method") - fmt.Fprintf(w, generateResourceGroupResponse(singleAwsResourceGroup(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - response, err := c.V2.ResourceGroups.GetAws(resourceGUID) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) - assert.Equal(t, "group_name", response.Data.Name) - assert.Equal(t, "All Aws Accounts", response.Data.Props.Description) - assert.Equal(t, []string{"*"}, response.Data.Props.AccountIDs) -} - -func TestResourceGroupsAwsUpdate(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "PATCH", r.Method, "UpdateAwsResourceGroup() should be a PATCH method") - - if assert.NotNil(t, r.Body) { - body := httpBodySniffer(r) - assert.Contains(t, body, "group_name", "Resource Group name is missing") - assert.Contains(t, body, "AWS", "wrong Resource Group type") - assert.Contains(t, body, "Updated", "wrong description") - assert.Contains(t, body, "[\"abc123\",\"cba321\"]", "wrong account ids") - } - - fmt.Fprintf(w, generateResourceGroupResponse(singleAwsResourceGroupUpdateResponse(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - resourceGroup := api.NewResourceGroup("group_name", - api.AwsResourceGroup, - api.AwsResourceGroupProps{ - Description: "Updated", - AccountIDs: []string{"abc123", "cba321"}, - }, - ) - assert.Equal(t, "group_name", resourceGroup.Name, "Aws Resource Group name mismatch") - assert.Equal(t, "AWS", resourceGroup.Type, "a new Aws Resource Group should match its type") - assert.Equal(t, 1, resourceGroup.Enabled, "a new Aws Resource Group should be enabled") - resourceGroup.ResourceGuid = resourceGUID - - response, err := c.V2.ResourceGroups.UpdateAws(&resourceGroup) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) -} - -func TestMarshallResourceGroupLastUpdatedTime(t *testing.T) { - var res api.AwsResourceGroupResponse - err := json.Unmarshal([]byte(generateResourceGroupResponse(singleAwsResourceGroupUpdateResponse("test"))), &res) - if err != nil { - log.Fatal("Unable to unmarshall aws resource group string") - } - jsonString, err := json.Marshal(res) - if err != nil { - log.Fatal("Unable to marshall aws resource group string") - } - - assert.Equal(t, res.Data.Props.LastUpdated.ToTime().UnixNano()/int64(time.Millisecond), int64(1586453993470)) - assert.Contains(t, string(jsonString), "2020-04-09T17:39:53Z") -} - -func singleAwsResourceGroup(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": "1", - "props": "{\"DESCRIPTION\":\"All Aws Accounts\",\"ACCOUNT_IDS\":[\"*\"],\"UPDATED_BY\":null,\"LAST_UPDATED\":1586453993470}", - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} - -func singleAwsResourceGroupUpdateResponse(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": 1, - "props": { - "description":"All Aws Accounts", - "accountIds":["*"], - "updatedBy":null, - "lastUpdated":1586453993470 - }, - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} diff --git a/api/resource_groups_azure.go b/api/resource_groups_azure.go deleted file mode 100644 index b2c293f67..000000000 --- a/api/resource_groups_azure.go +++ /dev/null @@ -1,167 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "encoding/json" - "strconv" - - "github.com/lacework/go-sdk/lwtime" - "github.com/pkg/errors" -) - -// Wildcard values for selecting all azure subscriptions -var ( - AzureResourceGroupAllSubscriptions = []string{"*"} -) - -// GetAzure gets a single Azure ResourceGroup matching the -// provided resource guid -func (svc *ResourceGroupsVersionService) GetAzure(guid string) ( - response AzureResourceGroupResponse, - err error, -) { - var rawResponse resourceGroupWorkaroundResponse - err = svc.get(guid, &rawResponse) - if err != nil { - return - } - - return setAzureResponse(rawResponse) -} - -// UpdateAzure updates a single Azure ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) UpdateAzure(data ResourceGroup) ( - response AzureResourceGroupResponse, - err error, -) { - if data == nil { - err = errors.New("resource group must not be empty") - return - } - guid := data.ID() - data.ResetResourceGUID() - - err = svc.update(guid, data, &response) - if err != nil { - return - } - - return -} - -// CreateAzure creates a single Azure ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) CreateAzure(data ResourceGroup) ( - response AzureResourceGroupResponse, - err error, -) { - err = svc.create(data, &response) - return -} - -func setAzureResponse(response resourceGroupWorkaroundResponse) (az AzureResourceGroupResponse, err error) { - var props AzureResourceJsonStringGroupProps - - isDefault, err := strconv.Atoi(response.Data.IsDefault) - if err != nil { - return - } - - az = AzureResourceGroupResponse{ - Data: AzureResourceGroupData{ - Guid: response.Data.Guid, - IsDefault: isDefault, - ResourceGuid: response.Data.ResourceGuid, - Name: response.Data.Name, - Type: response.Data.Type, - Enabled: response.Data.Enabled, - }, - } - - propsString, ok := response.Data.Props.(string) - if !ok { - err = errors.New("unable to cast props field from API response") - return - } - - err = json.Unmarshal([]byte(propsString), &props) - if err != nil { - return - } - - az.Data.Props = AzureResourceGroupProps(props) - - return -} - -type AzureResourceGroupResponse struct { - Data AzureResourceGroupData `json:"data"` -} - -type AzureResourceGroupData struct { - Guid string `json:"guid,omitempty"` - IsDefault int `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName"` - Type string `json:"resourceType"` - Enabled int `json:"enabled,omitempty"` - Props AzureResourceGroupProps `json:"props"` -} - -type AzureResourceGroupProps struct { - Description string `json:"description,omitempty"` - Tenant string `json:"tenant"` - Subscriptions []string `json:"subscriptions"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated *lwtime.Epoch `json:"lastUpdated,omitempty"` -} - -// Workaround for props being returned as a json string -type AzureResourceJsonStringGroupProps struct { - Description string `json:"DESCRIPTION,omitempty"` - Tenant string `json:"TENANT"` - Subscriptions []string `json:"SUBSCRIPTIONS"` - UpdatedBy string `json:"UPDATED_BY,omitempty"` - LastUpdated *lwtime.Epoch `json:"LAST_UPDATED,omitempty"` -} - -func (props AzureResourceGroupProps) GetBaseProps() ResourceGroupPropsBase { - return ResourceGroupPropsBase{ - Description: props.Description, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated, - } -} - -func (props AzureResourceGroupProps) MarshalJSON() ([]byte, error) { - res := struct { - Description string `json:"description,omitempty"` - Tenant string `json:"tenant"` - Subscriptions []string `json:"subscriptions"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated string `json:"lastUpdated,omitempty"` - }{ - Description: props.Description, - Tenant: props.Tenant, - Subscriptions: props.Subscriptions, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated.String(), - } - return json.Marshal(&res) -} diff --git a/api/resource_groups_azure_test.go b/api/resource_groups_azure_test.go deleted file mode 100644 index 6e620b955..000000000 --- a/api/resource_groups_azure_test.go +++ /dev/null @@ -1,143 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/lacework/go-sdk/api" - "github.com/lacework/go-sdk/internal/intgguid" - "github.com/lacework/go-sdk/internal/lacework" -) - -func TestResourceGroupAzureGet(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "GET", r.Method, "GetAzureResourceGroup() should be a GET method") - fmt.Fprintf(w, generateResourceGroupResponse(singleAzureResourceGroup(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - response, err := c.V2.ResourceGroups.GetAzure(resourceGUID) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) - assert.Equal(t, "group_name", response.Data.Name) - assert.Equal(t, "All Tenants and Subscriptions", response.Data.Props.Description) - assert.Equal(t, []string{"*"}, response.Data.Props.Subscriptions) - assert.Equal(t, "*", response.Data.Props.Tenant) -} - -func TestResourceGroupsAzureUpdate(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "PATCH", r.Method, "UpdateAzureResourceGroup() should be a PATCH method") - - if assert.NotNil(t, r.Body) { - body := httpBodySniffer(r) - assert.Contains(t, body, "group_name", "Resource Group name is missing") - assert.Contains(t, body, "AZURE", "wrong Resource Group type") - assert.Contains(t, body, "Updated", "wrong description") - assert.Contains(t, body, "[\"abc123\",\"cba321\"]", "wrong subscriptions") - } - - fmt.Fprintf(w, generateResourceGroupResponse(singleAzureResourceGroupUpdateResponse(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - resourceGroup := api.NewResourceGroup("group_name", - api.AzureResourceGroup, - api.AzureResourceGroupProps{ - Description: "Updated", - Subscriptions: []string{"abc123", "cba321"}, - Tenant: "tenant", - }, - ) - assert.Equal(t, "group_name", resourceGroup.Name, "Azure Resource Group name mismatch") - assert.Equal(t, "AZURE", resourceGroup.Type, "a new Azure Resource Group should match its type") - assert.Equal(t, 1, resourceGroup.Enabled, "a new Azure Resource Group should be enabled") - resourceGroup.ResourceGuid = resourceGUID - - response, err := c.V2.ResourceGroups.UpdateAzure(&resourceGroup) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) -} - -func singleAzureResourceGroup(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": "1", - "props": "{\"DESCRIPTION\":\"All Tenants and Subscriptions\",\"SUBSCRIPTIONS\":[\"*\"],\"TENANT\":\"*\",\"UPDATED_BY\":null,\"LAST_UPDATED\":1586453993500}", - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AZURE", - "enabled": 1 - } - ` -} - -func singleAzureResourceGroupUpdateResponse(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": 1, - "props": { - "description":"All Tenants and Subscriptions", - "subscriptions":["*"], - "tenant":"*", - "updatedBy":null, - "lastUpdated":1586453993470 - }, - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} diff --git a/api/resource_groups_container.go b/api/resource_groups_container.go deleted file mode 100644 index 197699300..000000000 --- a/api/resource_groups_container.go +++ /dev/null @@ -1,167 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "encoding/json" - "strconv" - - "github.com/lacework/go-sdk/lwtime" - "github.com/pkg/errors" -) - -// Wildcard values for selecting all labels/tags -var ( - ContainerResourceGroupAllLabels = []map[string]string{{"*": "*"}} - ContainerResourceGroupAllTags = []string{"*"} -) - -// GetContainer gets a single Container ResourceGroup matching the -// provided resource guid -func (svc *ResourceGroupsVersionService) GetContainer(guid string) ( - response ContainerResourceGroupResponse, - err error, -) { - var rawResponse resourceGroupWorkaroundResponse - err = svc.get(guid, &rawResponse) - if err != nil { - return - } - - return setContainerResponse(rawResponse) -} - -// UpdateContainer updates a single Container ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) UpdateContainer(data ResourceGroup) ( - response ContainerResourceGroupResponse, - err error, -) { - if data == nil { - err = errors.New("resource group must not be empty") - return - } - guid := data.ID() - data.ResetResourceGUID() - - err = svc.update(guid, data, &response) - return -} - -// CreateContainer creates a single Container ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) CreateContainer(data ResourceGroup) ( - response ContainerResourceGroupResponse, - err error, -) { - err = svc.create(data, &response) - if err != nil { - return - } - - return -} - -func setContainerResponse(response resourceGroupWorkaroundResponse) (ctr ContainerResourceGroupResponse, err error) { - var props ContainerResourceJsonStringGroupProps - - isDefault, err := strconv.Atoi(response.Data.IsDefault) - if err != nil { - return - } - - ctr = ContainerResourceGroupResponse{ - Data: ContainerResourceGroupData{ - Guid: response.Data.Guid, - IsDefault: isDefault, - ResourceGuid: response.Data.ResourceGuid, - Name: response.Data.Name, - Type: response.Data.Type, - Enabled: response.Data.Enabled, - }, - } - - propsString, ok := response.Data.Props.(string) - if !ok { - err = errors.New("unable to cast props field from API response") - return - } - - err = json.Unmarshal([]byte(propsString), &props) - if err != nil { - return - } - - ctr.Data.Props = ContainerResourceGroupProps(props) - return -} - -type ContainerResourceGroupResponse struct { - Data ContainerResourceGroupData `json:"data"` -} - -type ContainerResourceGroupData struct { - Guid string `json:"guid,omitempty"` - IsDefault int `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName"` - Type string `json:"resourceType"` - Enabled int `json:"enabled,omitempty"` - Props ContainerResourceGroupProps `json:"props"` -} - -type ContainerResourceGroupProps struct { - Description string `json:"description,omitempty"` - ContainerLabels []map[string]string `json:"containerLabels"` - ContainerTags []string `json:"containerTags"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated *lwtime.Epoch `json:"lastUpdated,omitempty"` -} - -// Workaround for props being returned as a json string -type ContainerResourceJsonStringGroupProps struct { - Description string `json:"DESCRIPTION,omitempty"` - ContainerLabels []map[string]string `json:"CONTAINER_LABELS"` - ContainerTags []string `json:"CONTAINER_TAGS"` - UpdatedBy string `json:"UPDATED_BY,omitempty"` - LastUpdated *lwtime.Epoch `json:"LAST_UPDATED,omitempty"` -} - -func (props ContainerResourceGroupProps) GetBaseProps() ResourceGroupPropsBase { - return ResourceGroupPropsBase{ - Description: props.Description, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated, - } -} - -func (props ContainerResourceGroupProps) MarshalJSON() ([]byte, error) { - res := struct { - Description string `json:"description,omitempty"` - ContainerLabels []map[string]string `json:"containerLabels"` - ContainerTags []string `json:"containerTags"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated string `json:"lastUpdated,omitempty"` - }{ - Description: props.Description, - ContainerLabels: props.ContainerLabels, - ContainerTags: props.ContainerTags, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated.String(), - } - return json.Marshal(&res) -} diff --git a/api/resource_groups_container_test.go b/api/resource_groups_container_test.go deleted file mode 100644 index df2bf78c7..000000000 --- a/api/resource_groups_container_test.go +++ /dev/null @@ -1,143 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/lacework/go-sdk/api" - "github.com/lacework/go-sdk/internal/intgguid" - "github.com/lacework/go-sdk/internal/lacework" -) - -func TestResourceGroupContainerGet(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "GET", r.Method, "GetContainerResourceGroup() should be a GET method") - fmt.Fprintf(w, generateResourceGroupResponse(singleContainerResourceGroup(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - response, err := c.V2.ResourceGroups.GetContainer(resourceGUID) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) - assert.Equal(t, "group_name", response.Data.Name) - assert.Equal(t, "All Container Labels", response.Data.Props.Description) - assert.Equal(t, []string{"*"}, response.Data.Props.ContainerTags) - assert.Equal(t, []map[string]string{{"*": "*"}}, response.Data.Props.ContainerLabels) -} - -func TestResourceGroupsContainerUpdate(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "PATCH", r.Method, "UpdateContainerResourceGroup() should be a PATCH method") - - if assert.NotNil(t, r.Body) { - body := httpBodySniffer(r) - assert.Contains(t, body, "group_name", "Resource Group name is missing") - assert.Contains(t, body, "CONTAINER", "wrong Resource Group type") - assert.Contains(t, body, "Updated", "wrong description") - assert.Contains(t, body, "[\"abc123\",\"cba321\"]", "wrong container tags ids") - } - - fmt.Fprintf(w, generateResourceGroupResponse(singleContainerResourceGroupUpdateResponse(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - resourceGroup := api.NewResourceGroup("group_name", - api.ContainerResourceGroup, - api.ContainerResourceGroupProps{ - Description: "Updated", - ContainerTags: []string{"abc123", "cba321"}, - ContainerLabels: []map[string]string{{"label1": "testlabel"}}, - }, - ) - assert.Equal(t, "group_name", resourceGroup.Name, "Container Resource Group name mismatch") - assert.Equal(t, "CONTAINER", resourceGroup.Type, "a new Container Resource Group should match its type") - assert.Equal(t, 1, resourceGroup.Enabled, "a new Container Resource Group should be enabled") - resourceGroup.ResourceGuid = resourceGUID - - response, err := c.V2.ResourceGroups.UpdateContainer(&resourceGroup) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) -} - -func singleContainerResourceGroup(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": "1", - "props": "{\"DESCRIPTION\":\"All Container Labels\",\"CONTAINER_LABELS\":[{\"*\":\"*\"}],\"CONTAINER_TAGS\":[\"*\"],\"UPDATED_BY\":null,\"LAST_UPDATED\":1586453993595}", - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "CONTAINER", - "enabled": 1 - } - ` -} - -func singleContainerResourceGroupUpdateResponse(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": 1, - "props": { - "description":"All Container Labels", - "containerLabels":[{"*":"*"}], - "containerTags":["*"], - "updatedBy":null, - "lastUpdated":1586453993470 - }, - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} diff --git a/api/resource_groups_gcp.go b/api/resource_groups_gcp.go deleted file mode 100644 index 72f27dcae..000000000 --- a/api/resource_groups_gcp.go +++ /dev/null @@ -1,165 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "encoding/json" - "strconv" - - "github.com/lacework/go-sdk/lwtime" - "github.com/pkg/errors" -) - -// Wildcard values for selecting all gcp projects -var ( - GcpResourceGroupAllProjects = []string{"*"} -) - -// GetGcp gets a single Gcp ResourceGroup matching the -// provided resource guid -func (svc *ResourceGroupsVersionService) GetGcp(guid string) ( - response GcpResourceGroupResponse, - err error, -) { - var rawResponse resourceGroupWorkaroundResponse - err = svc.get(guid, &rawResponse) - if err != nil { - return - } - - return setGcpResponse(rawResponse) -} - -// UpdateGcp updates a single Gcp ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) UpdateGcp(data ResourceGroup) ( - response GcpResourceGroupResponse, - err error, -) { - if data == nil { - err = errors.New("resource group must not be empty") - return - } - guid := data.ID() - data.ResetResourceGUID() - - err = svc.update(guid, data, &response) - return -} - -// CreateGcp creates a single Gcp ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) CreateGcp(data ResourceGroup) ( - response GcpResourceGroupResponse, - err error, -) { - err = svc.create(data, &response) - if err != nil { - return - } - - return -} - -func setGcpResponse(response resourceGroupWorkaroundResponse) (gcp GcpResourceGroupResponse, err error) { - var props GcpResourceGroupJsonStringProps - - isDefault, err := strconv.Atoi(response.Data.IsDefault) - if err != nil { - return - } - - gcp = GcpResourceGroupResponse{ - Data: GcpResourceGroupData{ - Guid: response.Data.Guid, - IsDefault: isDefault, - ResourceGuid: response.Data.ResourceGuid, - Name: response.Data.Name, - Type: response.Data.Type, - Enabled: response.Data.Enabled, - }, - } - - propsString, ok := response.Data.Props.(string) - if !ok { - err = errors.New("unable to cast props field from API response") - return - } - - err = json.Unmarshal([]byte(propsString), &props) - if err != nil { - return - } - gcp.Data.Props = GcpResourceGroupProps(props) - return -} - -type GcpResourceGroupResponse struct { - Data GcpResourceGroupData `json:"data"` -} - -type GcpResourceGroupData struct { - Guid string `json:"guid,omitempty"` - IsDefault int `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName"` - Type string `json:"resourceType"` - Enabled int `json:"enabled,omitempty"` - Props GcpResourceGroupProps `json:"props"` -} - -type GcpResourceGroupProps struct { - Description string `json:"description,omitempty"` - Organization string `json:"organization"` - Projects []string `json:"projects"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated *lwtime.Epoch `json:"lastUpdated,omitempty"` -} - -// Workaround for props being returned as a json string -type GcpResourceGroupJsonStringProps struct { - Description string `json:"DESCRIPTION,omitempty"` - Organization string `json:"ORGANIZATION"` - Projects []string `json:"PROJECTS"` - UpdatedBy string `json:"UPDATED_BY,omitempty"` - LastUpdated *lwtime.Epoch `json:"LAST_UPDATED,omitempty"` -} - -func (props GcpResourceGroupProps) GetBaseProps() ResourceGroupPropsBase { - return ResourceGroupPropsBase{ - Description: props.Description, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated, - } -} - -func (props GcpResourceGroupProps) MarshalJSON() ([]byte, error) { - res := struct { - Description string `json:"description,omitempty"` - Organization string `json:"organization"` - Projects []string `json:"projects"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated string `json:"lastUpdated,omitempty"` - }{ - Description: props.Description, - Organization: props.Organization, - Projects: props.Projects, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated.String(), - } - return json.Marshal(&res) -} diff --git a/api/resource_groups_gcp_test.go b/api/resource_groups_gcp_test.go deleted file mode 100644 index bc9ad9fa3..000000000 --- a/api/resource_groups_gcp_test.go +++ /dev/null @@ -1,143 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/lacework/go-sdk/api" - "github.com/lacework/go-sdk/internal/intgguid" - "github.com/lacework/go-sdk/internal/lacework" -) - -func TestResourceGroupGcpGet(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "GET", r.Method, "GetGcpResourceGroup() should be a GET method") - fmt.Fprintf(w, generateResourceGroupResponse(singleGcpResourceGroup(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - response, err := c.V2.ResourceGroups.GetGcp(resourceGUID) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) - assert.Equal(t, "group_name", response.Data.Name) - assert.Equal(t, "All Organizations and Projects", response.Data.Props.Description) - assert.Equal(t, []string{"*"}, response.Data.Props.Projects) - assert.Equal(t, "*", response.Data.Props.Organization) -} - -func TestResourceGroupsGcpUpdate(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "PATCH", r.Method, "UpdateGcpResourceGroup() should be a PATCH method") - - if assert.NotNil(t, r.Body) { - body := httpBodySniffer(r) - assert.Contains(t, body, "group_name", "Resource Group name is missing") - assert.Contains(t, body, "GCP", "wrong Resource Group type") - assert.Contains(t, body, "Updated", "wrong description") - assert.Contains(t, body, "[\"abc123\",\"cba321\"]", "wrong project ids") - } - - fmt.Fprintf(w, generateResourceGroupResponse(singleGcpResourceGroupUpdateResponse(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - resourceGroup := api.NewResourceGroup("group_name", - api.GcpResourceGroup, - api.GcpResourceGroupProps{ - Description: "Updated", - Projects: []string{"abc123", "cba321"}, - Organization: "ORG123", - }, - ) - assert.Equal(t, "group_name", resourceGroup.Name, "Gcp Resource Group name mismatch") - assert.Equal(t, "GCP", resourceGroup.Type, "a new Gcp Resource Group should match its type") - assert.Equal(t, 1, resourceGroup.Enabled, "a new Gcp Resource Group should be enabled") - resourceGroup.ResourceGuid = resourceGUID - - response, err := c.V2.ResourceGroups.UpdateGcp(&resourceGroup) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) -} - -func singleGcpResourceGroup(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": "1", - "props": "{\"DESCRIPTION\":\"All Organizations and Projects\",\"PROJECTS\":[\"*\"],\"ORGANIZATION\":\"*\",\"UPDATED_BY\":null,\"LAST_UPDATED\":1586453993529}", - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} - -func singleGcpResourceGroupUpdateResponse(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": 1, - "props": { - "description":"All Organizations and Projects", - "organization": "*", - "projects":["*"], - "updatedBy":null, - "lastUpdated":1586453993470 - }, - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} diff --git a/api/resource_groups_lw_account.go b/api/resource_groups_lw_account.go deleted file mode 100644 index 5a4ee9912..000000000 --- a/api/resource_groups_lw_account.go +++ /dev/null @@ -1,161 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "encoding/json" - "strconv" - - "github.com/lacework/go-sdk/lwtime" - "github.com/pkg/errors" -) - -// Wildcard values for selecting all lacework accounts -var ( - LwAccountResourceGroupAllAccounts = []string{"*"} -) - -// GetContainer gets a single LwAccount ResourceGroup matching the -// provided resource guid -func (svc *ResourceGroupsVersionService) GetLwAccount(guid string) ( - response LwAccountResourceGroupResponse, - err error, -) { - var rawResponse resourceGroupWorkaroundResponse - err = svc.get(guid, &rawResponse) - if err != nil { - return - } - - return setLwAccountResponse(rawResponse) -} - -// UpdateLwAccount updates a single LwAccount ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) UpdateLwAccount(data ResourceGroup) ( - response LwAccountResourceGroupResponse, - err error, -) { - if data == nil { - err = errors.New("resource group must not be empty") - return - } - guid := data.ID() - data.ResetResourceGUID() - - err = svc.update(guid, data, &response) - if err != nil { - return - } - - return -} - -// CreateLwAccount creates a single LwAccount ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) CreateLwAccount(data ResourceGroup) ( - response LwAccountResourceGroupResponse, - err error, -) { - err = svc.create(data, &response) - return -} - -func setLwAccountResponse(response resourceGroupWorkaroundResponse) (lw LwAccountResourceGroupResponse, err error) { - var props LwAccountResourceGroupJsonStringProps - - isDefault, err := strconv.Atoi(response.Data.IsDefault) - if err != nil { - return - } - - lw = LwAccountResourceGroupResponse{ - Data: LwAccountResourceGroupData{ - Guid: response.Data.Guid, - IsDefault: isDefault, - ResourceGuid: response.Data.ResourceGuid, - Name: response.Data.Name, - Type: response.Data.Type, - Enabled: response.Data.Enabled, - }, - } - - propsString, ok := response.Data.Props.(string) - if !ok { - err = errors.New("unable to cast props field from API response") - return - } - - err = json.Unmarshal([]byte(propsString), &props) - if err != nil { - return - } - lw.Data.Props = LwAccountResourceGroupProps(props) - return -} - -type LwAccountResourceGroupResponse struct { - Data LwAccountResourceGroupData `json:"data"` -} - -type LwAccountResourceGroupData struct { - Guid string `json:"guid,omitempty"` - IsDefault int `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName"` - Type string `json:"resourceType"` - Enabled int `json:"enabled,omitempty"` - Props LwAccountResourceGroupProps `json:"props"` -} - -type LwAccountResourceGroupProps struct { - Description string `json:"description,omitempty"` - LwAccounts []string `json:"lwAccounts"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated *lwtime.Epoch `json:"lastUpdated,omitempty"` -} - -// Workaround for props being returned as a json string -type LwAccountResourceGroupJsonStringProps struct { - Description string `json:"DESCRIPTION,omitempty"` - LwAccounts []string `json:"LW_ACCOUNTS"` - UpdatedBy string `json:"UPDATED_BY,omitempty"` - LastUpdated *lwtime.Epoch `json:"LAST_UPDATED,omitempty"` -} - -func (props LwAccountResourceGroupProps) GetBaseProps() ResourceGroupPropsBase { - return ResourceGroupPropsBase{ - Description: props.Description, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated, - } -} - -func (props LwAccountResourceGroupProps) MarshalJSON() ([]byte, error) { - res := struct { - Description string `json:"description,omitempty"` - LwAccounts []string `json:"lwAccounts"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated string `json:"lastUpdated,omitempty"` - }{ - Description: props.Description, - LwAccounts: props.LwAccounts, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated.String(), - } - return json.Marshal(&res) -} diff --git a/api/resource_groups_lw_account_test.go b/api/resource_groups_lw_account_test.go deleted file mode 100644 index bd7a4aa1a..000000000 --- a/api/resource_groups_lw_account_test.go +++ /dev/null @@ -1,140 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/lacework/go-sdk/api" - "github.com/lacework/go-sdk/internal/intgguid" - "github.com/lacework/go-sdk/internal/lacework" -) - -func TestResourceGroupLwAccountGet(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "GET", r.Method, "GetLwAccountResourceGroup() should be a GET method") - fmt.Fprintf(w, generateResourceGroupResponse(singleLwAccountResourceGroup(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - response, err := c.V2.ResourceGroups.GetLwAccount(resourceGUID) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) - assert.Equal(t, "group_name", response.Data.Name) - assert.Equal(t, "All Lacework Accounts", response.Data.Props.Description) - assert.Equal(t, []string{"*"}, response.Data.Props.LwAccounts) -} - -func TestResourceGroupsLwAccountUpdate(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "PATCH", r.Method, "UpdateLwAccountResourceGroup() should be a PATCH method") - - if assert.NotNil(t, r.Body) { - body := httpBodySniffer(r) - assert.Contains(t, body, "group_name", "Resource Group name is missing") - assert.Contains(t, body, "LW_ACCOUNT", "wrong Resource Group type") - assert.Contains(t, body, "Updated", "wrong description") - assert.Contains(t, body, "[\"abc123\",\"cba321\"]", "wrong lw accounts ids") - } - - fmt.Fprintf(w, generateResourceGroupResponse(singleLwAccountResourceGroupUpdateResponse(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - resourceGroup := api.NewResourceGroup("group_name", - api.LwAccountResourceGroup, - api.LwAccountResourceGroupProps{ - Description: "Updated", - LwAccounts: []string{"abc123", "cba321"}, - }, - ) - assert.Equal(t, "group_name", resourceGroup.Name, "LwAccount Resource Group name mismatch") - assert.Equal(t, "LW_ACCOUNT", resourceGroup.Type, "a new LwAccount Resource Group should match its type") - assert.Equal(t, 1, resourceGroup.Enabled, "a new LwAccount Resource Group should be enabled") - resourceGroup.ResourceGuid = resourceGUID - - response, err := c.V2.ResourceGroups.UpdateLwAccount(&resourceGroup) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) -} - -func singleLwAccountResourceGroup(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": "1", - "props": "{\"DESCRIPTION\":\"All Lacework Accounts\",\"LW_ACCOUNTS\":[\"*\"],\"UPDATED_BY\":null,\"LAST_UPDATED\":1582066544260}", - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "lW_ACCOUNT", - "enabled": 1 - } - ` -} - -func singleLwAccountResourceGroupUpdateResponse(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": 1, - "props": { - "description":"All Lacework Accounts", - "lwAccounts":["*"], - "updatedBy":null, - "lastUpdated":1586453993470 - }, - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} diff --git a/api/resource_groups_machine.go b/api/resource_groups_machine.go deleted file mode 100644 index f00ac47c7..000000000 --- a/api/resource_groups_machine.go +++ /dev/null @@ -1,163 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "encoding/json" - "strconv" - - "github.com/lacework/go-sdk/lwtime" - "github.com/pkg/errors" -) - -// Wildcard values for selecting all machine tags -var ( - MachineResourceGroupAllTags = []map[string]string{{"*": "*"}} -) - -// GetMachine gets a single Machine ResourceGroup matching the -// provided resource guid -func (svc *ResourceGroupsVersionService) GetMachine(guid string) ( - response MachineResourceGroupResponse, - err error, -) { - var rawResponse resourceGroupWorkaroundResponse - err = svc.get(guid, &rawResponse) - if err != nil { - return - } - - return setMachineAccountResponse(rawResponse) -} - -// UpdateMachine updates a single Machine ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) UpdateMachine(data ResourceGroup) ( - response MachineResourceGroupResponse, - err error, -) { - if data == nil { - err = errors.New("resource group must not be empty") - return - } - guid := data.ID() - data.ResetResourceGUID() - - err = svc.update(guid, data, &response) - if err != nil { - return - } - - return -} - -// CreateMachine creates a single Machine ResourceGroup on the Lacework Server -func (svc *ResourceGroupsVersionService) CreateMachine(data ResourceGroup) ( - response MachineResourceGroupResponse, - err error, -) { - err = svc.create(data, &response) - return -} - -func setMachineAccountResponse(response resourceGroupWorkaroundResponse) ( - machine MachineResourceGroupResponse, err error, -) { - var props MachineResourceGroupJsonStringProps - - isDefault, err := strconv.Atoi(response.Data.IsDefault) - if err != nil { - return - } - - machine = MachineResourceGroupResponse{ - Data: MachineResourceGroupData{ - Guid: response.Data.Guid, - IsDefault: isDefault, - ResourceGuid: response.Data.ResourceGuid, - Name: response.Data.Name, - Type: response.Data.Type, - Enabled: response.Data.Enabled, - }, - } - - propsString, ok := response.Data.Props.(string) - if !ok { - err = errors.New("unable to cast props field from API response") - return - } - - err = json.Unmarshal([]byte(propsString), &props) - if err != nil { - return - } - machine.Data.Props = MachineResourceGroupProps(props) - return -} - -type MachineResourceGroupResponse struct { - Data MachineResourceGroupData `json:"data"` -} - -type MachineResourceGroupData struct { - Guid string `json:"guid,omitempty"` - IsDefault int `json:"isDefault,omitempty"` - ResourceGuid string `json:"resourceGuid,omitempty"` - Name string `json:"resourceName"` - Type string `json:"resourceType"` - Enabled int `json:"enabled,omitempty"` - Props MachineResourceGroupProps `json:"props"` -} - -type MachineResourceGroupProps struct { - Description string `json:"description,omitempty"` - MachineTags []map[string]string `json:"machineTags"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated *lwtime.Epoch `json:"lastUpdated,omitempty"` -} - -// Workaround for props being returned as a json string -type MachineResourceGroupJsonStringProps struct { - Description string `json:"DESCRIPTION,omitempty"` - MachineTags []map[string]string `json:"MACHINE_TAGS"` - UpdatedBy string `json:"UPDATED_BY,omitempty"` - LastUpdated *lwtime.Epoch `json:"LAST_UPDATED,omitempty"` -} - -func (props MachineResourceGroupProps) GetBaseProps() ResourceGroupPropsBase { - return ResourceGroupPropsBase{ - Description: props.Description, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated, - } -} - -func (props MachineResourceGroupProps) MarshalJSON() ([]byte, error) { - res := struct { - Description string `json:"description,omitempty"` - MachineTags []map[string]string `json:"machineTags"` - UpdatedBy string `json:"updatedBy,omitempty"` - LastUpdated string `json:"lastUpdated,omitempty"` - }{ - Description: props.Description, - MachineTags: props.MachineTags, - UpdatedBy: props.UpdatedBy, - LastUpdated: props.LastUpdated.String(), - } - return json.Marshal(&res) -} diff --git a/api/resource_groups_machine_test.go b/api/resource_groups_machine_test.go deleted file mode 100644 index 76371c2ec..000000000 --- a/api/resource_groups_machine_test.go +++ /dev/null @@ -1,140 +0,0 @@ -// -// Author:: Darren Murray () -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/lacework/go-sdk/api" - "github.com/lacework/go-sdk/internal/intgguid" - "github.com/lacework/go-sdk/internal/lacework" -) - -func TestResourceGroupMachineGet(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "GET", r.Method, "GetMachineResourceGroup() should be a GET method") - fmt.Fprintf(w, generateResourceGroupResponse(singleMachineResourceGroup(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - response, err := c.V2.ResourceGroups.GetMachine(resourceGUID) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) - assert.Equal(t, "group_name", response.Data.Name) - assert.Equal(t, "All Machine Tags", response.Data.Props.Description) - assert.Equal(t, []map[string]string{{"*": "*"}}, response.Data.Props.MachineTags) -} - -func TestResourceGroupsMachineUpdate(t *testing.T) { - var ( - resourceGUID = intgguid.New() - apiPath = fmt.Sprintf("ResourceGroups/%s", resourceGUID) - fakeServer = lacework.MockServer() - ) - fakeServer.MockToken("TOKEN") - defer fakeServer.Close() - - fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "PATCH", r.Method, "UpdateMachineResourceGroup() should be a PATCH method") - - if assert.NotNil(t, r.Body) { - body := httpBodySniffer(r) - assert.Contains(t, body, "group_name", "Resource Group name is missing") - assert.Contains(t, body, "MACHINE", "wrong Resource Group type") - assert.Contains(t, body, "Updated", "wrong description") - assert.Contains(t, body, "[{\"tag\":\"machineTag\"}]", "wrong machine tags") - } - - fmt.Fprintf(w, generateResourceGroupResponse(singleMachineResourceGroupUpdateResponse(resourceGUID))) - }) - - c, err := api.NewClient("test", - api.WithToken("TOKEN"), - api.WithURL(fakeServer.URL()), - ) - assert.Nil(t, err) - - resourceGroup := api.NewResourceGroup("group_name", - api.MachineResourceGroup, - api.MachineResourceGroupProps{ - Description: "Updated", - MachineTags: []map[string]string{{"tag": "machineTag"}}, - }, - ) - assert.Equal(t, "group_name", resourceGroup.Name, "Machine Resource Group name mismatch") - assert.Equal(t, "MACHINE", resourceGroup.Type, "a new Machine Resource Group should match its type") - assert.Equal(t, 1, resourceGroup.Enabled, "a new Machine Resource Group should be enabled") - resourceGroup.ResourceGuid = resourceGUID - - response, err := c.V2.ResourceGroups.UpdateMachine(&resourceGroup) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) -} - -func singleMachineResourceGroup(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": "1", - "props": "{\"DESCRIPTION\":\"All Machine Tags\",\"MACHINE_TAGS\":[{\"*\":\"*\"}],\"UPDATED_BY\":null,\"LAST_UPDATED\":1586453993565}", - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "MACHINE", - "enabled": 1 - } - ` -} - -func singleMachineResourceGroupUpdateResponse(id string) string { - return ` - { - "guid": "` + id + `", - "isDefault": 1, - "props": { - "description":"All Machine Tags", - "machineTags":[{"*":"*"}], - "updatedBy":null, - "lastUpdated":1586453993470 - }, - "resourceGuid": "` + id + `", - "resourceName": "group_name", - "resourceType": "AWS", - "enabled": 1 - } - ` -} diff --git a/api/resource_groups_test.go b/api/resource_groups_test.go index ee8f86410..8b38dbee5 100644 --- a/api/resource_groups_test.go +++ b/api/resource_groups_test.go @@ -38,7 +38,8 @@ func TestResourceGroupTypes(t *testing.T) { assert.Equal(t, "CONTAINER", api.ContainerResourceGroup.String(), "wrong resource group type") assert.Equal(t, "GCP", api.GcpResourceGroup.String(), "wrong resource group type") assert.Equal(t, "MACHINE", api.MachineResourceGroup.String(), "wrong resource group type") - assert.Equal(t, "LW_ACCOUNT", api.LwAccountResourceGroup.String(), "wrong resource group type") + assert.Equal(t, "OCI", api.OciResourceGroup.String(), "wrong resource group type") + assert.Equal(t, "KUBERNETES", api.KubernetesResourceGroup.String(), "wrong resource group type") } func TestFindResourceGroupType(t *testing.T) { @@ -51,25 +52,29 @@ func TestFindResourceGroupType(t *testing.T) { assert.True(t, found, "resource group type should exist") assert.Equal(t, "AWS", groupFound.String(), "wrong resource group type") - groupFound, found = api.FindResourceGroupType("AWS") + groupFound, found = api.FindResourceGroupType("GCP") assert.True(t, found, "resource group type should exist") - assert.Equal(t, "AWS", groupFound.String(), "wrong resource group type") + assert.Equal(t, "GCP", groupFound.String(), "wrong resource group type") - groupFound, found = api.FindResourceGroupType("CONTAINER") + groupFound, found = api.FindResourceGroupType("AZURE") assert.True(t, found, "resource group type should exist") - assert.Equal(t, "CONTAINER", groupFound.String(), "wrong resource group type") + assert.Equal(t, "AZURE", groupFound.String(), "wrong resource group type") - groupFound, found = api.FindResourceGroupType("GCP") + groupFound, found = api.FindResourceGroupType("CONTAINER") assert.True(t, found, "resource group type should exist") - assert.Equal(t, "GCP", groupFound.String(), "wrong resource group type") + assert.Equal(t, "CONTAINER", groupFound.String(), "wrong resource group type") groupFound, found = api.FindResourceGroupType("MACHINE") assert.True(t, found, "resource group type should exist") assert.Equal(t, "MACHINE", groupFound.String(), "wrong resource group type") - groupFound, found = api.FindResourceGroupType("LW_ACCOUNT") + groupFound, found = api.FindResourceGroupType("OCI") assert.True(t, found, "resource group type should exist") - assert.Equal(t, "LW_ACCOUNT", groupFound.String(), "wrong resource group type") + assert.Equal(t, "OCI", groupFound.String(), "wrong resource group type") + + groupFound, found = api.FindResourceGroupType("KUBERNETES") + assert.True(t, found, "resource group type should exist") + assert.Equal(t, "KUBERNETES", groupFound.String(), "wrong resource group type") } func TestResourceGroupGet(t *testing.T) { @@ -110,7 +115,7 @@ func TestResourceGroupGet(t *testing.T) { err := c.V2.ResourceGroups.Get(resourceGUID, &response) assert.Nil(t, err) if assert.NotNil(t, response) { - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) + assert.Equal(t, resourceGUID, response.Data.ResourceGroupGuid) assert.Equal(t, "group_name", response.Data.Name) assert.Equal(t, "VANILLA", response.Data.Type) } @@ -173,7 +178,7 @@ func TestResourceGroupsDelete(t *testing.T) { err := c.V2.ResourceGroups.Get(resourceGUID, &response) assert.Nil(t, err) if assert.NotNil(t, response) { - assert.Equal(t, resourceGUID, response.Data.ResourceGuid) + assert.Equal(t, resourceGUID, response.Data.ResourceGroupGuid) assert.Equal(t, "group_name", response.Data.Name) assert.Equal(t, "VANILLA", response.Data.Type) } @@ -195,14 +200,17 @@ func TestResourceGroupsDelete(t *testing.T) { func TestResourceGroupsList(t *testing.T) { var ( - awsResourceGUIDs = []string{intgguid.New(), intgguid.New()} - azureResourceGUIDs = []string{intgguid.New(), intgguid.New()} - containerResourceGUIDs = []string{intgguid.New()} - gcpResourceGUIDs = []string{intgguid.New()} - machineResourceGUIDs = []string{intgguid.New()} - allGroups = [][]string{awsResourceGUIDs, azureResourceGUIDs, containerResourceGUIDs, gcpResourceGUIDs, machineResourceGUIDs} - allGuids []string - fakeServer = lacework.MockServer() + awsResourceGUIDs = []string{intgguid.New(), intgguid.New()} + azureResourceGUIDs = []string{intgguid.New(), intgguid.New()} + containerResourceGUIDs = []string{intgguid.New()} + gcpResourceGUIDs = []string{intgguid.New()} + machineResourceGUIDs = []string{intgguid.New()} + ociResourceGUIDs = []string{intgguid.New()} + kubernetesResourceGUIDs = []string{intgguid.New()} + allGroups = [][]string{awsResourceGUIDs, azureResourceGUIDs, containerResourceGUIDs, + gcpResourceGUIDs, machineResourceGUIDs, ociResourceGUIDs, kubernetesResourceGUIDs} + allGuids []string + fakeServer = lacework.MockServer() ) for _, guids := range allGroups { @@ -220,6 +228,8 @@ func TestResourceGroupsList(t *testing.T) { generateResourceGroups(containerResourceGUIDs, "CONTAINER"), generateResourceGroups(gcpResourceGUIDs, "GCP"), generateResourceGroups(machineResourceGUIDs, "MACHINE"), + generateResourceGroups(ociResourceGUIDs, "OCI"), + generateResourceGroups(kubernetesResourceGUIDs, "KUBERNETES"), } fmt.Fprintf(w, generateResourceGroupsResponse( @@ -241,7 +251,7 @@ func TestResourceGroupsList(t *testing.T) { assert.NotNil(t, response) assert.Equal(t, expectedLen, len(response.Data)) for _, d := range response.Data { - assert.Contains(t, allGuids, d.ResourceGuid) + assert.Contains(t, allGuids, d.ResourceGroupGuid) } } @@ -257,15 +267,473 @@ func generateResourceGroups(guids []string, iType string) string { resourceGroups[i] = singleContainerResourceGroup(guid) case api.GcpResourceGroup.String(): resourceGroups[i] = singleGcpResourceGroup(guid) - case api.LwAccountResourceGroup.String(): - resourceGroups[i] = singleLwAccountResourceGroup(guid) case api.MachineResourceGroup.String(): resourceGroups[i] = singleMachineResourceGroup(guid) + case api.OciResourceGroup.String(): + resourceGroups[i] = singleOciResourceGroup(guid) + case api.KubernetesResourceGroup.String(): + resourceGroups[i] = singleKubernetesResourceGroup(guid) + } } return strings.Join(resourceGroups, ", ") } +func singleAwsResourceGroup(id string) string { + return ` + { + "guid": "` + id + `", + "description": "All Aws Resources", + "isDefaultBoolean": true, + "resourceGroupGuid": "` + id + `", + "resourceName": "group_name", + "resourceType": "AWS", + "enabled": 1, + "query": { + "filters": { + "filter1": { + "field": "Account", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter2": { + "field": "Organization ID", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter3": { + "field": "Resource Tag", + "operation": "EQUALS", + "key": "*", + "values": [ + "*" + ] + }, + "filter4": { + "field": "Region", + "operation": "EQUALS", + "values": [ + "*" + ] + } + }, + "expression": { + "operator": "OR", + "children": [ + { + "filterName": "filter1" + }, + { + "filterName": "filter2" + }, + { + "filterName": "filter3" + }, + { + "filterName": "filter4" + } + ] + } + } + } + ` +} + +func singleAzureResourceGroup(id string) string { + + return ` + { + "guid": "` + id + `", + "description": "All Azure Resources", + "isDefaultBoolean": true, + "resourceGroupGuid": "` + id + `", + "resourceName": "group_name", + "resourceType": "AZURE", + "enabled": 1, + "query": { + "filters": { + "filter1": { + "field": "Tenant ID", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter2": { + "field": "Subscription ID", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter3": { + "field": "Resource Tag", + "operation": "EQUALS", + "key": "*", + "values": [ + "*" + ] + }, + "filter4": { + "field": "Region", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter5": { + "field": "Tenant Name", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter6": { + "field": "Subscription Name", + "operation": "EQUALS", + "values": [ + "*" + ] + } + }, + "expression": { + "operator": "OR", + "children": [ + { + "filterName": "filter1" + }, + { + "filterName": "filter2" + }, + { + "filterName": "filter3" + }, + { + "filterName": "filter4" + }, + { + "filterName": "filter5" + }, + { + "filterName": "filter6" + } + ] + } + } + } + ` +} + +func singleContainerResourceGroup(id string) string { + return ` + { + "guid": "` + id + `", + "description": "All Container Resources", + "isDefaultBoolean": true, + "resourceGroupGuid": "` + id + `", + "resourceName": "group_name", + "resourceType": "CONTAINER", + "enabled": 1, + "query": { + "filters": { + "filter1": { + "field": "Container Tag", + "operation": "EQUALS", + "values": [ + "*" + ], + "key": "*" + }, + "filter2": { + "field": "Container Label", + "operation": "EQUALS", + "values": [ + "*" + ], + "key": "*" + }, + "filter3": { + "field": "Image Repo", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter4": { + "field": "Image Registry", + "operation": "EQUALS", + "values": [ + "*" + ] + } + }, + "expression": { + "operator": "OR", + "children": [ + { + "filterName": "filter1" + }, + { + "filterName": "filter2" + }, + { + "filterName": "filter3" + }, + { + "filterName": "filter4" + } + ] + } + } + } + ` +} + +func singleGcpResourceGroup(id string) string { + return ` + { + "guid": "` + id + `", + "description": "All GCP Resources", + "isDefaultBoolean": true, + "resourceGroupGuid": "` + id + `", + "resourceName": "group_name", + "resourceType": "GCP", + "enabled": 1, + "query": { + "filters": { + "filter1": { + "field": "Organization ID", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter2": { + "field": "Folder", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter3": { + "field": "Project ID", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter4": { + "field": "Resource Label", + "operation": "EQUALS", + "key": "*", + "values": [ + "*" + ] + }, + "filter5": { + "field": "Region", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter6": { + "field": "Organization Name", + "operation": "EQUALS", + "values": [ + "*" + ] + } + }, + "expression": { + "operator": "OR", + "children": [ + { + "filterName": "filter1" + }, + { + "filterName": "filter2" + }, + { + "filterName": "filter3" + }, + { + "filterName": "filter4" + }, + { + "filterName": "filter5" + }, + { + "filterName": "filter5" + } + ] + } + } + } + ` +} + +func singleMachineResourceGroup(id string) string { + return ` + { + "guid": "` + id + `", + "description": "All Machine Resources", + "isDefaultBoolean": true, + "resourceGroupGuid": "` + id + `", + "resourceName": "group_name", + "resourceType": "MACHINE", + "enabled": 1, + "query": { + "filters": { + "filter1": { + "field": "Machine Tag", + "operation": "EQUALS", + "values": [ + "*" + ], + "key": "*" + } + }, + "expression": { + "filterName": "filter1" + } + } + } + ` +} + +func singleOciResourceGroup(id string) string { + return ` + { + "guid": "` + id + `", + "description": "All OCI Resources", + "isDefaultBoolean": true, + "resourceGroupGuid": "` + id + `", + "resourceName": "group_name", + "resourceType": "OCI", + "enabled": 1, + "query": { + "filters": { + "filter1": { + "field": "Compartment ID", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter2": { + "field": "Compartment Name", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter3": { + "field": "Resource Tag", + "operation": "EQUALS", + "key": "*", + "values": [ + "*" + ] + }, + "filter4": { + "field": "Region", + "operation": "EQUALS", + "values": [ + "*" + ] + } + }, + "expression": { + "operator": "OR", + "children": [ + { + "filterName": "filter1" + }, + { + "filterName": "filter2" + }, + { + "filterName": "filter3" + }, + { + "filterName": "filter4" + } + ] + } + } + } + ` +} + +func singleKubernetesResourceGroup(id string) string { + + return ` + { + "guid": "` + id + `", + "description": "All Kubernetes Resources", + "isDefaultBoolean": true, + "resourceGroupGuid": "` + id + `", + "resourceName": "group_name", + "resourceType": "KUBERNETES", + "enabled": 1, + "query": { + "filters": { + "filter1": { + "field": "AWS Account", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter2": { + "field": "AWS Region", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter3": { + "field": "Cluster Name", + "operation": "EQUALS", + "values": [ + "*" + ] + }, + "filter4": { + "field": "Namespace", + "operation": "EQUALS", + "values": [ + "*" + ] + } + }, + "expression": { + "operator": "OR", + "children": [ + { + "filterName": "filter1" + }, + { + "filterName": "filter2" + }, + { + "filterName": "filter3" + }, + { + "filterName": "filter4" + } + ] + } + } + } + ` +} + func generateResourceGroupsResponse(data string) string { return ` { @@ -282,17 +750,16 @@ func generateResourceGroupResponse(data string) string { ` } -func singleVanillaResourceGroup(id string, iType string, props string) string { - if props == "" { - props = "{}" +func singleVanillaResourceGroup(id string, iType string, query string) string { + if query == "" { + query = "{}" } return ` { - "guid": "` + id + `", - "isDefault": "1", - "props": ` + props + `, - "resourceGuid": "` + id + `", - "resourceName": "group_name", + "isDefaultBoolean": true, + "query": ` + query + `, + "resourceGroupGuid": "` + id + `", + "name": "group_name", "resourceType": "` + iType + `", "enabled": 1 } diff --git a/api/resource_groups_v2.go b/api/resource_groups_v2.go deleted file mode 100644 index e438d1871..000000000 --- a/api/resource_groups_v2.go +++ /dev/null @@ -1,185 +0,0 @@ -// -// Author:: Zeki Sherif() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "fmt" - "time" - - "github.com/pkg/errors" -) - -func (svc *ResourceGroupsV2Service) List() (response ResourceGroupsV2Response, err error) { - var rawResponse ResourceGroupsV2Response - err = svc.client.RequestDecoder("GET", apiV2ResourceGroups, nil, &rawResponse) - if err != nil { - return - } - - return -} - -func (svc *ResourceGroupsV2Service) Create(group ResourceGroupDataWithQuery) ( - response ResourceGroupV2Response, - err error, -) { - err = svc.create(group, &response) - return -} - -func (svc *ResourceGroupsV2Service) Update(data ResourceGroup) ( - response ResourceGroupV2Response, - err error, -) { - if data == nil { - err = errors.New("resource group must not be empty") - return - } - guid := data.ID() - data.ResetResourceGUID() - - err = svc.update(guid, data, &response) - if err != nil { - return - } - - return -} - -func (svc *ResourceGroupsV2Service) Delete(guid string) error { - if guid == "" { - return errors.New("specify a resourceGuid") - } - - return svc.client.RequestDecoder( - "DELETE", - fmt.Sprintf(apiV2ResourceGroupsFromGUID, guid), - nil, - nil, - ) -} - -func (svc *ResourceGroupsV2Service) Get(guid string, response interface{}) error { - var rawResponse resourceGroupWorkaroundResponse - err := svc.get(guid, &rawResponse) - if err != nil { - return err - } - - return castResourceGroupResponse(rawResponse.Data, &response) -} - -func (svc *ResourceGroupsV2Service) create(data interface{}, response interface{}) error { - return svc.client.RequestEncoderDecoder("POST", apiV2ResourceGroups, data, response) -} - -func (svc *ResourceGroupsV2Service) get(guid string, response interface{}) error { - if guid == "" { - return errors.New("specify an resourceGuid") - } - apiPath := fmt.Sprintf(apiV2ResourceGroupsFromGUID, guid) - return svc.client.RequestDecoder("GET", apiPath, nil, response) -} - -func (svc *ResourceGroupsV2Service) update(guid string, data interface{}, response interface{}) error { - if guid == "" { - return errors.New("specify a resource group guid") - } - - apiPath := fmt.Sprintf(apiV2ResourceGroupsFromGUID, guid) - return svc.client.RequestEncoderDecoder("PATCH", apiPath, data, response) -} - -type ResourceGroupV2Response struct { - Data ResourceGroupDataWithQuery `json:"data"` -} - -type ResourceGroupsV2Response struct { - Data []ResourceGroupDataWithQuery `json:"data"` -} - -type ResourceGroupsV2Service struct { - client *Client -} - -type RGExpression struct { - Operator string `json:"operator"` - Children []*RGChild `json:"children"` -} - -type RGChild struct { - Operator string `json:"operator,omitempty"` - FilterName string `json:"filterName,omitempty"` - Children []*RGChild `json:"children,omitempty"` -} - -type RGFilter struct { - Field string `json:"field"` - Operation string `json:"operation"` - Values []string `json:"values"` - Key string `json:"key,omitempty"` -} - -type RGQuery struct { - Filters map[string]*RGFilter `json:"filters"` - Expression *RGExpression `json:"expression"` -} -type ResourceGroupDataWithQuery struct { - Name string `json:"name"` - Type string `json:"resourceType"` - Query *RGQuery `json:"query"` - Description string `json:"description,omitempty"` - ResourceGroupGuid string `json:"resourceGroupGuid,omitempty"` - CreatedTime *time.Time `json:"lastUpdated,omitempty"` - CreatedBy string `json:"createdBy,omitempty"` - UpdatedTime *time.Time `json:"updatedTime,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty"` - Enabled int `json:"enabled,omitempty"` - IsDefaultBoolean *bool `json:"isDefaultBoolean,omitempty"` - IsOrg *bool `json:"isOrg,omitempty"` -} - -func (group ResourceGroupDataWithQuery) GetProps() interface{} { - return nil -} - -func (group ResourceGroupDataWithQuery) GetQuery() *RGQuery { - return group.Query -} - -func (group ResourceGroupDataWithQuery) ResourceGroupType() resourceGroupType { - t, _ := FindResourceGroupType(group.Type) - return t -} - -func (group ResourceGroupDataWithQuery) ID() string { - return group.ResourceGroupGuid -} - -func (group *ResourceGroupDataWithQuery) ResetRGV2Fields() { - // no-op -} - -func (group *ResourceGroupDataWithQuery) ResetResourceGUID() { - group.ResourceGroupGuid = "" -} - -func (group ResourceGroupDataWithQuery) IsV2Group() bool { - return true -} diff --git a/api/resource_groups_version_service.go b/api/resource_groups_version_service.go deleted file mode 100644 index 8af98aa41..000000000 --- a/api/resource_groups_version_service.go +++ /dev/null @@ -1,373 +0,0 @@ -// -// Author:: Zeki Sherif() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package api - -import ( - "encoding/json" - "fmt" - "strconv" - - "github.com/pkg/errors" -) - -type ResourceGroupsVersionService struct { - client *Client - v1ResourceGroupService *ResourceGroupsService - v2ResourceGroupService *ResourceGroupsV2Service - featureFlagService *FeatureFlagsService -} - -type ResourceGroupsInterfaceData interface { - GetProps() interface{} - GetQuery() *RGQuery -} - -func (group ResourceGroupData) GetProps() interface{} { - return group.Props -} - -func (group ResourceGroupData) GetQuery() *RGQuery { - return nil -} - -func NewResourceGroupsVersionService(c *Client) *ResourceGroupsVersionService { - return &ResourceGroupsVersionService{ - c, - &ResourceGroupsService{c}, - &ResourceGroupsV2Service{c}, - &FeatureFlagsService{c}, - } -} - -// NewResourceGroup returns an instance of the ResourceGroupData struct with the -// provided ResourceGroup type, name and the props field as an interface{}. -// -// NOTE: This function must be used by any ResourceGroup type. -// -// Basic usage: Initialize a new ContainerResourceGroup struct, then -// -// use the new instance to do CRUD operations -// -// client, err := api.NewClient("account") -// if err != nil { -// return err -// } -// -// group := api.NewResourceGroup("container resource group", -// api.ContainerResourceGroup, -// api.ContainerResourceGroupData{ -// Props: api.ContainerResourceGroupProps{ -// Description: "all containers, -// ContainerLabels: ContainerResourceGroupAllLabels, -// ContainerTags: ContainerResourceGroupAllTags, -// }, -// }, -// ) -// -// client.V2.ResourceGroups.Create(group) -func NewResourceGroup(name string, iType resourceGroupType, props interface{}) ResourceGroupData { - return ResourceGroupData{ - Name: name, - Type: iType.String(), - Enabled: 1, - Props: props, - } -} - -// NewResourceGroupWithQuery Only available with RGv2 beta -func NewResourceGroupWithQuery(name string, iType resourceGroupType, - description string, query *RGQuery) ResourceGroupDataWithQuery { - return ResourceGroupDataWithQuery{ - Name: name, - Type: iType.String(), - Enabled: 1, - Query: query, - Description: description, - } -} - -func isRGV2FlagEnabled(featureFlagService *FeatureFlagsService) bool { - response, err := featureFlagService.GetFeatureFlagsMatchingPrefix(ApiV2CliFeatureFlag) - - if err != nil { - return false - } - - return len(response.Data.Flags) >= 1 -} - -func (svc *ResourceGroupsVersionService) Get(guid string, response interface{}) error { - var rawResponse resourceGroupWorkaroundResponse - err := svc.get(guid, &rawResponse) - if err != nil { - return err - } - - if rawResponse.Data.Query != nil { - return castRGV2WorkAroundResponse(rawResponse, response) - } else { - return castRGV1WorkAroundResponse(rawResponse, response) - } -} - -func (svc *ResourceGroupsVersionService) Create(group ResourceGroupsInterfaceData) ( - response ResourceGroupResponse, - err error, -) { - isV2FlagEnabled := isRGV2FlagEnabled(svc.featureFlagService) - - if group.GetProps() == nil && !isV2FlagEnabled && group.GetQuery() == nil { - if isV2FlagEnabled { - err = errors.New("Invalid request. Missing `query` field.") - } else { - err = errors.New("Invalid request. Missing `props` field.") - } - - return - } - - if group.GetProps() != nil { - response, err = svc.v1ResourceGroupService.Create(group.(ResourceGroupData)) - return - } - - createResponse, createErr := svc.v2ResourceGroupService.Create(group.(ResourceGroupDataWithQuery)) - if createErr != nil { - err = createErr - return - } - - err = castResourceGroupV2Response(createResponse, &response) - return -} - -func (svc *ResourceGroupsVersionService) Update(group ResourceGroupsInterfaceData) ( - response ResourceGroupResponse, - err error, -) { - if group.GetProps() != nil { - response, err = svc.v1ResourceGroupService.Update(group.(ResourceGroup)) - return - } - - isV2FlagEnabled := isRGV2FlagEnabled(svc.featureFlagService) - - if isV2FlagEnabled { - updateResponse, updateErr := svc.v2ResourceGroupService.Update(group.(ResourceGroup)) - if updateErr != nil { - err = updateErr - return - } - - err = castResourceGroupV2Response(updateResponse, &response) - return - } - - err = errors.New("Unable to update resource group") - return -} - -func (svc *ResourceGroupsVersionService) Delete(guid string) error { - // It doesn't matcher which version of service we use as api-server handles - // delete for both v1 and v2 resource groups - err := svc.v1ResourceGroupService.Delete(guid) - - if err != nil { - return err - } - - return nil -} - -func (svc *ResourceGroupsVersionService) List() (response ResourceGroupsResponse, err error) { - var rawResponse resourceGroupsWorkaroundResponse - err = svc.client.RequestDecoder("GET", apiV2ResourceGroups, nil, &rawResponse) - - if err != nil { - return - } - - return setResourceGroupsVersionUnawareResponse(rawResponse) -} - -func castRGV1WorkAroundResponse(data resourceGroupWorkaroundResponse, response interface{}) error { - isDefault, err := strconv.Atoi(data.Data.IsDefault) - if err != nil { - return err - } - group := ResourceGroupResponse{ - Data: ResourceGroupData{ - Guid: data.Data.Guid, - IsDefault: isDefault, - ResourceGuid: data.Data.ResourceGuid, - Name: data.Data.Name, - Type: data.Data.Type, - Enabled: data.Data.Enabled, - Props: data.Data.Props, - }, - } - - j, err := json.Marshal(group) - if err != nil { - return err - } - - err = json.Unmarshal(j, &response) - if err != nil { - return err - } - - return nil -} - -func castRGV2WorkAroundResponse(data resourceGroupWorkaroundResponse, response interface{}) error { - group := ResourceGroupResponse{ - Data: ResourceGroupData{ - Type: data.Data.Type, - Enabled: data.Data.Enabled, - NameV2: data.Data.NameV2, - Query: data.Data.Query, - Description: data.Data.Description, - ResourceGroupGuid: data.Data.ResourceGroupGuid, - CreatedTime: data.Data.CreatedTime, - CreatedBy: data.Data.CreatedBy, - UpdatedTime: data.Data.UpdatedTime, - UpdatedBy: data.Data.UpdatedBy, - IsDefaultBoolean: data.Data.IsDefaultBoolean, - IsOrg: data.Data.IsOrg, - }, - } - - j, err := json.Marshal(group) - if err != nil { - return err - } - - err = json.Unmarshal(j, &response) - if err != nil { - return err - } - - return nil -} - -func castResourceGroupV2Response(data ResourceGroupV2Response, response interface{}) error { - group := ResourceGroupResponse{ - Data: ResourceGroupData{ - Type: data.Data.Type, - Enabled: data.Data.Enabled, - NameV2: data.Data.Name, - Query: data.Data.Query, - Description: data.Data.Description, - ResourceGroupGuid: data.Data.ResourceGroupGuid, - CreatedTime: data.Data.CreatedTime, - CreatedBy: data.Data.CreatedBy, - UpdatedTime: data.Data.UpdatedTime, - UpdatedBy: data.Data.UpdatedBy, - IsDefaultBoolean: data.Data.IsDefaultBoolean, - IsOrg: data.Data.IsOrg, - }, - } - - j, err := json.Marshal(group) - if err != nil { - return err - } - - err = json.Unmarshal(j, &response) - if err != nil { - return err - } - - return nil -} - -func (svc *ResourceGroupsVersionService) get(guid string, response interface{}) error { - if guid == "" { - return errors.New("specify an resourceGuid") - } - apiPath := fmt.Sprintf(apiV2ResourceGroupsFromGUID, guid) - return svc.client.RequestDecoder("GET", apiPath, nil, response) -} - -func (svc *ResourceGroupsVersionService) create(data interface{}, response interface{}) error { - return svc.client.RequestEncoderDecoder("POST", apiV2ResourceGroups, data, response) -} - -func (svc *ResourceGroupsVersionService) update(guid string, data interface{}, response interface{}) error { - if guid == "" { - return errors.New("specify a resource group guid") - } - - apiPath := fmt.Sprintf(apiV2ResourceGroupsFromGUID, guid) - return svc.client.RequestEncoderDecoder("PATCH", apiPath, data, response) -} - -func setResourceGroupResponse(response resourceGroupWorkaroundData) (ResourceGroupResponse, - error) { - - if response.Props != nil { - isDefault, err := strconv.Atoi(response.IsDefault) - if err != nil { - return ResourceGroupResponse{}, err - } - return ResourceGroupResponse{ - Data: ResourceGroupData{ - Guid: response.Guid, - IsDefault: isDefault, - ResourceGuid: response.ResourceGuid, - Name: response.Name, - Type: response.Type, - Enabled: response.Enabled, - Props: response.Props, - }, - }, nil - } else { - return ResourceGroupResponse{ - Data: ResourceGroupData{ - Type: response.Type, - Enabled: response.Enabled, - NameV2: response.NameV2, - Query: response.Query, - Description: response.Description, - ResourceGroupGuid: response.ResourceGroupGuid, - CreatedTime: response.CreatedTime, - CreatedBy: response.CreatedBy, - UpdatedTime: response.UpdatedTime, - UpdatedBy: response.UpdatedBy, - IsDefaultBoolean: response.IsDefaultBoolean, - IsOrg: response.IsOrg, - }, - }, nil - } -} - -func setResourceGroupsVersionUnawareResponse(workaround resourceGroupsWorkaroundResponse) ( - ResourceGroupsResponse, error) { - var data []ResourceGroupData - for _, r := range workaround.Data { - group, err := setResourceGroupResponse(r) - if err != nil { - return ResourceGroupsResponse{}, err - } - data = append(data, group.Data) - } - - return ResourceGroupsResponse{Data: data}, nil -} diff --git a/api/v2.go b/api/v2.go index bf47f1e21..cb44328f1 100644 --- a/api/v2.go +++ b/api/v2.go @@ -43,7 +43,7 @@ type V2Endpoints struct { ContainerRegistries *ContainerRegistriesService Configs *v2ConfigService FeatureFlags *FeatureFlagsService - ResourceGroups *ResourceGroupsVersionService + ResourceGroups *ResourceGroupsService AgentAccessTokens *AgentAccessTokensService AgentInfo *AgentInfoService Inventory *InventoryService @@ -80,7 +80,7 @@ func NewV2Endpoints(c *Client) *V2Endpoints { &ContainerRegistriesService{c}, NewV2ConfigService(c), &FeatureFlagsService{c}, - NewResourceGroupsVersionService(c), + &ResourceGroupsService{c}, &AgentAccessTokensService{c}, &AgentInfoService{c}, &InventoryService{c}, diff --git a/cli/cmd/resource_group_aws.go b/cli/cmd/resource_group_aws.go deleted file mode 100644 index dcdafc69c..000000000 --- a/cli/cmd/resource_group_aws.go +++ /dev/null @@ -1,95 +0,0 @@ -// -// Author:: Darren Murray() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package cmd - -import ( - "encoding/json" - "strings" - - "github.com/AlecAivazis/survey/v2" - - "github.com/lacework/go-sdk/api" -) - -func createAwsResourceGroup() error { - questions := []*survey.Question{ - { - Name: "name", - Prompt: &survey.Input{Message: "Name: "}, - Validate: survey.Required, - }, - { - Name: "description", - Prompt: &survey.Input{Message: "Description: "}, - Validate: survey.Required, - }, - { - Name: "account_ids", - Prompt: &survey.Multiline{Message: "List of Account IDs: "}, - Validate: survey.Required, - }, - } - - answers := struct { - Name string - Description string `survey:"description"` - AccountIDs string `survey:"account_ids"` - }{} - - err := survey.Ask(questions, &answers, - survey.WithIcons(promptIconsFunc), - ) - if err != nil { - return err - } - - aws := api.NewResourceGroup( - answers.Name, - api.AwsResourceGroup, - api.AwsResourceGroupProps{ - Description: answers.Description, - AccountIDs: strings.Split(answers.AccountIDs, "\n"), - }) - - cli.StartProgress(" Creating resource group...") - _, err = cli.LwApi.V2.ResourceGroups.Create(aws) - cli.StopProgress() - return err -} - -func setAwsProps(group []byte) []string { - awsProps, err := unmarshallAwsProps(group) - if err != nil { - return []string{} - } - - return []string{"ACCOUNT IDS", strings.Join(awsProps.AccountIDs, ",")} -} - -func unmarshallAwsPropString(group []byte) (props api.AwsResourceGroupProps, err error) { - var rawProps api.AwsResourceJsonStringGroupProps - err = json.Unmarshal(group, &rawProps) - props = api.AwsResourceGroupProps(rawProps) - return -} - -func unmarshallAwsProps(group []byte) (props api.AwsResourceGroupProps, err error) { - err = json.Unmarshal(group, &props) - return -} diff --git a/cli/cmd/resource_group_azure.go b/cli/cmd/resource_group_azure.go deleted file mode 100644 index 945bd9f15..000000000 --- a/cli/cmd/resource_group_azure.go +++ /dev/null @@ -1,106 +0,0 @@ -// -// Author:: Darren Murray() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package cmd - -import ( - "encoding/json" - "strings" - - "github.com/AlecAivazis/survey/v2" - - "github.com/lacework/go-sdk/api" -) - -func createAzureResourceGroup() error { - questions := []*survey.Question{ - { - Name: "name", - Prompt: &survey.Input{Message: "Name: "}, - Validate: survey.Required, - }, - { - Name: "description", - Prompt: &survey.Input{Message: "Description: "}, - Validate: survey.Required, - }, - { - Name: "tenant", - Prompt: &survey.Input{Message: "Tenant: "}, - Validate: survey.Required, - }, - { - Name: "subscriptions", - Prompt: &survey.Multiline{Message: "List of Subscriptions: "}, - Validate: survey.Required, - }, - } - - answers := struct { - Name string - Description string `survey:"description"` - Tenant string `survey:"tenant"` - Subscriptions string `survey:"subscriptions"` - }{} - - err := survey.Ask(questions, &answers, - survey.WithIcons(promptIconsFunc), - ) - if err != nil { - return err - } - - azure := api.NewResourceGroup( - answers.Name, - api.AzureResourceGroup, - api.AzureResourceGroupProps{ - Description: answers.Description, - Tenant: answers.Tenant, - Subscriptions: strings.Split(answers.Subscriptions, "\n"), - }) - - cli.StartProgress(" Creating resource group...") - _, err = cli.LwApi.V2.ResourceGroups.Create(azure) - cli.StopProgress() - return err -} - -func setAzureProps(group []byte) [][]string { - var details [][]string - - azProps, err := unmarshallAzureProps(group) - if err != nil { - return [][]string{} - } - - details = append(details, []string{"TENANT", azProps.Tenant}) - details = append(details, []string{"SUBSCRIPTIONS", strings.Join(azProps.Subscriptions, ",")}) - return details -} - -func unmarshallAzurePropString(group []byte) (props api.AzureResourceGroupProps, err error) { - var rawProps api.AzureResourceJsonStringGroupProps - err = json.Unmarshal(group, &rawProps) - props = api.AzureResourceGroupProps(rawProps) - return -} - -func unmarshallAzureProps(group []byte) (props api.AzureResourceGroupProps, err error) { - err = json.Unmarshal(group, &props) - return -} diff --git a/cli/cmd/resource_group_container.go b/cli/cmd/resource_group_container.go deleted file mode 100644 index e1ce514bf..000000000 --- a/cli/cmd/resource_group_container.go +++ /dev/null @@ -1,114 +0,0 @@ -// -// Author:: Darren Murray() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package cmd - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/AlecAivazis/survey/v2" - - "github.com/lacework/go-sdk/api" -) - -func createContainerResourceGroup() error { - questions := []*survey.Question{ - { - Name: "name", - Prompt: &survey.Input{Message: "Name: "}, - Validate: survey.Required, - }, - { - Name: "description", - Prompt: &survey.Input{Message: "Description: "}, - Validate: survey.Required, - }, - { - Name: "tags", - Prompt: &survey.Multiline{Message: "List of Tags: "}, - Validate: survey.Required, - }, { - Name: "labels", - Prompt: &survey.Multiline{Message: "List of 'key:value' Labels:"}, - Validate: survey.Required, - }, - } - - answers := struct { - Name string - Description string `survey:"description"` - Tags string `survey:"tags"` - Labels string `survey:"labels"` - }{} - - err := survey.Ask(questions, &answers, - survey.WithIcons(promptIconsFunc), - ) - if err != nil { - return err - } - - container := api.NewResourceGroup( - answers.Name, - api.ContainerResourceGroup, - api.ContainerResourceGroupProps{ - Description: answers.Description, - ContainerTags: strings.Split(answers.Tags, "\n"), - ContainerLabels: castStringToLimitByLabel(answers.Labels), - }) - - cli.StartProgress(" Creating resource group...") - _, err = cli.LwApi.V2.ResourceGroups.Create(container) - cli.StopProgress() - return err -} - -func setContainerProps(group []byte) [][]string { - var ( - details [][]string - labels []string - ) - - ctrProps, err := unmarshallContainerProps(group) - if err != nil { - return [][]string{} - } - - for _, labelMap := range ctrProps.ContainerLabels { - for key, val := range labelMap { - labels = append(labels, fmt.Sprintf("%s: %v", key, val)) - } - } - details = append(details, []string{"CONTAINER LABELS", strings.Join(labels, ",")}) - details = append(details, []string{"CONTAINER TAGS", strings.Join(ctrProps.ContainerTags, ",")}) - return details -} - -func unmarshallContainerPropString(group []byte) (props api.ContainerResourceGroupProps, err error) { - var rawProps api.ContainerResourceJsonStringGroupProps - err = json.Unmarshal(group, &rawProps) - props = api.ContainerResourceGroupProps(rawProps) - return -} - -func unmarshallContainerProps(group []byte) (props api.ContainerResourceGroupProps, err error) { - err = json.Unmarshal(group, &props) - return -} diff --git a/cli/cmd/resource_group_gcp.go b/cli/cmd/resource_group_gcp.go deleted file mode 100644 index 7549b1874..000000000 --- a/cli/cmd/resource_group_gcp.go +++ /dev/null @@ -1,105 +0,0 @@ -// -// Author:: Darren Murray() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package cmd - -import ( - "encoding/json" - "strings" - - "github.com/AlecAivazis/survey/v2" - "github.com/lacework/go-sdk/api" -) - -func createGcpResourceGroup() error { - questions := []*survey.Question{ - { - Name: "name", - Prompt: &survey.Input{Message: "Name: "}, - Validate: survey.Required, - }, - { - Name: "description", - Prompt: &survey.Input{Message: "Description: "}, - Validate: survey.Required, - }, - { - Name: "organization", - Prompt: &survey.Input{Message: "Organization: "}, - Validate: survey.Required, - }, - { - Name: "projects", - Prompt: &survey.Multiline{Message: "List of Projects: "}, - Validate: survey.Required, - }, - } - - answers := struct { - Name string - Description string `survey:"description"` - Organization string `survey:"organization"` - Projects string `survey:"projects"` - }{} - - err := survey.Ask(questions, &answers, - survey.WithIcons(promptIconsFunc), - ) - if err != nil { - return err - } - - gcp := api.NewResourceGroup( - answers.Name, - api.GcpResourceGroup, - api.GcpResourceGroupProps{ - Description: answers.Description, - Organization: answers.Organization, - Projects: strings.Split(answers.Projects, "\n"), - }) - - cli.StartProgress(" Creating resource group...") - _, err = cli.LwApi.V2.ResourceGroups.Create(gcp) - cli.StopProgress() - return err -} - -func setGcpProps(group []byte) [][]string { - var details [][]string - - gcpProps, err := unmarshallGcpProps(group) - if err != nil { - return [][]string{} - } - - details = append(details, []string{"ORGANIZATION", gcpProps.Organization}) - details = append(details, []string{"PROJECTS", strings.Join(gcpProps.Projects, ",")}) - return details -} - -func unmarshallGcpPropString(group []byte) (props api.GcpResourceGroupProps, err error) { - var rawProps api.GcpResourceGroupJsonStringProps - err = json.Unmarshal(group, &rawProps) - props = api.GcpResourceGroupProps(rawProps) - return -} - -func unmarshallGcpProps(group []byte) (props api.GcpResourceGroupProps, err error) { - err = json.Unmarshal(group, &props) - return -} diff --git a/cli/cmd/resource_group_lw_account.go b/cli/cmd/resource_group_lw_account.go deleted file mode 100644 index 252572a27..000000000 --- a/cli/cmd/resource_group_lw_account.go +++ /dev/null @@ -1,103 +0,0 @@ -// -// Author:: Darren Murray() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package cmd - -import ( - "encoding/json" - "strings" - - "github.com/AlecAivazis/survey/v2" - "github.com/lacework/go-sdk/api" -) - -func createLwAccountResourceGroup() error { - questions := []*survey.Question{ - { - Name: "name", - Prompt: &survey.Input{Message: "Name: "}, - Validate: survey.Required, - }, - { - Name: "description", - Prompt: &survey.Input{Message: "Description: "}, - Validate: survey.Required, - }, - { - Name: "accounts", - Prompt: &survey.Multiline{Message: "List of Lacework Accounts: "}, - Validate: survey.Required, - }, - } - - answers := struct { - Name string - Description string `survey:"description"` - Accounts string `survey:"accounts"` - }{} - - err := survey.Ask(questions, &answers, - survey.WithIcons(promptIconsFunc), - ) - if err != nil { - return err - } - - lwAccount := api.NewResourceGroup( - answers.Name, - api.LwAccountResourceGroup, - api.LwAccountResourceGroupProps{ - Description: answers.Description, - LwAccounts: strings.Split(answers.Accounts, "\n"), - }) - - orgLwClient, err := api.CopyClient(cli.LwApi, - api.WithOrgAccess(), - ) - - if err != nil { - return err - } - - cli.StartProgress(" Creating resource group...") - _, err = orgLwClient.V2.ResourceGroups.Create(lwAccount) - - cli.StopProgress() - return err -} - -func setLwAccountProps(group []byte) []string { - lwProps, err := unmarshallLwAccountProps(group) - if err != nil { - return []string{} - } - - return []string{"LW ACCOUNTS", strings.Join(lwProps.LwAccounts, ",")} -} - -func unmarshallLwAccountPropString(group []byte) (props api.LwAccountResourceGroupProps, err error) { - var rawProps api.LwAccountResourceGroupJsonStringProps - err = json.Unmarshal(group, &rawProps) - props = api.LwAccountResourceGroupProps(rawProps) - return -} - -func unmarshallLwAccountProps(group []byte) (props api.LwAccountResourceGroupProps, err error) { - err = json.Unmarshal(group, &props) - return -} diff --git a/cli/cmd/resource_group_machine.go b/cli/cmd/resource_group_machine.go deleted file mode 100644 index 78083d0f5..000000000 --- a/cli/cmd/resource_group_machine.go +++ /dev/null @@ -1,102 +0,0 @@ -// -// Author:: Darren Murray() -// Copyright:: Copyright 2021, Lacework Inc. -// License:: Apache License, Version 2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package cmd - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/AlecAivazis/survey/v2" - "github.com/lacework/go-sdk/api" -) - -func createMachineResourceGroup() error { - questions := []*survey.Question{ - { - Name: "name", - Prompt: &survey.Input{Message: "Name: "}, - Validate: survey.Required, - }, - { - Name: "description", - Prompt: &survey.Input{Message: "Description: "}, - Validate: survey.Required, - }, - { - Name: "tags", - Prompt: &survey.Multiline{Message: "List of 'key:value' Machine Tags:"}, - Validate: survey.Required, - }, - } - - answers := struct { - Name string - Description string `survey:"description"` - MachineTags string `survey:"tags"` - }{} - - err := survey.Ask(questions, &answers, - survey.WithIcons(promptIconsFunc), - ) - if err != nil { - return err - } - - machine := api.NewResourceGroup( - answers.Name, - api.MachineResourceGroup, - api.MachineResourceGroupProps{ - Description: answers.Description, - MachineTags: castStringToLimitByLabel(answers.MachineTags), - }) - - cli.StartProgress(" Creating resource group...") - _, err = cli.LwApi.V2.ResourceGroups.Create(machine) - cli.StopProgress() - return err -} - -func setMachineProps(group []byte) []string { - machineProps, err := unmarshallMachineProps(group) - if err != nil { - return []string{} - } - - var tags []string - for _, tagMap := range machineProps.MachineTags { - for key, val := range tagMap { - tags = append(tags, fmt.Sprintf("%s: %v", key, val)) - - } - } - return []string{"MACHINE TAGS", strings.Join(tags, ",")} -} - -func unmarshallMachinePropString(group []byte) (props api.MachineResourceGroupProps, err error) { - var rawProps api.MachineResourceGroupJsonStringProps - err = json.Unmarshal(group, &rawProps) - props = api.MachineResourceGroupProps(rawProps) - return -} - -func unmarshallMachineProps(group []byte) (props api.MachineResourceGroupProps, err error) { - err = json.Unmarshal(group, &props) - return -} diff --git a/cli/cmd/resource_group_v2.go b/cli/cmd/resource_group_v2.go index 2e5b05a35..8002c82c7 100644 --- a/cli/cmd/resource_group_v2.go +++ b/cli/cmd/resource_group_v2.go @@ -27,7 +27,7 @@ import ( "github.com/lacework/go-sdk/api" ) -func createResourceGroupV2(resourceType string) error { +func createResourceGroup(resourceType string) error { questions := []*survey.Question{ { Name: "name", @@ -71,8 +71,7 @@ func createResourceGroupV2(resourceType string) error { // This should never reach this. The type is controlled by us in cmd/resource_groups return errors.New("internal error") } - resourceGroup := api.NewResourceGroupWithQuery(answers.Name, groupType, answers.Description, &rgQuery) - + resourceGroup := api.NewResourceGroup(answers.Name, groupType, answers.Description, &rgQuery) cli.StartProgress(" Creating resource group...") _, err = cli.LwApi.V2.ResourceGroups.Create(resourceGroup) cli.StopProgress() diff --git a/cli/cmd/resource_groups.go b/cli/cmd/resource_groups.go index cb0e896c3..e3667c7fd 100644 --- a/cli/cmd/resource_groups.go +++ b/cli/cmd/resource_groups.go @@ -19,13 +19,12 @@ package cmd import ( - "encoding/json" "fmt" + "strconv" "time" "github.com/AlecAivazis/survey/v2" "github.com/lacework/go-sdk/api" - "github.com/olekukonko/tablewriter" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -70,35 +69,14 @@ Then navigate to Settings > Resource Groups. groups := make([]resourceGroup, 0) for _, g := range resourceGroups.Data { - var props api.ResourceGroupProps - var resourceGroupGuid string - var isDefault int - var resourceName string - - if g.GetProps() != nil { - props, _ = parsePropsType(g.Props, g.Type) - resourceGroupGuid = g.ResourceGuid - isDefault = g.IsDefault - resourceName = g.Name - } else { - resourceGroupGuid = g.ResourceGroupGuid - if *g.IsDefaultBoolean { - isDefault = 1 - } else { - isDefault = 0 - } - resourceName = g.NameV2 - } groups = append(groups, resourceGroup{ - Id: resourceGroupGuid, - ResType: g.Type, - Name: resourceName, - status: g.Status(), - Props: props, - Enabled: g.Enabled, - IsDefault: isDefault, - Query: g.Query, + Id: g.ResourceGroupGuid, + ResType: g.Type, + Name: g.Name, + Enabled: g.Enabled, + IsDefaultBoolean: g.IsDefaultBoolean, + Query: g.Query, }) } @@ -111,7 +89,8 @@ Then navigate to Settings > Resource Groups. rows := [][]string{} for _, g := range groups { - rows = append(rows, []string{g.Id, g.ResType, g.Name, g.status, IsDefault(g.IsDefault)}) + rows = append(rows, []string{g.Id, g.ResType, g.Name, strconv.Itoa(g.Enabled), + strconv.FormatBool(*g.IsDefaultBoolean)}) } cli.OutputHuman(renderSimpleTable([]string{"RESOURCE GROUP ID", "TYPE", "NAME", "STATUS", "DEFAULT"}, rows)) @@ -127,42 +106,23 @@ Then navigate to Settings > Resource Groups. RunE: func(_ *cobra.Command, args []string) error { var response api.ResourceGroupResponse err := cli.LwApi.V2.ResourceGroups.Get(args[0], &response) + if err != nil { return errors.Wrap(err, "unable to get resource group") } - var props api.ResourceGroupProps - var resourceGroupGuid string - var isDefault int - var name string - - if response.Data.Props != nil { - props, _ = parsePropsType(response.Data.Props, response.Data.Type) - resourceGroupGuid = response.Data.ResourceGuid - isDefault = response.Data.IsDefault - name = response.Data.Name - } else { - resourceGroupGuid = response.Data.ResourceGroupGuid - if *response.Data.IsDefaultBoolean { - isDefault = 1 - } else { - isDefault = 0 - } - name = response.Data.NameV2 - } - group := resourceGroup{ - Id: resourceGroupGuid, - ResType: response.Data.Type, - Name: name, - status: response.Data.Status(), - Props: props, - Enabled: response.Data.Enabled, - IsDefault: isDefault, - Query: response.Data.Query, - Description: response.Data.Description, - UpdatedBy: response.Data.UpdatedBy, - UpdatedTime: response.Data.UpdatedTime, + Id: response.Data.ResourceGroupGuid, + ResType: response.Data.Type, + Name: response.Data.Name, + Enabled: response.Data.Enabled, + IsDefaultBoolean: response.Data.IsDefaultBoolean, + Query: response.Data.Query, + Description: response.Data.Description, + UpdatedBy: response.Data.UpdatedBy, + UpdatedTime: response.Data.UpdatedTime, + CreatedTime: response.Data.CreatedTime, + CreatedBy: response.Data.CreatedBy, } if cli.JSONOutput() { @@ -174,21 +134,13 @@ Then navigate to Settings > Resource Groups. var groupCommon [][]string - if group.Props != nil { - groupCommon = append(groupCommon, - []string{group.Id, group.ResType, group.Name, group.status, IsDefault(group.IsDefault)}, - ) - cli.OutputHuman(renderSimpleTable([]string{"RESOURCE GROUP ID", "TYPE", "NAME", "STATE", "DEFAULT"}, groupCommon)) - cli.OutputHuman("\n") - cli.OutputHuman(buildResourceGroupPropsTable(group)) - } else { - groupCommon = append(groupCommon, - []string{group.Id, group.ResType, group.Name, group.Description, group.status, - IsDefault(group.IsDefault), group.UpdatedBy, group.UpdatedTime.UTC().String()}, - ) - cli.OutputHuman(renderSimpleTable([]string{"RESOURCE GROUP ID", "TYPE", "NAME", "DESCRIPTION", "STATE", - "DEFAULT", "UPDATED BY", "UPDATED_TIME"}, groupCommon)) - } + groupCommon = append(groupCommon, + []string{group.Id, group.ResType, group.Name, group.Description, strconv.Itoa(group.Enabled), + strconv.FormatBool(*group.IsDefaultBoolean), group.CreatedBy, group.CreatedTime.UTC().String(), + group.UpdatedBy, group.UpdatedTime.UTC().String()}, + ) + cli.OutputHuman(renderSimpleTable([]string{"RESOURCE GROUP ID", "TYPE", "NAME", "DESCRIPTION", "STATE", + "DEFAULT", "CREATED BY", "CREATED TIME", "UPDATED BY", "UPDATED TIME"}, groupCommon)) return nil }, @@ -232,27 +184,6 @@ Then navigate to Settings > Resource Groups. } ) -// parsePropsType converts props json string to interface of resource group props type -func parsePropsType(props interface{}, resourceType string) (api.ResourceGroupProps, error) { - propsString := props.(string) - - switch resourceType { - case api.AwsResourceGroup.String(): - return unmarshallAwsPropString([]byte(propsString)) - case api.AzureResourceGroup.String(): - return unmarshallAzurePropString([]byte(propsString)) - case api.ContainerResourceGroup.String(): - return unmarshallContainerPropString([]byte(propsString)) - case api.GcpResourceGroup.String(): - return unmarshallGcpPropString([]byte(propsString)) - case api.LwAccountResourceGroup.String(): - return unmarshallLwAccountPropString([]byte(propsString)) - case api.MachineResourceGroup.String(): - return unmarshallMachinePropString([]byte(propsString)) - } - return nil, errors.New("Unable to determine resource group props type") -} - func promptCreateResourceGroup() error { resourceGroupOptions := []string{ @@ -260,25 +191,9 @@ func promptCreateResourceGroup() error { "AZURE", "CONTAINER", "GCP", - "LW_ACCOUNT", "MACHINE", - } - - isRGv2Enabled := false - ffResponse, _ := cli.LwApi.V2.FeatureFlags.GetFeatureFlagsMatchingPrefix(api.ApiV2CliFeatureFlag) - if len(ffResponse.Data.Flags) >= 1 { - isRGv2Enabled = true - } - - if isRGv2Enabled { - resourceGroupOptions = append(resourceGroupOptions, - "AWS(v2)", - "AZURE(v2)", - "GCP(v2)", - "CONTAINER(v2)", - "MACHINE(v2)", - "OCI(v2)", - ) + "OCI", + "KUBERNETES", } var ( @@ -295,89 +210,24 @@ func promptCreateResourceGroup() error { switch group { case "AWS": - return createAwsResourceGroup() + return createResourceGroup("AWS") case "AZURE": - return createAzureResourceGroup() - case "CONTAINER": - return createContainerResourceGroup() + return createResourceGroup("AZURE") case "GCP": - return createGcpResourceGroup() - case "LW_ACCOUNT": - return createLwAccountResourceGroup() + return createResourceGroup("GCP") + case "CONTAINER": + return createResourceGroup("CONTAINER") case "MACHINE": - return createMachineResourceGroup() - case "AWS(v2)": - return createResourceGroupV2("AWS") - case "AZURE(v2)": - return createResourceGroupV2("AZURE") - case "GCP(v2)": - return createResourceGroupV2("GCP") - case "CONTAINER(v2)": - return createResourceGroupV2("CONTAINER") - case "MACHINE(v2)": - return createResourceGroupV2("MACHINE") - case "OCI(v2)": - return createResourceGroupV2("OCI") + return createResourceGroup("MACHINE") + case "OCI": + return createResourceGroup("OCI") + case "KUBERNETES": + return createResourceGroup("KUBERNETES") default: return errors.New("unknown resource group type") } } -func buildResourceGroupPropsTable(group resourceGroup) string { - props := determineResourceGroupProps(group.ResType, group.Props) - - return renderOneLineCustomTable("RESOURCE GROUP PROPS", - renderCustomTable([]string{}, props, - tableFunc(func(t *tablewriter.Table) { - t.SetBorder(false) - t.SetColumnSeparator(" ") - t.SetAutoWrapText(false) - t.SetAlignment(tablewriter.ALIGN_LEFT) - }), - ), - tableFunc(func(t *tablewriter.Table) { - t.SetBorder(false) - t.SetAutoWrapText(false) - }), - ) -} - -func determineResourceGroupProps(resType string, props api.ResourceGroupProps) [][]string { - propsString, err := json.Marshal(props) - if err != nil { - return [][]string{} - } - details := setBaseProps(props) - - switch resType { - case api.AwsResourceGroup.String(): - details = append(details, setAwsProps(propsString)) - case api.AzureResourceGroup.String(): - details = append(details, setAzureProps(propsString)...) - case api.ContainerResourceGroup.String(): - details = append(details, setContainerProps(propsString)...) - case api.GcpResourceGroup.String(): - details = append(details, setGcpProps(propsString)...) - case api.LwAccountResourceGroup.String(): - details = append(details, setLwAccountProps(propsString)) - case api.MachineResourceGroup.String(): - details = append(details, setMachineProps(propsString)) - } - - return details -} - -func setBaseProps(props api.ResourceGroupProps) [][]string { - var ( - details [][]string - ) - lastUpdated := props.GetBaseProps().LastUpdated - details = append(details, []string{"DESCRIPTION", props.GetBaseProps().Description}) - details = append(details, []string{"UPDATED BY", props.GetBaseProps().UpdatedBy}) - details = append(details, []string{"LAST UPDATED", lastUpdated.String()}) - return details -} - func init() { // add the resource-group command rootCmd.AddCommand(resourceGroupsCommand) @@ -389,23 +239,16 @@ func init() { resourceGroupsCommand.AddCommand(resourceGroupsDeleteCommand) } -func IsDefault(isDefault int) string { - if isDefault == 1 { - return "True" - } - return "False" -} - type resourceGroup struct { - Id string `json:"resource_guid"` - ResType string `json:"type"` - Name string `json:"name"` - Props api.ResourceGroupProps `json:"props"` - Enabled int `json:"enabled"` - IsDefault int `json:"isDefault"` - Query *api.RGQuery `json:"query"` - Description string `json:"description,omitempty"` - UpdatedTime *time.Time `json:"updatedTime,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty"` - status string + Id string `json:"resourceGroupGuid"` + ResType string `json:"type"` + Name string `json:"name"` + Enabled int `json:"enabled"` + IsDefaultBoolean *bool `json:"isDefaultBoolean"` + Query *api.RGQuery `json:"query"` + Description string `json:"description,omitempty"` + UpdatedTime *time.Time `json:"updatedTime,omitempty"` + UpdatedBy string `json:"updatedBy,omitempty"` + CreatedBy string `json:"createdBy,omitempty"` + CreatedTime *time.Time `json:"createdTime,omitempty"` } diff --git a/cli/docs/lacework_cloud-account_migrate.md b/cli/docs/lacework_cloud-account_migrate.md new file mode 100644 index 000000000..a94e153f7 --- /dev/null +++ b/cli/docs/lacework_cloud-account_migrate.md @@ -0,0 +1,41 @@ +--- +title: "lacework cloud-account migrate" +slug: lacework_cloud-account_migrate +hide_title: true +--- + +## lacework cloud-account migrate + +Mark a GCPv1 (storage-based) cloud account integration for migration + +``` +lacework cloud-account migrate [flags] +``` + +### Options + +``` + -h, --help help for migrate +``` + +### Options inherited from parent commands + +``` + -a, --account string account subdomain of URL (i.e. .lacework.net) + -k, --api_key string access key id + -s, --api_secret string secret access key + --api_token string access token (replaces the use of api_key and api_secret) + --debug turn on debug logging + --json switch commands output from human-readable to json format + --nocache turn off caching + --nocolor turn off colors + --noninteractive turn off interactive mode (disable spinners, prompts, etc.) + --organization access organization level data sets (org admins only) + -p, --profile string switch between profiles configured at ~/.lacework.toml + --subaccount string sub-account name inside your organization (org admins only) +``` + +### SEE ALSO + +* [lacework cloud-account](lacework_cloud-account.md) - Manage cloud accounts + diff --git a/cli/docs/lacework_compliance_aws_scan.md b/cli/docs/lacework_compliance_aws_scan.md new file mode 100644 index 000000000..68c497d65 --- /dev/null +++ b/cli/docs/lacework_compliance_aws_scan.md @@ -0,0 +1,45 @@ +--- +title: "lacework compliance aws scan" +slug: lacework_compliance_aws_scan +hide_title: true +--- + +## lacework compliance aws scan + +Scan triggers a new resource inventory scan + +### Synopsis + +Scan triggers a new resource inventory scan. + +``` +lacework compliance aws scan [flags] +``` + +### Options + +``` + -h, --help help for scan +``` + +### Options inherited from parent commands + +``` + -a, --account string account subdomain of URL (i.e. .lacework.net) + -k, --api_key string access key id + -s, --api_secret string secret access key + --api_token string access token (replaces the use of api_key and api_secret) + --debug turn on debug logging + --json switch commands output from human-readable to json format + --nocache turn off caching + --nocolor turn off colors + --noninteractive turn off interactive mode (disable spinners, prompts, etc.) + --organization access organization level data sets (org admins only) + -p, --profile string switch between profiles configured at ~/.lacework.toml + --subaccount string sub-account name inside your organization (org admins only) +``` + +### SEE ALSO + +* [lacework compliance aws](lacework_compliance_aws.md) - Compliance for AWS + diff --git a/cli/docs/lacework_compliance_azure_scan.md b/cli/docs/lacework_compliance_azure_scan.md new file mode 100644 index 000000000..f71fd0d76 --- /dev/null +++ b/cli/docs/lacework_compliance_azure_scan.md @@ -0,0 +1,45 @@ +--- +title: "lacework compliance azure scan" +slug: lacework_compliance_azure_scan +hide_title: true +--- + +## lacework compliance azure scan + +Scan triggers a new resource inventory scan + +### Synopsis + +Scan triggers a new resource inventory scan. + +``` +lacework compliance azure scan [flags] +``` + +### Options + +``` + -h, --help help for scan +``` + +### Options inherited from parent commands + +``` + -a, --account string account subdomain of URL (i.e. .lacework.net) + -k, --api_key string access key id + -s, --api_secret string secret access key + --api_token string access token (replaces the use of api_key and api_secret) + --debug turn on debug logging + --json switch commands output from human-readable to json format + --nocache turn off caching + --nocolor turn off colors + --noninteractive turn off interactive mode (disable spinners, prompts, etc.) + --organization access organization level data sets (org admins only) + -p, --profile string switch between profiles configured at ~/.lacework.toml + --subaccount string sub-account name inside your organization (org admins only) +``` + +### SEE ALSO + +* [lacework compliance azure](lacework_compliance_azure.md) - Compliance for Azure Cloud + diff --git a/cli/docs/lacework_compliance_google_scan.md b/cli/docs/lacework_compliance_google_scan.md new file mode 100644 index 000000000..a6c4b2d83 --- /dev/null +++ b/cli/docs/lacework_compliance_google_scan.md @@ -0,0 +1,45 @@ +--- +title: "lacework compliance google scan" +slug: lacework_compliance_google_scan +hide_title: true +--- + +## lacework compliance google scan + +Scan triggers a new resource inventory scan + +### Synopsis + +Scan triggers a new resource inventory scan. + +``` +lacework compliance google scan [flags] +``` + +### Options + +``` + -h, --help help for scan +``` + +### Options inherited from parent commands + +``` + -a, --account string account subdomain of URL (i.e. .lacework.net) + -k, --api_key string access key id + -s, --api_secret string secret access key + --api_token string access token (replaces the use of api_key and api_secret) + --debug turn on debug logging + --json switch commands output from human-readable to json format + --nocache turn off caching + --nocolor turn off colors + --noninteractive turn off interactive mode (disable spinners, prompts, etc.) + --organization access organization level data sets (org admins only) + -p, --profile string switch between profiles configured at ~/.lacework.toml + --subaccount string sub-account name inside your organization (org admins only) +``` + +### SEE ALSO + +* [lacework compliance google](lacework_compliance_google.md) - Compliance for Google Cloud + diff --git a/cli/docs/lacework_generate_cloud-account_aws_controltower.md b/cli/docs/lacework_generate_cloud-account_aws_controltower.md new file mode 100644 index 000000000..260cf248d --- /dev/null +++ b/cli/docs/lacework_generate_cloud-account_aws_controltower.md @@ -0,0 +1,117 @@ +--- +title: "lacework generate cloud-account aws controltower" +slug: lacework_generate_cloud-account_aws_controltower +hide_title: true +--- + +## lacework generate cloud-account aws controltower + +Generate and/or execute Terraform code for ControlTower integration + +### Synopsis + +Use this command to generate Terraform code for deploying Lacework with Aws Cloudtrail and +ControlTower. + +By default, this command interactively prompts for the required information to set up the new cloud account. +In interactive mode, this command will: + +* Prompt for the required information to set up the integration +* Generate new Terraform code using the inputs +* Optionally, run the generated Terraform code: + * If Terraform is already installed, the version is verified as compatible for use + * If Terraform is not installed, or the version installed is not compatible, a new + version will be installed into a temporary location + * Once Terraform is detected or installed, the Terraform plan is executed + * The command prompts you with the outcome of the plan and allows you to view more + details or continue with Terraform apply + * If confirmed, Terraform apply runs, completing the setup of the cloud account + +This command can also be run in noninteractive mode. +See help output for more details on the parameter values required for Terraform code generation. + + +``` +lacework generate cloud-account aws controltower [flags] +``` + +### Options + +``` + --apply run terraform apply without executing plan or prompting + --audit_account string The audit account flag input in the format profile:region + -h, --help help for controltower + --iam_role_arn string specify the arn of the existing iam role + --iam_role_external_id string specify the external id of the existing iam role + --iam_role_name string specify the name of the existing iam role + --lacework_aws_account_id string the Lacework AWS root account id + --log_archive_account string The log archive account flag input in the format profile:region + --org_account_mapping string Org account mapping json string. Example: '{"default_lacework_account":"main", "mapping": [{ "aws_accounts": ["123456789011"], "lacework_account": "sub-account-1"}]}' + --output string location to write generated content + --prefix string specify the prefix that will be used at the beginning of every generated resource + --s3_bucket_arn string the S3 Bucket for consolidated CloudTrail + --sns_topic_arn string the SNS Topic + --sqs_queue_name string specify the name of the sqs queue +``` + +### Options inherited from parent commands + +``` + -a, --account string account subdomain of URL (i.e. .lacework.net) + --agentless enable agentless integration + --agentless_management_account_id string AWS management account ID for Agentless integration + --agentless_monitored_account_ids strings AWS monitored account IDs for Agentless integrations; may contain account IDs, OUs, or the organization root (e.g. 123456789000,ou-abcd-12345678,r-abcd) + --agentless_monitored_accounts strings AWS monitored accounts for Agentless integrations; value format must be : + --agentless_scanning_accounts strings AWS scanning accounts for Agentless integrations; value format must be : + -k, --api_key string access key id + -s, --api_secret string secret access key + --api_token string access token (replaces the use of api_key and api_secret) + --aws_assume_role string specify aws assume role + --aws_organization enable organization integration + --aws_profile string specify aws profile + --aws_region string specify aws region + --aws_subaccount strings configure an additional aws account; value format must be : + --bucket_encryption_enabled enable S3 bucket encryption when creating bucket (default true) + --bucket_name string specify bucket name when creating bucket + --bucket_sse_key_arn string specify existing KMS encryption key arn for bucket + --cloudtrail enable cloudtrail integration + --cloudtrail_name string specify name of cloudtrail integration + --cloudtrail_org_account_mapping string Org account mapping json string. Example: '{"default_lacework_account":"main", "mapping": [{ "aws_accounts": ["123456789011"], "lacework_account": "sub-account-1"}]}' + --config enable config integration + --config_cf_resource_prefix string specify Cloudformation resource prefix for Config organization integration + --config_lacework_access_key_id string specify AWS access key ID for Config organization integration + --config_lacework_account string specify lacework account for Config organization integration + --config_lacework_secret_key string specify AWS secret key for Config organization integration + --config_lacework_sub_account string specify lacework sub-account for Config organization integration + --config_organization_id string specify AWS organization ID for Config organization integration + --config_organization_units strings specify AWS organization units for Config organization integration + --consolidated_cloudtrail use consolidated trail + --controltower enable Control Tower integration + --controltower_audit_account string specify AWS Control Tower Audit account; value format must be : + --controltower_kms_key_arn string specify AWS Control Tower custom kMS key ARN + --controltower_log_archive_account string specify AWS Control Tower Log Archive account; value format must be : + --debug turn on debug logging + --existing_bucket_arn string specify existing cloudtrail S3 bucket ARN + --existing_iam_role_arn string specify existing iam role arn to use + --existing_iam_role_externalid string specify existing iam role external_id to use + --existing_iam_role_name string specify existing iam role name to use + --existing_sns_topic_arn string specify existing SNS topic arn + --json switch commands output from human-readable to json format + --nocache turn off caching + --nocolor turn off colors + --noninteractive turn off interactive mode (disable spinners, prompts, etc.) + --organization access organization level data sets (org admins only) + -p, --profile string switch between profiles configured at ~/.lacework.toml + --sns_topic_encryption_enabled enable encryption on SNS topic when creating one (default true) + --sns_topic_encryption_key_arn string specify existing KMS encryption key arn for SNS topic + --sns_topic_name string specify SNS topic name if creating new one + --sqs_encryption_enabled enable encryption on SQS queue when creating (default true) + --sqs_encryption_key_arn string specify existing KMS encryption key arn for SQS queue + --subaccount string sub-account name inside your organization (org admins only) + --use_s3_bucket_notification enable S3 bucket notifications +``` + +### SEE ALSO + +* [lacework generate cloud-account aws](lacework_generate_cloud-account_aws.md) - Generate and/or execute Terraform code for AWS integration + diff --git a/cli/docs/lacework_generate_cloud-account_oci.md b/cli/docs/lacework_generate_cloud-account_oci.md new file mode 100644 index 000000000..5ddc3e20d --- /dev/null +++ b/cli/docs/lacework_generate_cloud-account_oci.md @@ -0,0 +1,69 @@ +--- +title: "lacework generate cloud-account oci" +slug: lacework_generate_cloud-account_oci +hide_title: true +--- + +## lacework generate cloud-account oci + +Generate and/or execute Terraform code for OCI integration + +### Synopsis + +Use this command to generate Terraform code for deploying Lacework into an OCI tenant. + +By default, this command interactively prompts for the required information to setup the new cloud account. +In interactive mode, this command will: + +* Prompt for the required information to setup the integration +* Generate new Terraform code using the inputs +* Optionally, run the generated Terraform code: + * If Terraform is already installed, the version is verified as compatible for use + * If Terraform is not installed, or the version installed is not compatible, a new + version will be installed into a temporary location + * Once Terraform is detected or installed, Terraform plan will be executed + * The command will prompt with the outcome of the plan and allow to view more details + or continue with Terraform apply + * If confirmed, Terraform apply will be run, completing the setup of the cloud account + +This command can also be run in noninteractive mode. +See help output for more details on the parameter value(s) required for Terraform code generation. + + +``` +lacework generate cloud-account oci [flags] +``` + +### Options + +``` + --apply run terraform apply without executing plan or prompting + --config enable configuration integration + --config_name string specify name of configuration integration + -h, --help help for oci + --oci_user_email string specify the email address to associate with the integration OCI user + --output string location to write generated content (default is ~/lacework/oci) + --tenant_ocid string specify the OCID of the tenant to integrate +``` + +### Options inherited from parent commands + +``` + -a, --account string account subdomain of URL (i.e. .lacework.net) + -k, --api_key string access key id + -s, --api_secret string secret access key + --api_token string access token (replaces the use of api_key and api_secret) + --debug turn on debug logging + --json switch commands output from human-readable to json format + --nocache turn off caching + --nocolor turn off colors + --noninteractive turn off interactive mode (disable spinners, prompts, etc.) + --organization access organization level data sets (org admins only) + -p, --profile string switch between profiles configured at ~/.lacework.toml + --subaccount string sub-account name inside your organization (org admins only) +``` + +### SEE ALSO + +* [lacework generate cloud-account](lacework_generate_cloud-account.md) - Generate cloud integration IaC + diff --git a/integration/resource_groups_test.go b/integration/resource_groups_test.go index ca8e40193..b3947f23b 100644 --- a/integration/resource_groups_test.go +++ b/integration/resource_groups_test.go @@ -38,7 +38,7 @@ func createResourceGroup(typ string, uid string) (string, error) { return "", errors.Wrap(err, "error serializing query template") } - var testResourceGroup api.ResourceGroupDataWithQuery = api.ResourceGroupDataWithQuery{ + var testResourceGroup api.ResourceGroupData = api.ResourceGroupData{ Name: fmt.Sprintf("CLI_TestCreateResourceGroup_%s", iType.String()+"_"+uid), Type: iType.String(), Query: &testQuery, @@ -61,17 +61,17 @@ func createResourceGroup(typ string, uid string) (string, error) { return "", errors.New("non-zero exit code") } - var resourceGroupV2Response api.ResourceGroupV2Response - err = json.Unmarshal(out.Bytes(), &resourceGroupV2Response) + var resourceGroupResponse api.ResourceGroupResponse + err = json.Unmarshal(out.Bytes(), &resourceGroupResponse) if err != nil { return "", err } - return resourceGroupV2Response.Data.ID(), nil + return resourceGroupResponse.Data.ID(), nil } func popResourceGroup() (string, error) { type resourceGroup struct { - Id string `json:"resource_guid"` + Id string `json:"resourceGroupGuid"` } type listResourceGroupsResponse struct { ResourceGroups []resourceGroup `json:"resource_groups"` @@ -119,7 +119,7 @@ func TestResourceGroupList(t *testing.T) { // list (output json) out, err, exitcode = LaceworkCLIWithTOMLConfig("resource-group", "list", "--json") - assert.Contains(t, out.String(), `"resource_guid"`) + assert.Contains(t, out.String(), `"resourceGroupGuid"`) assert.Contains(t, out.String(), `"type": "AWS"`) assert.Empty(t, err.String(), "STDERR should be empty") assert.Equal(t, 0, exitcode, "EXITCODE is not the expected one") @@ -148,7 +148,7 @@ func TestResourceGroupShow(t *testing.T) { t.Run("JSON Output", func(t *testing.T) { out, err, exitcode := LaceworkCLIWithTOMLConfig("resource-group", "show", resourceGroupShowID, "--json") - assert.Contains(t, out.String(), `"resource_guid"`) + assert.Contains(t, out.String(), `"resourceGroupGuid"`) assert.Contains(t, out.String(), `"`+resourceGroupShowID+`"`) assert.Empty(t, err.String(), "STDERR should be empty") assert.Equal(t, 0, exitcode, "EXITCODE is not the expected one") @@ -167,7 +167,7 @@ func TestResourceGroupDelete(t *testing.T) { // test each RGv2 type against its default template for i := range api.ResourceGroupTypes { switch i { - case api.NoneResourceGroup, api.LwAccountResourceGroup: + case api.NoneResourceGroup: // these resource groups are not applicable continue default: