Skip to content

Commit

Permalink
Port 4554 terraform add support in scorecards (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
dvirsegev authored Aug 24, 2023
1 parent 738ab03 commit 88a1657
Show file tree
Hide file tree
Showing 12 changed files with 897 additions and 1 deletion.
63 changes: 63 additions & 0 deletions docs/resources/port_scorecard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "port_scorecard Resource - terraform-provider-port-labs"
subcategory: ""
description: |-
scorecard resource
---

# port_scorecard (Resource)

scorecard resource

<!-- schema generated by tfplugindocs -->

## Schema

### Required

- `blueprint` (String) The blueprint of the scorecard
- `identifier` (String) The identifier of the scorecard
- `rules` (Attributes List) The rules of the scorecard (see [below for nested schema](#nestedatt--rules))
- `title` (String) The title of the scorecard

### Read-Only

- `created_at` (String) The creation date of the scorecard
- `created_by` (String) The creator of the scorecard
- `id` (String) The ID of this resource.
- `updated_at` (String) The last update date of the scorecard
- `updated_by` (String) The last updater of the scorecard

<a id="nestedatt--rules"></a>

### Nested Schema for `rules`

Required:

- `identifier` (String) The identifier of the rule
- `level` (String) The level of the rule
- `query` (Attributes) The query of the rule (see [below for nested schema](#nestedatt--rules--query))
- `title` (String) The title of the rule

<a id="nestedatt--rules--query"></a>

### Nested Schema for `rules.query`

Required:

- `combinator` (String) The combinator of the query
- `conditions` (Attributes List) The conditions of the query (see [below for nested schema](#nestedatt--rules--query--conditions))

<a id="nestedatt--rules--query--conditions"></a>

### Nested Schema for `rules.query.conditions`

Required:

- `operator` (String) The operator of the condition
- `property` (String) The property of the condition

Optional:

- `value` (String) The value of the condition
2 changes: 2 additions & 0 deletions docs/resources/port_webhook.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Webhook resource
- `id` (String) The ID of this resource.
- `updated_at` (String) The last update date of the webhook
- `updated_by` (String) The last updater of the webhook
- `url` (String) The url of the webhook
- `webhook_key` (String) The webhook key of the webhook

<a id="nestedatt--mappings"></a>
### Nested Schema for `mappings`
Expand Down
31 changes: 31 additions & 0 deletions internal/cli/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,32 @@ type (
Many *bool `json:"many,omitempty"`
}

Scorecard struct {
Meta
Identifier string `json:"identifier,omitempty"`
Title string `json:"title,omitempty"`
Blueprint string `json:"blueprint,omitempty"`
Rules []Rule `json:"rules,omitempty"`
}

Rule struct {
Identifier string `json:"identifier,omitempty"`
Title string `json:"title,omitempty"`
Level string `json:"level,omitempty"`
Query Query `json:"query,omitempty"`
}

Query struct {
Combinator string `json:"combinator,omitempty"`
Conditions []Condition `json:"conditions,omitempty"`
}

Condition struct {
Property string `json:"property,omitempty"`
Operator string `json:"operator,omitempty"`
Value *string `json:"value,omitempty"`
}

Webhook struct {
Meta
Identifier string `json:"identifier,omitempty"`
Expand Down Expand Up @@ -240,6 +266,7 @@ type PortBody struct {
Blueprint Blueprint `json:"blueprint"`
Action Action `json:"action"`
Integration Webhook `json:"integration"`
Scorecard Scorecard `json:"Scorecard"`
}

type PortProviderModel struct {
Expand All @@ -248,3 +275,7 @@ type PortProviderModel struct {
Token types.String `tfsdk:"token"`
BaseUrl types.String `tfsdk:"base_url"`
}

type PortBodyDelete struct {
Ok bool `json:"ok"`
}
92 changes: 92 additions & 0 deletions internal/cli/scorecard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package cli

import (
"context"
"encoding/json"
"fmt"
)

func (c *PortClient) ReadScorecard(ctx context.Context, blueprintID string, scorecardID string) (*Scorecard, int, error) {
pb := &PortBody{}
url := "v1/blueprints/{blueprint_identifier}/scorecards/{scorecard_identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetResult(pb).
SetPathParam("blueprint_identifier", blueprintID).
SetPathParam("scorecard_identifier", scorecardID).
Get(url)
if err != nil {
return nil, resp.StatusCode(), err
}
if !pb.OK {
return nil, resp.StatusCode(), fmt.Errorf("failed to read scorecard, got: %s", resp.Body())
}
return &pb.Scorecard, resp.StatusCode(), nil
}

func (c *PortClient) CreateScorecard(ctx context.Context, blueprintID string, scorecard *Scorecard) (*Scorecard, error) {
url := "v1/blueprints/{blueprint_identifier}/scorecards"
resp, err := c.Client.R().
SetBody(scorecard).
SetContext(ctx).
SetPathParam("blueprint_identifier", blueprintID).
Post(url)
if err != nil {
return nil, err
}
var pb PortBody
err = json.Unmarshal(resp.Body(), &pb)
if err != nil {
return nil, err
}
if !pb.OK {
return nil, fmt.Errorf("failed to create scorecard, got: %s", resp.Body())
}
return &pb.Scorecard, nil
}

func (c *PortClient) UpdateScorecard(ctx context.Context, blueprintID string, scorecardId string, scorecard *Scorecard) (*Scorecard, error) {
url := "v1/blueprints/{blueprint_identifier}/scorecards/{scorecard_identifier}"
resp, err := c.Client.R().
SetBody(scorecard).
SetContext(ctx).
SetPathParam("blueprint_identifier", blueprintID).
SetPathParam("scorecard_identifier", scorecardId).
Put(url)
if err != nil {
return nil, err
}
var pb PortBody
err = json.Unmarshal(resp.Body(), &pb)
if err != nil {
return nil, err
}
if !pb.OK {
return nil, fmt.Errorf("failed to update scorecard, got: %s", resp.Body())
}
return &pb.Scorecard, nil
}

func (c *PortClient) DeleteScorecard(ctx context.Context, blueprintID string, scorecardID string) error {
url := "v1/blueprints/{blueprint_identifier}/scorecards/{scorecard_identifier}"
resp, err := c.Client.R().
SetContext(ctx).
SetHeader("Accept", "application/json").
SetPathParam("blueprint_identifier", blueprintID).
SetPathParam("scorecard_identifier", scorecardID).
Delete(url)
if err != nil {
return err
}
var pb PortBodyDelete
err = json.Unmarshal(resp.Body(), &pb)
if err != nil {
return err
}

if !(pb.Ok) {
return fmt.Errorf("failed to delete scorecard. got:\n%s", string(resp.Body()))
}
return nil
}
2 changes: 1 addition & 1 deletion port/action/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (r *ActionResource) Read(ctx context.Context, req resource.ReadRequest, res
}

blueprintIdentifier := state.Blueprint.ValueString()
a, statusCode, err := r.portClient.ReadAction(ctx, state.Blueprint.ValueString(), state.Identifier.ValueString())
a, statusCode, err := r.portClient.ReadAction(ctx, blueprintIdentifier, state.Identifier.ValueString())
if err != nil {
if statusCode == 404 {
resp.State.RemoveResource(ctx)
Expand Down
35 changes: 35 additions & 0 deletions port/scorecard/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package scorecard

import (
"github.com/hashicorp/terraform-plugin-framework/types"
)

type Condition struct {
Operator types.String `tfsdk:"operator"`
Property types.String `tfsdk:"property"`
Value types.String `tfsdk:"value"`
}

type Query struct {
Combinator types.String `tfsdk:"combinator"`
Conditions []Condition `tfsdk:"conditions"`
}

type Rule struct {
Identifier types.String `tfsdk:"identifier"`
Title types.String `tfsdk:"title"`
Level types.String `tfsdk:"level"`
Query *Query `tfsdk:"query"`
}

type ScorecardModel struct {
ID types.String `tfsdk:"id"`
Identifier types.String `tfsdk:"identifier"`
Blueprint types.String `tfsdk:"blueprint"`
Title types.String `tfsdk:"title"`
Rules []Rule `tfsdk:"rules"`
CreatedAt types.String `tfsdk:"created_at"`
CreatedBy types.String `tfsdk:"created_by"`
UpdatedAt types.String `tfsdk:"updated_at"`
UpdatedBy types.String `tfsdk:"updated_by"`
}
50 changes: 50 additions & 0 deletions port/scorecard/refreshScorecardState.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package scorecard

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/port-labs/terraform-provider-port-labs/internal/cli"
"github.com/port-labs/terraform-provider-port-labs/internal/flex"
)

func refreshScorecardState(ctx context.Context, state *ScorecardModel, s *cli.Scorecard, blueprintIdentifier string) {
state.ID = types.StringValue(fmt.Sprintf("%s:%s", blueprintIdentifier, s.Identifier))
state.Identifier = types.StringValue(s.Identifier)
state.Blueprint = types.StringValue(blueprintIdentifier)
state.Title = types.StringValue(s.Title)
state.CreatedAt = types.StringValue(s.CreatedAt.String())
state.CreatedBy = types.StringValue(s.CreatedBy)
state.UpdatedAt = types.StringValue(s.UpdatedAt.String())
state.UpdatedBy = types.StringValue(s.UpdatedBy)

stateRules := []Rule{}
for _, rule := range s.Rules {
stateRule := &Rule{
Title: types.StringValue(rule.Title),
Level: types.StringValue(rule.Level),
Identifier: types.StringValue(rule.Identifier),
}
stateQuery := &Query{
Combinator: types.StringValue(rule.Query.Combinator),
}
stateConditions := []Condition{}
for _, condition := range rule.Query.Conditions {
stateCondition := &Condition{
Operator: types.StringValue(condition.Operator),
Property: types.StringValue(condition.Property),
Value: flex.GoStringToFramework(condition.Value),
}
stateConditions = append(stateConditions, *stateCondition)
}
stateQuery.Conditions = stateConditions

stateRule.Query = stateQuery

stateRules = append(stateRules, *stateRule)
}

state.Rules = stateRules

}
Loading

0 comments on commit 88a1657

Please sign in to comment.