diff --git a/docs/resources/policy.md b/docs/resources/policy.md
index 0ddcf26..dffc315 100644
--- a/docs/resources/policy.md
+++ b/docs/resources/policy.md
@@ -30,6 +30,7 @@ description: |-
- `environment_progression` (Block List) Environment progression rules (see [below for nested schema](#nestedblock--environment_progression))
- `gradual_rollout` (Block List) Gradual rollout rules (see [below for nested schema](#nestedblock--gradual_rollout))
- `metadata` (Map of String) The metadata of the policy
+- `plan_validation_opa` (Block List) OPA-based plan validation rules. Each rule must define a `deny` rule set following the Conftest convention. (see [below for nested schema](#nestedblock--plan_validation_opa))
- `priority` (Number) The priority of the policy (higher is evaluated first)
- `verification` (Block List) Verification rules (see [below for nested schema](#nestedblock--verification))
- `version_cooldown` (Block List) Version cooldown rules (see [below for nested schema](#nestedblock--version_cooldown))
@@ -120,6 +121,24 @@ Read-Only:
- `id` (String) Rule ID
+
+### Nested Schema for `plan_validation_opa`
+
+Required:
+
+- `name` (String) Human-readable rule name; used in check output to identify which rule produced a violation.
+- `rego` (String) Rego source code. Follows Conftest conventions for emitting violations.
+
+Optional:
+
+- `description` (String) Optional human-readable explanation of the rule.
+
+Read-Only:
+
+- `created_at` (String) Rule creation timestamp
+- `id` (String) Rule ID
+
+
### Nested Schema for `verification`
diff --git a/internal/api/client.gen.go b/internal/api/client.gen.go
index cdc506c..950fed8 100644
--- a/internal/api/client.gen.go
+++ b/internal/api/client.gen.go
@@ -248,8 +248,14 @@ type CreateDeploymentRequest struct {
// CreateDeploymentVersionRequest defines model for CreateDeploymentVersionRequest.
type CreateDeploymentVersionRequest struct {
- Config *map[string]interface{} `json:"config,omitempty"`
- CreatedAt *time.Time `json:"createdAt,omitempty"`
+ Config *map[string]interface{} `json:"config,omitempty"`
+ CreatedAt *time.Time `json:"createdAt,omitempty"`
+
+ // Dependencies Map of dependency deployment ID to a CEL version selector evaluated against that deployment's current release on the same resource. Inserted atomically with the version so reconciliation cannot fire before edges are attached.
+ Dependencies *map[string]struct {
+ // VersionSelector CEL expression evaluated against the dependency deployment's current release version on the same resource.
+ VersionSelector string `json:"versionSelector"`
+ } `json:"dependencies,omitempty"`
JobAgentConfig *map[string]interface{} `json:"jobAgentConfig,omitempty"`
Metadata *map[string]string `json:"metadata,omitempty"`
Name string `json:"name"`
@@ -289,6 +295,7 @@ type CreatePolicyRule struct {
DeploymentWindow *DeploymentWindowRule `json:"deploymentWindow,omitempty"`
EnvironmentProgression *EnvironmentProgressionRule `json:"environmentProgression,omitempty"`
GradualRollout *GradualRolloutRule `json:"gradualRollout,omitempty"`
+ PlanValidationOpa *PlanValidationOpaRule `json:"planValidationOpa,omitempty"`
Retry *RetryRule `json:"retry,omitempty"`
Verification *VerificationRule `json:"verification,omitempty"`
VersionCooldown *VersionCooldownRule `json:"versionCooldown,omitempty"`
@@ -534,6 +541,15 @@ type DeploymentVersion struct {
Tag string `json:"tag"`
}
+// DeploymentVersionDependency defines model for DeploymentVersionDependency.
+type DeploymentVersionDependency struct {
+ DependencyDeploymentId string `json:"dependencyDeploymentId"`
+ DeploymentVersionId string `json:"deploymentVersionId"`
+
+ // VersionSelector CEL expression evaluated against the dependency deployment's current release version on the same resource.
+ VersionSelector string `json:"versionSelector"`
+}
+
// DeploymentVersionStatus defines model for DeploymentVersionStatus.
type DeploymentVersionStatus string
@@ -778,6 +794,17 @@ type ObjectValue struct {
Object map[string]interface{} `json:"object"`
}
+// PlanValidationOpaRule defines model for PlanValidationOpaRule.
+type PlanValidationOpaRule struct {
+ Description *string `json:"description,omitempty"`
+
+ // Name Human-readable rule name; used in check output to identify which rule produced a violation.
+ Name string `json:"name"`
+
+ // Rego Rego v1 source code. Must define a `deny` rule set following the Conftest convention (deny contains msg if { ... }).
+ Rego string `json:"rego"`
+}
+
// Policy defines model for Policy.
type Policy struct {
CreatedAt string `json:"createdAt"`
@@ -805,6 +832,7 @@ type PolicyRule struct {
EnvironmentProgression *EnvironmentProgressionRule `json:"environmentProgression,omitempty"`
GradualRollout *GradualRolloutRule `json:"gradualRollout,omitempty"`
Id string `json:"id"`
+ PlanValidationOpa *PlanValidationOpaRule `json:"planValidationOpa,omitempty"`
PolicyId string `json:"policyId"`
Retry *RetryRule `json:"retry,omitempty"`
Verification *VerificationRule `json:"verification,omitempty"`
@@ -1184,6 +1212,12 @@ type UpsertDeploymentVariableValueRequest struct {
Value Value `json:"value"`
}
+// UpsertDeploymentVersionDependencyRequest defines model for UpsertDeploymentVersionDependencyRequest.
+type UpsertDeploymentVersionDependencyRequest struct {
+ // VersionSelector CEL expression evaluated against the dependency deployment's current release version on the same resource.
+ VersionSelector string `json:"versionSelector"`
+}
+
// UpsertEnvironmentRequest defines model for UpsertEnvironmentRequest.
type UpsertEnvironmentRequest struct {
Description *string `json:"description,omitempty"`
@@ -1226,6 +1260,7 @@ type UpsertPolicyRule struct {
EnvironmentProgression *EnvironmentProgressionRule `json:"environmentProgression,omitempty"`
GradualRollout *GradualRolloutRule `json:"gradualRollout,omitempty"`
Id *string `json:"id,omitempty"`
+ PlanValidationOpa *PlanValidationOpaRule `json:"planValidationOpa,omitempty"`
PolicyId *string `json:"policyId,omitempty"`
Retry *RetryRule `json:"retry,omitempty"`
Verification *VerificationRule `json:"verification,omitempty"`
@@ -1772,6 +1807,9 @@ type RequestDeploymentVariableValueUpsertJSONRequestBody = UpsertDeploymentVaria
// RequestDeploymentVariableUpdateJSONRequestBody defines body for RequestDeploymentVariableUpdate for application/json ContentType.
type RequestDeploymentVariableUpdateJSONRequestBody = UpsertDeploymentVariableRequest
+// RequestDeploymentVersionDependencyUpsertJSONRequestBody defines body for RequestDeploymentVersionDependencyUpsert for application/json ContentType.
+type RequestDeploymentVersionDependencyUpsertJSONRequestBody = UpsertDeploymentVersionDependencyRequest
+
// RequestUserApprovalRecordUpsertJSONRequestBody defines body for RequestUserApprovalRecordUpsert for application/json ContentType.
type RequestUserApprovalRecordUpsertJSONRequestBody = UpsertUserApprovalRecordRequest
@@ -2608,6 +2646,17 @@ type ClientInterface interface {
RequestDeploymentVariableUpdate(ctx context.Context, workspaceId string, variableId string, body RequestDeploymentVariableUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // ListDeploymentVersionDependencies request
+ ListDeploymentVersionDependencies(ctx context.Context, workspaceId string, deploymentVersionId string, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // RequestDeploymentVersionDependencyDeletion request
+ RequestDeploymentVersionDependencyDeletion(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // RequestDeploymentVersionDependencyUpsertWithBody request with any body
+ RequestDeploymentVersionDependencyUpsertWithBody(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ RequestDeploymentVersionDependencyUpsert(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, body RequestDeploymentVersionDependencyUpsertJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// RequestUserApprovalRecordUpsertWithBody request with any body
RequestUserApprovalRecordUpsertWithBody(ctx context.Context, workspaceId string, deploymentVersionId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -3094,6 +3143,54 @@ func (c *Client) RequestDeploymentVariableUpdate(ctx context.Context, workspaceI
return c.Client.Do(req)
}
+func (c *Client) ListDeploymentVersionDependencies(ctx context.Context, workspaceId string, deploymentVersionId string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewListDeploymentVersionDependenciesRequest(c.Server, workspaceId, deploymentVersionId)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) RequestDeploymentVersionDependencyDeletion(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewRequestDeploymentVersionDependencyDeletionRequest(c.Server, workspaceId, deploymentVersionId, dependencyDeploymentId)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) RequestDeploymentVersionDependencyUpsertWithBody(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewRequestDeploymentVersionDependencyUpsertRequestWithBody(c.Server, workspaceId, deploymentVersionId, dependencyDeploymentId, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) RequestDeploymentVersionDependencyUpsert(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, body RequestDeploymentVersionDependencyUpsertJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewRequestDeploymentVersionDependencyUpsertRequest(c.Server, workspaceId, deploymentVersionId, dependencyDeploymentId, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) RequestUserApprovalRecordUpsertWithBody(ctx context.Context, workspaceId string, deploymentVersionId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewRequestUserApprovalRecordUpsertRequestWithBody(c.Server, workspaceId, deploymentVersionId, contentType, body)
if err != nil {
@@ -4866,6 +4963,156 @@ func NewRequestDeploymentVariableUpdateRequestWithBody(server string, workspaceI
return req, nil
}
+// NewListDeploymentVersionDependenciesRequest generates requests for ListDeploymentVersionDependencies
+func NewListDeploymentVersionDependenciesRequest(server string, workspaceId string, deploymentVersionId string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithLocation("simple", false, "workspaceId", runtime.ParamLocationPath, workspaceId)
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithLocation("simple", false, "deploymentVersionId", runtime.ParamLocationPath, deploymentVersionId)
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/v1/workspaces/%s/deployment-versions/%s/dependencies", pathParam0, pathParam1)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewRequestDeploymentVersionDependencyDeletionRequest generates requests for RequestDeploymentVersionDependencyDeletion
+func NewRequestDeploymentVersionDependencyDeletionRequest(server string, workspaceId string, deploymentVersionId string, dependencyDeploymentId string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithLocation("simple", false, "workspaceId", runtime.ParamLocationPath, workspaceId)
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithLocation("simple", false, "deploymentVersionId", runtime.ParamLocationPath, deploymentVersionId)
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam2 string
+
+ pathParam2, err = runtime.StyleParamWithLocation("simple", false, "dependencyDeploymentId", runtime.ParamLocationPath, dependencyDeploymentId)
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/v1/workspaces/%s/deployment-versions/%s/dependencies/%s", pathParam0, pathParam1, pathParam2)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("DELETE", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewRequestDeploymentVersionDependencyUpsertRequest calls the generic RequestDeploymentVersionDependencyUpsert builder with application/json body
+func NewRequestDeploymentVersionDependencyUpsertRequest(server string, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, body RequestDeploymentVersionDependencyUpsertJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewRequestDeploymentVersionDependencyUpsertRequestWithBody(server, workspaceId, deploymentVersionId, dependencyDeploymentId, "application/json", bodyReader)
+}
+
+// NewRequestDeploymentVersionDependencyUpsertRequestWithBody generates requests for RequestDeploymentVersionDependencyUpsert with any type of body
+func NewRequestDeploymentVersionDependencyUpsertRequestWithBody(server string, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithLocation("simple", false, "workspaceId", runtime.ParamLocationPath, workspaceId)
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam1 string
+
+ pathParam1, err = runtime.StyleParamWithLocation("simple", false, "deploymentVersionId", runtime.ParamLocationPath, deploymentVersionId)
+ if err != nil {
+ return nil, err
+ }
+
+ var pathParam2 string
+
+ pathParam2, err = runtime.StyleParamWithLocation("simple", false, "dependencyDeploymentId", runtime.ParamLocationPath, dependencyDeploymentId)
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/v1/workspaces/%s/deployment-versions/%s/dependencies/%s", pathParam0, pathParam1, pathParam2)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("PUT", queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
// NewRequestUserApprovalRecordUpsertRequest calls the generic RequestUserApprovalRecordUpsert builder with application/json body
func NewRequestUserApprovalRecordUpsertRequest(server string, workspaceId string, deploymentVersionId string, body RequestUserApprovalRecordUpsertJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
@@ -9213,6 +9460,17 @@ type ClientWithResponsesInterface interface {
RequestDeploymentVariableUpdateWithResponse(ctx context.Context, workspaceId string, variableId string, body RequestDeploymentVariableUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*RequestDeploymentVariableUpdateResponse, error)
+ // ListDeploymentVersionDependenciesWithResponse request
+ ListDeploymentVersionDependenciesWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, reqEditors ...RequestEditorFn) (*ListDeploymentVersionDependenciesResponse, error)
+
+ // RequestDeploymentVersionDependencyDeletionWithResponse request
+ RequestDeploymentVersionDependencyDeletionWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, reqEditors ...RequestEditorFn) (*RequestDeploymentVersionDependencyDeletionResponse, error)
+
+ // RequestDeploymentVersionDependencyUpsertWithBodyWithResponse request with any body
+ RequestDeploymentVersionDependencyUpsertWithBodyWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequestDeploymentVersionDependencyUpsertResponse, error)
+
+ RequestDeploymentVersionDependencyUpsertWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, body RequestDeploymentVersionDependencyUpsertJSONRequestBody, reqEditors ...RequestEditorFn) (*RequestDeploymentVersionDependencyUpsertResponse, error)
+
// RequestUserApprovalRecordUpsertWithBodyWithResponse request with any body
RequestUserApprovalRecordUpsertWithBodyWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequestUserApprovalRecordUpsertResponse, error)
@@ -9802,6 +10060,77 @@ func (r RequestDeploymentVariableUpdateResponse) StatusCode() int {
return 0
}
+type ListDeploymentVersionDependenciesResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *[]DeploymentVersionDependency
+ JSON404 *ErrorResponse
+}
+
+// Status returns HTTPResponse.Status
+func (r ListDeploymentVersionDependenciesResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ListDeploymentVersionDependenciesResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+type RequestDeploymentVersionDependencyDeletionResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON202 *DeploymentRequestAccepted
+ JSON400 *ErrorResponse
+ JSON404 *ErrorResponse
+}
+
+// Status returns HTTPResponse.Status
+func (r RequestDeploymentVersionDependencyDeletionResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r RequestDeploymentVersionDependencyDeletionResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+type RequestDeploymentVersionDependencyUpsertResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON202 *DeploymentRequestAccepted
+ JSON400 *ErrorResponse
+ JSON404 *ErrorResponse
+}
+
+// Status returns HTTPResponse.Status
+func (r RequestDeploymentVersionDependencyUpsertResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r RequestDeploymentVersionDependencyUpsertResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
type RequestUserApprovalRecordUpsertResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -10099,8 +10428,9 @@ func (r ListDeploymentVersionsResponse) StatusCode() int {
type CreateDeploymentVersionResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON202 *DeploymentVersion
+ JSON200 *DeploymentVersion
JSON400 *ErrorResponse
+ JSON404 *ErrorResponse
}
// Status returns HTTPResponse.Status
@@ -12015,6 +12345,41 @@ func (c *ClientWithResponses) RequestDeploymentVariableUpdateWithResponse(ctx co
return ParseRequestDeploymentVariableUpdateResponse(rsp)
}
+// ListDeploymentVersionDependenciesWithResponse request returning *ListDeploymentVersionDependenciesResponse
+func (c *ClientWithResponses) ListDeploymentVersionDependenciesWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, reqEditors ...RequestEditorFn) (*ListDeploymentVersionDependenciesResponse, error) {
+ rsp, err := c.ListDeploymentVersionDependencies(ctx, workspaceId, deploymentVersionId, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseListDeploymentVersionDependenciesResponse(rsp)
+}
+
+// RequestDeploymentVersionDependencyDeletionWithResponse request returning *RequestDeploymentVersionDependencyDeletionResponse
+func (c *ClientWithResponses) RequestDeploymentVersionDependencyDeletionWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, reqEditors ...RequestEditorFn) (*RequestDeploymentVersionDependencyDeletionResponse, error) {
+ rsp, err := c.RequestDeploymentVersionDependencyDeletion(ctx, workspaceId, deploymentVersionId, dependencyDeploymentId, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseRequestDeploymentVersionDependencyDeletionResponse(rsp)
+}
+
+// RequestDeploymentVersionDependencyUpsertWithBodyWithResponse request with arbitrary body returning *RequestDeploymentVersionDependencyUpsertResponse
+func (c *ClientWithResponses) RequestDeploymentVersionDependencyUpsertWithBodyWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequestDeploymentVersionDependencyUpsertResponse, error) {
+ rsp, err := c.RequestDeploymentVersionDependencyUpsertWithBody(ctx, workspaceId, deploymentVersionId, dependencyDeploymentId, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseRequestDeploymentVersionDependencyUpsertResponse(rsp)
+}
+
+func (c *ClientWithResponses) RequestDeploymentVersionDependencyUpsertWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, dependencyDeploymentId string, body RequestDeploymentVersionDependencyUpsertJSONRequestBody, reqEditors ...RequestEditorFn) (*RequestDeploymentVersionDependencyUpsertResponse, error) {
+ rsp, err := c.RequestDeploymentVersionDependencyUpsert(ctx, workspaceId, deploymentVersionId, dependencyDeploymentId, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseRequestDeploymentVersionDependencyUpsertResponse(rsp)
+}
+
// RequestUserApprovalRecordUpsertWithBodyWithResponse request with arbitrary body returning *RequestUserApprovalRecordUpsertResponse
func (c *ClientWithResponses) RequestUserApprovalRecordUpsertWithBodyWithResponse(ctx context.Context, workspaceId string, deploymentVersionId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequestUserApprovalRecordUpsertResponse, error) {
rsp, err := c.RequestUserApprovalRecordUpsertWithBody(ctx, workspaceId, deploymentVersionId, contentType, body, reqEditors...)
@@ -13479,6 +13844,119 @@ func ParseRequestDeploymentVariableUpdateResponse(rsp *http.Response) (*RequestD
return response, nil
}
+// ParseListDeploymentVersionDependenciesResponse parses an HTTP response from a ListDeploymentVersionDependenciesWithResponse call
+func ParseListDeploymentVersionDependenciesResponse(rsp *http.Response) (*ListDeploymentVersionDependenciesResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ListDeploymentVersionDependenciesResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest []DeploymentVersionDependency
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
+ var dest ErrorResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON404 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseRequestDeploymentVersionDependencyDeletionResponse parses an HTTP response from a RequestDeploymentVersionDependencyDeletionWithResponse call
+func ParseRequestDeploymentVersionDependencyDeletionResponse(rsp *http.Response) (*RequestDeploymentVersionDependencyDeletionResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &RequestDeploymentVersionDependencyDeletionResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
+ var dest DeploymentRequestAccepted
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON202 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest ErrorResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
+ var dest ErrorResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON404 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseRequestDeploymentVersionDependencyUpsertResponse parses an HTTP response from a RequestDeploymentVersionDependencyUpsertWithResponse call
+func ParseRequestDeploymentVersionDependencyUpsertResponse(rsp *http.Response) (*RequestDeploymentVersionDependencyUpsertResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &RequestDeploymentVersionDependencyUpsertResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
+ var dest DeploymentRequestAccepted
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON202 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest ErrorResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
+ var dest ErrorResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON404 = &dest
+
+ }
+
+ return response, nil
+}
+
// ParseRequestUserApprovalRecordUpsertResponse parses an HTTP response from a RequestUserApprovalRecordUpsertWithResponse call
func ParseRequestUserApprovalRecordUpsertResponse(rsp *http.Response) (*RequestUserApprovalRecordUpsertResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -13945,12 +14423,12 @@ func ParseCreateDeploymentVersionResponse(rsp *http.Response) (*CreateDeployment
}
switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
var dest DeploymentVersion
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
- response.JSON202 = &dest
+ response.JSON200 = &dest
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
var dest ErrorResponse
@@ -13959,6 +14437,13 @@ func ParseCreateDeploymentVersionResponse(rsp *http.Response) (*CreateDeployment
}
response.JSON400 = &dest
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
+ var dest ErrorResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON404 = &dest
+
}
return response, nil
diff --git a/internal/provider/policy_resource.go b/internal/provider/policy_resource.go
index 8a695ca..1a13258 100644
--- a/internal/provider/policy_resource.go
+++ b/internal/provider/policy_resource.go
@@ -448,6 +448,39 @@ func (r *PolicyResource) Schema(ctx context.Context, req resource.SchemaRequest,
},
},
},
+ "plan_validation_opa": schema.ListNestedBlock{
+ Description: "OPA-based plan validation rules. Each rule must define a `deny` rule set following the Conftest convention.",
+ NestedObject: schema.NestedBlockObject{
+ Attributes: map[string]schema.Attribute{
+ "created_at": schema.StringAttribute{
+ Computed: true,
+ Description: "Rule creation timestamp",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ "id": schema.StringAttribute{
+ Computed: true,
+ Description: "Rule ID",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ "name": schema.StringAttribute{
+ Required: true,
+ Description: "Human-readable rule name; used in check output to identify which rule produced a violation.",
+ },
+ "description": schema.StringAttribute{
+ Optional: true,
+ Description: "Optional human-readable explanation of the rule.",
+ },
+ "rego": schema.StringAttribute{
+ Required: true,
+ Description: "Rego source code. Follows Conftest conventions for emitting violations.",
+ },
+ },
+ },
+ },
},
}
}
@@ -638,6 +671,7 @@ func (r *PolicyResource) Read(ctx context.Context, req resource.ReadRequest, res
data.GradualRollout = rules.GradualRollout
data.AnyApproval = rules.AnyApproval
data.EnvironmentProgression = rules.EnvironmentProgression
+ data.PlanValidationOpa = rules.PlanValidationOpa
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
@@ -728,6 +762,7 @@ func (r *PolicyResource) Update(ctx context.Context, req resource.UpdateRequest,
data.GradualRollout = readRules.GradualRollout
data.AnyApproval = readRules.AnyApproval
data.EnvironmentProgression = readRules.EnvironmentProgression
+ data.PlanValidationOpa = readRules.PlanValidationOpa
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
}
@@ -773,6 +808,7 @@ type PolicyResourceModel struct {
GradualRollout []PolicyGradualRollout `tfsdk:"gradual_rollout"`
AnyApproval []PolicyAnyApproval `tfsdk:"any_approval"`
EnvironmentProgression []PolicyEnvironmentProgression `tfsdk:"environment_progression"`
+ PlanValidationOpa []PolicyPlanValidationOpa `tfsdk:"plan_validation_opa"`
}
type PolicyVersionSelector struct {
@@ -832,6 +868,14 @@ type PolicyVerificationRule struct {
Metric []PolicyVerificationMetric `tfsdk:"metric"`
}
+type PolicyPlanValidationOpa struct {
+ CreatedAt types.String `tfsdk:"created_at"`
+ ID types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Rego types.String `tfsdk:"rego"`
+}
+
type PolicyVerificationMetric struct {
Name types.String `tfsdk:"name"`
Interval types.String `tfsdk:"interval"`
@@ -870,6 +914,7 @@ type policyRulesModel struct {
GradualRollout []PolicyGradualRollout
AnyApproval []PolicyAnyApproval
EnvironmentProgression []PolicyEnvironmentProgression
+ PlanValidationOpa []PolicyPlanValidationOpa
}
type policyRequestPayload struct {
@@ -893,6 +938,7 @@ type policyRequestRule struct {
GradualRollout *api.GradualRolloutRule `json:"gradualRollout,omitempty"`
AnyApproval *api.AnyApprovalRule `json:"anyApproval,omitempty"`
EnvironmentProgression *api.EnvironmentProgressionRule `json:"environmentProgression,omitempty"`
+ PlanValidationOpa *api.PlanValidationOpaRule `json:"planValidationOpa,omitempty"`
PolicyId *string `json:"policyId,omitempty"`
}
@@ -1086,6 +1132,29 @@ func policyRulesFromModel(data PolicyResourceModel) ([]policyRequestRule, diag.D
})
}
+ for _, opa := range data.PlanValidationOpa {
+ id := selectorIDValue(opa.ID)
+ name := opa.Name.ValueString()
+ rego := opa.Rego.ValueString()
+ if name == "" || rego == "" {
+ diags.AddError("Invalid plan validation rule", "name and rego must be set")
+ continue
+ }
+ rule := api.PlanValidationOpaRule{
+ Name: name,
+ Rego: rego,
+ }
+ if selectorValueSet(opa.Description) {
+ desc := opa.Description.ValueString()
+ rule.Description = &desc
+ }
+ rules = append(rules, policyRequestRule{
+ CreatedAt: createdAtValue(opa.CreatedAt),
+ Id: id,
+ PlanValidationOpa: &rule,
+ })
+ }
+
return rules, diags
}
@@ -1340,6 +1409,19 @@ func policyRulesToModel(rules []api.PolicyRule) (policyRulesModel, diag.Diagnost
}
result.EnvironmentProgression = append(result.EnvironmentProgression, model)
}
+ if rule.PlanValidationOpa != nil {
+ model := PolicyPlanValidationOpa{
+ CreatedAt: types.StringValue(rule.CreatedAt),
+ ID: types.StringValue(rule.Id),
+ Name: types.StringValue(rule.PlanValidationOpa.Name),
+ Description: types.StringNull(),
+ Rego: types.StringValue(rule.PlanValidationOpa.Rego),
+ }
+ if rule.PlanValidationOpa.Description != nil {
+ model.Description = types.StringValue(*rule.PlanValidationOpa.Description)
+ }
+ result.PlanValidationOpa = append(result.PlanValidationOpa, model)
+ }
}
return result, diags
@@ -1354,6 +1436,7 @@ func ensurePolicyIDs(plan *PolicyResourceModel, state *PolicyResourceModel) {
mergeGradualRolloutIDs(plan.GradualRollout, gradualRolloutListFromState(state))
mergeAnyApprovalIDs(plan.AnyApproval, anyApprovalListFromState(state))
mergeEnvironmentProgressionIDs(plan.EnvironmentProgression, environmentProgressionListFromState(state))
+ mergePlanValidationOpaIDs(plan.PlanValidationOpa, planValidationOpaListFromState(state))
}
func ensurePolicyRuleCreatedAt(plan *PolicyResourceModel, state *PolicyResourceModel) {
@@ -1365,6 +1448,7 @@ func ensurePolicyRuleCreatedAt(plan *PolicyResourceModel, state *PolicyResourceM
mergeGradualRolloutCreatedAt(plan.GradualRollout, gradualRolloutListFromState(state))
mergeAnyApprovalCreatedAt(plan.AnyApproval, anyApprovalListFromState(state))
mergeEnvironmentProgressionCreatedAt(plan.EnvironmentProgression, environmentProgressionListFromState(state))
+ mergePlanValidationOpaCreatedAt(plan.PlanValidationOpa, planValidationOpaListFromState(state))
}
func setPolicyIDOnRules(request *policyRequestPayload, policyID string) {
@@ -1644,6 +1728,39 @@ func mergeEnvironmentProgressionCreatedAt(plan []PolicyEnvironmentProgression, s
}
}
+func planValidationOpaListFromState(state *PolicyResourceModel) []PolicyPlanValidationOpa {
+ if state == nil {
+ return nil
+ }
+ return state.PlanValidationOpa
+}
+
+func mergePlanValidationOpaIDs(plan []PolicyPlanValidationOpa, state []PolicyPlanValidationOpa) {
+ for i := range plan {
+ if selectorValueSet(plan[i].ID) {
+ continue
+ }
+ if i < len(state) && selectorValueSet(state[i].ID) {
+ plan[i].ID = state[i].ID
+ continue
+ }
+ plan[i].ID = types.StringValue(uuid.NewString())
+ }
+}
+
+func mergePlanValidationOpaCreatedAt(plan []PolicyPlanValidationOpa, state []PolicyPlanValidationOpa) {
+ for i := range plan {
+ if selectorValueSet(plan[i].CreatedAt) {
+ continue
+ }
+ if i < len(state) && selectorValueSet(state[i].CreatedAt) {
+ plan[i].CreatedAt = state[i].CreatedAt
+ continue
+ }
+ plan[i].CreatedAt = types.StringValue(time.Now().UTC().Format(time.RFC3339))
+ }
+}
+
func policyVerificationRuleToModel(rule *api.VerificationRule) (PolicyVerificationRule, error) {
model := PolicyVerificationRule{
TriggerOn: types.StringNull(),