Skip to content

Commit a839e96

Browse files
feat: rules commands (#228)
1 parent e57b9d7 commit a839e96

File tree

11 files changed

+878
-7
lines changed

11 files changed

+878
-7
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ on:
1414
- examples/**
1515

1616
env:
17-
GORELEASER_VERSION: v2.4.1
17+
GORELEASER_VERSION: v2.4.4
1818
jobs:
1919
lint:
2020
name: Lint Code

docs/30_commands.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,63 @@ Available flags for the command:
431431
- `--context`, to specify a different context from the currently selected one
432432
- `--company-id`, to set the ID of the desired Company
433433

434+
### rules
435+
436+
Rules command helps you manage different rules for configuration update for the whole Company or specific Projects.
437+
438+
:::tip
439+
This feature is currently in closed preview and may be subject to breaking changes, reach out to your Mia-Platorm referent
440+
if you are interested in use it.
441+
:::
442+
443+
#### list
444+
445+
List available rules for the Company or for a specific Project.
446+
447+
Usage:
448+
449+
```sh
450+
miactl company rules list [flags]
451+
```
452+
453+
Available flags for the command:
454+
455+
- `--company-id`, the id of the Company
456+
- `--project-id`, the id of the Project (if provided the command will print avilable rules for the project,
457+
together with the rules inherited from the Company)
458+
459+
#### update
460+
461+
Helps you update rules for a Company or for a specific Project
462+
463+
Usage:
464+
465+
```sh
466+
miactl company rules update [flags]
467+
```
468+
469+
Available flags for the command:
470+
471+
- `--company-id`, the id of the Company
472+
- `--project-id`, the id of the Project (if provided the command will update the rules for the specified Project only)
473+
- `-f`, path to the file where the rules are saved
474+
475+
<details>
476+
<summary>File example</summary>
477+
478+
```json
479+
[
480+
{
481+
"roleIds": ["developer"],
482+
"disallowedRuleSet": [
483+
{"ruleId": "endpoint.security.edit"}
484+
]
485+
}
486+
]
487+
```
488+
489+
</details>
490+
434491
## project
435492

436493
This command allows you to manage `miactl` Projects.

internal/cmd/company.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,9 @@ func CompanyCmd(options *clioptions.CLIOptions) *cobra.Command {
3838
company.IAMCmd(options),
3939
)
4040

41+
cmd.AddCommand(
42+
company.RulesCmd(options),
43+
)
44+
4145
return cmd
4246
}

internal/cmd/company/rules.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright Mia srl
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package company
17+
18+
import (
19+
"github.com/mia-platform/miactl/internal/clioptions"
20+
"github.com/mia-platform/miactl/internal/cmd/company/rules"
21+
"github.com/spf13/cobra"
22+
)
23+
24+
func RulesCmd(o *clioptions.CLIOptions) *cobra.Command {
25+
cmd := &cobra.Command{
26+
Use: "rules",
27+
Short: "Manage Company rules",
28+
Long: ``,
29+
}
30+
31+
// add cmd flags
32+
flags := cmd.PersistentFlags()
33+
o.AddConnectionFlags(flags)
34+
o.AddContextFlags(flags)
35+
o.AddCompanyFlags(flags)
36+
o.AddProjectFlags(flags)
37+
38+
cmd.AddCommand(
39+
rules.ListCmd(o),
40+
rules.UpdateRules(o),
41+
)
42+
43+
return cmd
44+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// Copyright Mia srl
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package rules
17+
18+
import (
19+
"context"
20+
"encoding/json"
21+
"fmt"
22+
"net/http"
23+
24+
"github.com/mia-platform/miactl/internal/client"
25+
"github.com/mia-platform/miactl/internal/resources"
26+
rulesentities "github.com/mia-platform/miactl/internal/resources/rules"
27+
)
28+
29+
const (
30+
tenantsAPIPrefix = "/api/backend/tenants/"
31+
projectsAPIPrefix = "/api/backend/projects/"
32+
getProjectAPIFmt = projectsAPIPrefix + "%s"
33+
patchTenantRulesFmt = tenantsAPIPrefix + "%s/rules"
34+
patchProjectRulesFmt = projectsAPIPrefix + "%s/rules"
35+
)
36+
37+
type IRulesClient interface {
38+
ListTenantRules(ctx context.Context, companyID string) ([]*rulesentities.SaveChangesRules, error)
39+
ListProjectRules(ctx context.Context, projectID string) ([]*rulesentities.ProjectSaveChangesRules, error)
40+
UpdateTenantRules(ctx context.Context, companyID string, rules []*rulesentities.SaveChangesRules) error
41+
UpdateProjectRules(ctx context.Context, projectID string, rules []*rulesentities.SaveChangesRules) error
42+
}
43+
44+
type rulesClient struct {
45+
c *client.APIClient
46+
}
47+
48+
func New(c *client.APIClient) IRulesClient {
49+
return &rulesClient{c: c}
50+
}
51+
52+
func (e *rulesClient) ListTenantRules(ctx context.Context, companyID string) ([]*rulesentities.SaveChangesRules, error) {
53+
request := e.c.Get().APIPath(tenantsAPIPrefix)
54+
request.SetParam("search", companyID)
55+
56+
resp, err := request.Do(ctx)
57+
if err != nil {
58+
return nil, fmt.Errorf("error executing request: %w", err)
59+
}
60+
if err := e.assertSuccessResponse(resp); err != nil {
61+
return nil, err
62+
}
63+
64+
var tenants []resources.Company
65+
if err := resp.ParseResponse(&tenants); err != nil {
66+
return nil, fmt.Errorf("error parsing response body: %w", err)
67+
}
68+
if len(tenants) == 0 {
69+
return nil, fmt.Errorf("Company %s not found", companyID)
70+
}
71+
var tenant *resources.Company
72+
for _, possible := range tenants {
73+
if possible.TenantID == companyID {
74+
tenant = &possible
75+
break
76+
}
77+
}
78+
if tenant == nil {
79+
return nil, fmt.Errorf("Company %s not found", companyID)
80+
}
81+
if len(tenant.ConfigurationManagement.SaveChangesRules) == 0 {
82+
return []*rulesentities.SaveChangesRules{}, nil
83+
}
84+
85+
return tenant.ConfigurationManagement.SaveChangesRules, nil
86+
}
87+
88+
func (e *rulesClient) ListProjectRules(ctx context.Context, projectID string) ([]*rulesentities.ProjectSaveChangesRules, error) {
89+
request := e.c.Get().APIPath(fmt.Sprintf(getProjectAPIFmt, projectID))
90+
request.SetParam("withTenant", "true")
91+
92+
resp, err := request.Do(ctx)
93+
if err != nil {
94+
return nil, fmt.Errorf("error executing request: %w", err)
95+
}
96+
if err := e.assertSuccessResponse(resp); err != nil {
97+
return nil, err
98+
}
99+
100+
var project resources.Project
101+
if err := resp.ParseResponse(&project); err != nil {
102+
return nil, fmt.Errorf("error parsing response body: %w", err)
103+
}
104+
105+
if len(project.ConfigurationManagement.SaveChangesRules) == 0 {
106+
return []*rulesentities.ProjectSaveChangesRules{}, nil
107+
}
108+
109+
return project.ConfigurationManagement.SaveChangesRules, nil
110+
}
111+
112+
type UpdateRequestBody struct {
113+
ConfigurationManagement *resources.ConfigurationManagement `json:"configurationManagement"`
114+
}
115+
116+
func (e *rulesClient) UpdateTenantRules(ctx context.Context, companyID string, rules []*rulesentities.SaveChangesRules) error {
117+
requestBody := UpdateRequestBody{
118+
ConfigurationManagement: &resources.ConfigurationManagement{
119+
SaveChangesRules: rules,
120+
},
121+
}
122+
bodyData, err := json.Marshal(requestBody)
123+
if err != nil {
124+
return err
125+
}
126+
127+
request := e.c.Patch().
128+
APIPath(
129+
fmt.Sprintf(patchTenantRulesFmt, companyID),
130+
).
131+
Body(bodyData)
132+
133+
resp, err := request.Do(ctx)
134+
if err != nil {
135+
return fmt.Errorf("error executing request: %w", err)
136+
}
137+
if err := e.assertSuccessResponse(resp); err != nil {
138+
return err
139+
}
140+
141+
return nil
142+
}
143+
144+
func (e *rulesClient) UpdateProjectRules(ctx context.Context, projectID string, rules []*rulesentities.SaveChangesRules) error {
145+
requestBody := UpdateRequestBody{
146+
ConfigurationManagement: &resources.ConfigurationManagement{
147+
SaveChangesRules: rules,
148+
},
149+
}
150+
bodyData, err := json.Marshal(requestBody)
151+
if err != nil {
152+
return err
153+
}
154+
155+
request := e.c.Patch().
156+
APIPath(
157+
fmt.Sprintf(patchProjectRulesFmt, projectID),
158+
).
159+
Body(bodyData)
160+
161+
resp, err := request.Do(ctx)
162+
if err != nil {
163+
return fmt.Errorf("error executing request: %w", err)
164+
}
165+
if err := e.assertSuccessResponse(resp); err != nil {
166+
return err
167+
}
168+
169+
return nil
170+
}
171+
172+
func (e *rulesClient) assertSuccessResponse(resp *client.Response) error {
173+
if resp.StatusCode() >= http.StatusBadRequest {
174+
return resp.Error()
175+
}
176+
return nil
177+
}

0 commit comments

Comments
 (0)