Skip to content

Commit

Permalink
gitops abac rules (#119)
Browse files Browse the repository at this point in the history
## What
- Add Gitops ABAC Rule resource
## Why
For creating rules for gitops entities
## Notes

## Checklist

* [x] _I have read
[CONTRIBUTING.md](https://github.com/codefresh-io/terraform-provider-codefresh/blob/master/CONTRIBUTING.md)._
* [x] _I have [allowed changes to my fork to be
made](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)._
* [x] _I have added tests, assuming new tests are warranted_.
* [x] _I understand that the `/test` comment will be ignored by the CI
trigger [unless it is made by a repo admin or
collaborator](https://codefresh.io/docs/docs/pipelines/triggers/git-triggers/#support-for-building-pull-requests-from-forks)._
  • Loading branch information
andrii-codefresh authored Jun 30, 2023
1 parent 2038cd8 commit ab97b85
Show file tree
Hide file tree
Showing 18 changed files with 832 additions and 4 deletions.
4 changes: 3 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Client struct {
Token string
TokenHeader string
Host string
HostV2 string
Client *http.Client
}

Expand All @@ -29,12 +30,13 @@ type RequestOptions struct {
// NewClient returns a new client configured to communicate on a server with the
// given hostname and to send an Authorization Header with the value of
// token
func NewClient(hostname string, token string, tokenHeader string) *Client {
func NewClient(hostname string, hostnameV2 string, token string, tokenHeader string) *Client {
if tokenHeader == "" {
tokenHeader = "Authorization"
}
return &Client{
Host: hostname,
HostV2: hostnameV2,
Token: token,
TokenHeader: tokenHeader,
Client: &http.Client{},
Expand Down
206 changes: 206 additions & 0 deletions client/gitops_abac_rules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package client

import (
"fmt"
)

type EntityAbacAttribute struct {
Name string `json:"name"`
Key string `json:"key,omitempty"`
Value string `json:"value"`
}

// GitopsAbacRule spec
type GitopsAbacRule struct {
ID string `json:"id,omitempty"`
AccountId string `json:"accountId,omitempty"`
EntityType string `json:"entityType"`
Teams []string `json:"teams"`
Tags []string `json:"tags,omitempty"`
Actions []string `json:"actions"`
Attributes []EntityAbacAttribute `json:"attributes"`
}

type GitopsAbacRulesListResponse struct {
Data struct {
AbacRules []GitopsAbacRule `json:"abacRules"`
} `json:"data"`
}

type GitopsAbacRuleResponse struct {
Data struct {
AbacRule GitopsAbacRule `json:"abacRule,omitempty"`
CreateAbacRule GitopsAbacRule `json:"createAbacRule,omitempty"`
RemoveAbacRule GitopsAbacRule `json:"removeAbacRule,omitempty"`
} `json:"data"`
}

func (client *Client) GetAbacRulesList(entityType string) ([]GitopsAbacRule, error) {
request := GraphQLRequest{
Query: `
query AbacRules($accountId: String!, $entityType: AbacEntityValues!) {
abacRules(accountId: $accountId, entityType: $entityType) {
id
accountId
entityType
teams
tags
actions
attributes {
name
key
value
}
}
}
`,
Variables: map[string]interface{}{
"accountId": "",
"entityType": entityType,
},
}

response, err := client.SendGqlRequest(request)
if err != nil {
fmt.Println("Error:", err)
return nil, err
}

var gitopsAbacRulesResponse GitopsAbacRulesListResponse
err = DecodeGraphQLResponseInto(response, &gitopsAbacRulesResponse)
if err != nil {
return nil, err
}

return gitopsAbacRulesResponse.Data.AbacRules, nil
}

// GetAbacRuleByID -
func (client *Client) GetAbacRuleByID(id string) (*GitopsAbacRule, error) {
request := GraphQLRequest{
Query: `
query AbacRule($accountId: String!, $id: ID!) {
abacRule(accountId: $accountId, id: $id) {
id
accountId
entityType
teams
tags
actions
attributes {
name
key
value
}
}
}
`,
Variables: map[string]interface{}{
"accountId": "",
"id": id,
},
}

response, err := client.SendGqlRequest(request)
if err != nil {
fmt.Println("Error:", err)
return nil, err
}

var gitopsAbacRuleResponse GitopsAbacRuleResponse
err = DecodeGraphQLResponseInto(response, &gitopsAbacRuleResponse)
if err != nil {
return nil, err
}

return &gitopsAbacRuleResponse.Data.AbacRule, nil
}

func (client *Client) CreateAbacRule(gitopsAbacRule *GitopsAbacRule) (*GitopsAbacRule, error) {

newAbacRule := &GitopsAbacRule{
EntityType: gitopsAbacRule.EntityType,
Teams: gitopsAbacRule.Teams,
Tags: gitopsAbacRule.Tags,
Actions: gitopsAbacRule.Actions,
Attributes: gitopsAbacRule.Attributes,
}

request := GraphQLRequest{
Query: `
mutation CreateAbacRule($accountId: String!, $createAbacRuleInput: CreateAbacRuleInput!) {
createAbacRule(accountId: $accountId, createAbacRuleInput: $createAbacRuleInput) {
id
accountId
entityType
teams
tags
actions
attributes {
name
key
value
}
}
}
`,
Variables: map[string]interface{}{
"accountId": "",
"createAbacRuleInput": newAbacRule,
},
}

response, err := client.SendGqlRequest(request)
if err != nil {
fmt.Println("Error:", err)
return nil, err
}

var gitopsAbacRuleResponse GitopsAbacRuleResponse
err = DecodeGraphQLResponseInto(response, &gitopsAbacRuleResponse)
if err != nil {
return nil, err
}

return &gitopsAbacRuleResponse.Data.CreateAbacRule, nil
}

func (client *Client) DeleteAbacRule(id string) (*GitopsAbacRule, error) {
request := GraphQLRequest{
Query: `
mutation RemoveAbacRule($accountId: String!, $id: ID!) {
removeAbacRule(accountId: $accountId, id: $id) {
id
accountId
entityType
teams
tags
actions
attributes {
name
key
value
}
}
}
`,
Variables: map[string]interface{}{
"accountId": "",
"id": id,
},
}

response, err := client.SendGqlRequest(request)
if err != nil {
fmt.Println("Error:", err)
return nil, err
}

var gitopsAbacRuleResponse GitopsAbacRuleResponse
err = DecodeGraphQLResponseInto(response, &gitopsAbacRuleResponse)
if err != nil {
return nil, err
}

return &gitopsAbacRuleResponse.Data.RemoveAbacRule, nil
}
57 changes: 57 additions & 0 deletions client/gql_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package client

import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
)

// GraphQLRequest GraphQL query
type GraphQLRequest struct {
Query string `json:"query"`
Variables map[string]interface{} `json:"variables,omitempty"`
}

func (client *Client) SendGqlRequest(request GraphQLRequest) ([]byte, error) {
jsonRequest, err := json.Marshal(request)
if err != nil {
return nil, err
}

req, err := http.NewRequest("POST", client.HostV2, bytes.NewBuffer(jsonRequest))
if err != nil {
return nil, err
}

tokenHeader := client.TokenHeader
if tokenHeader == "" {
tokenHeader = "Authorization"
}
req.Header.Set(tokenHeader, client.Token)
req.Header.Set("Content-Type", "application/json; charset=utf-8")

httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode >= 400 {
bodyBytes, _ := ioutil.ReadAll(resp.Body)
return nil, errors.New(resp.Status + " " + string(bodyBytes))
}
defer resp.Body.Close()

var buf bytes.Buffer
_, err = buf.ReadFrom(resp.Body)
if err != nil {
return nil, err
}

return buf.Bytes(), nil
}

func DecodeGraphQLResponseInto(body []byte, target interface{}) error {
return json.Unmarshal(body, target)
}
2 changes: 1 addition & 1 deletion client/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (client *Client) AddUserToTeamByAdmin(userID string, accountID string, team
return err
}
// new Client for accountAdmin
accountAdminClient := NewClient(client.Host, accountAdminToken, "x-access-token")
accountAdminClient := NewClient(client.Host, "", accountAdminToken, "x-access-token")
usersTeam, err := accountAdminClient.GetTeamByName(team)
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions codefresh/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ const (
ENV_CODEFRESH_PLUGIN_DEBUG = "CODEFRESH_PLUGIN_DEBUG"
ENV_CODEFRESH_PLUGIN_ADDR = "CODEFRESH_PLUGIN_ADDR"
ENV_CODEFRESH_API_URL = "CODEFRESH_API_URL"
ENV_CODEFRESH_API2_URL = "CODEFRESH_API2_URL"
ENV_CODEFRESH_API_KEY = "CODEFRESH_API_KEY"
DEFAULT_CODEFRESH_API_URL = "https://g.codefresh.io/api"
DEFAULT_CODEFRESH_API2_URL = "https://g.codefresh.io/2.0/api/graphql"
DEFAULT_CODEFRESH_PLUGIN_ADDR = "registry.terraform.io/-/codefresh"
)
15 changes: 14 additions & 1 deletion codefresh/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ func Provider() *schema.Provider {
},
Description: fmt.Sprintf("The Codefresh API URL. Defaults to `%s`. Can also be set using the `%s` environment variable.", DEFAULT_CODEFRESH_API_URL, ENV_CODEFRESH_API_URL),
},
"api_url_v2": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: func() (interface{}, error) {
if url := os.Getenv(ENV_CODEFRESH_API2_URL); url != "" {
return url, nil
}
return DEFAULT_CODEFRESH_API2_URL, nil
},
Description: fmt.Sprintf("The Codefresh gitops API URL. Defaults to `%s`. Can also be set using the `%s` environment variable.", DEFAULT_CODEFRESH_API2_URL, ENV_CODEFRESH_API2_URL),
},
"token": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -55,6 +66,7 @@ func Provider() *schema.Provider {
"codefresh_step_types": resourceStepTypes(),
"codefresh_user": resourceUser(),
"codefresh_team": resourceTeam(),
"codefresh_abac_rules": resourceGitopsAbacRule(),
},
ConfigureFunc: configureProvider,
}
Expand All @@ -63,9 +75,10 @@ func Provider() *schema.Provider {
func configureProvider(d *schema.ResourceData) (interface{}, error) {

apiURL := d.Get("api_url").(string)
apiURLV2 := d.Get("api_url_v2").(string)
token := d.Get("token").(string)
if token == "" {
token = os.Getenv(ENV_CODEFRESH_API_KEY)
}
return cfClient.NewClient(apiURL, token, ""), nil
return cfClient.NewClient(apiURL, apiURLV2, token, ""), nil
}
Loading

0 comments on commit ab97b85

Please sign in to comment.