Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions apps/workspace-engine/oapi/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,74 @@
],
"type": "object"
},
"PlanValidationOpaRule": {
"properties": {
"description": {
"type": "string"
},
"name": {
"description": "Human-readable rule name; used in check output to identify which rule produced a violation.",
"type": "string"
},
"rego": {
"description": "Rego v1 source code. Must define a `deny` rule set following the Conftest convention (deny contains msg if { ... }).",
"type": "string"
}
},
"required": [
"name",
"rego"
],
"type": "object"
},
"PlanValidationResult": {
"properties": {
"evaluatedAt": {
"format": "date-time",
"type": "string"
},
"id": {
"type": "string"
},
"passed": {
"type": "boolean"
},
"resultId": {
"description": "ID of the deployment_plan_target_result this validation was run against.",
"type": "string"
},
"ruleId": {
"description": "Polymorphic rule id. Resolves to a specific rule type (e.g. PlanValidationOpaRule) known by the writing controller.",
"type": "string"
},
"violations": {
"items": {
"$ref": "#/components/schemas/PlanValidationViolation"
},
"type": "array"
}
},
"required": [
"id",
"resultId",
"ruleId",
"passed",
"violations",
"evaluatedAt"
],
"type": "object"
},
"PlanValidationViolation": {
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
},
"Policy": {
"properties": {
"createdAt": {
Expand Down Expand Up @@ -1293,6 +1361,9 @@
"id": {
"type": "string"
},
"planValidationOpa": {
"$ref": "#/components/schemas/PlanValidationOpaRule"
},
"policyId": {
"type": "string"
},
Expand Down
3 changes: 2 additions & 1 deletion apps/workspace-engine/oapi/spec/main.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
(import 'schemas/systems.jsonnet') +
(import 'schemas/workflows.jsonnet') +
(import 'schemas/release_targets.jsonnet') +
(import 'schemas/variablesets.jsonnet'),
(import 'schemas/variablesets.jsonnet') +
(import 'schemas/plan_validation.jsonnet'),
},
}
49 changes: 49 additions & 0 deletions apps/workspace-engine/oapi/spec/schemas/plan_validation.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
local openapi = import '../lib/openapi.libsonnet';

{
PlanValidationOpaRule: {
type: 'object',
required: ['name', 'rego'],
properties: {
name: {
type: 'string',
description: 'Human-readable rule name; used in check output to identify which rule produced a violation.',
},
description: { type: 'string' },
rego: {
type: 'string',
description: 'Rego v1 source code. Must define a `deny` rule set following the Conftest convention (deny contains msg if { ... }).',
},
},
},

PlanValidationResult: {
type: 'object',
required: ['id', 'resultId', 'ruleId', 'passed', 'violations', 'evaluatedAt'],
properties: {
id: { type: 'string' },
resultId: {
type: 'string',
description: 'ID of the deployment_plan_target_result this validation was run against.',
},
ruleId: {
type: 'string',
description: 'Polymorphic rule id. Resolves to a specific rule type (e.g. PlanValidationOpaRule) known by the writing controller.',
},
passed: { type: 'boolean' },
violations: {
type: 'array',
items: openapi.schemaRef('PlanValidationViolation'),
},
evaluatedAt: { type: 'string', format: 'date-time' },
},
},

PlanValidationViolation: {
type: 'object',
required: ['message'],
properties: {
message: { type: 'string' },
},
},
}
1 change: 1 addition & 0 deletions apps/workspace-engine/oapi/spec/schemas/policy.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ local openapi = import '../lib/openapi.libsonnet';
verification: openapi.schemaRef('VerificationRule'),
versionCooldown: openapi.schemaRef('VersionCooldownRule'),
rollback: openapi.schemaRef('RollbackRule'),
planValidationOpa: openapi.schemaRef('PlanValidationOpaRule'),
},
},

Expand Down
18 changes: 18 additions & 0 deletions apps/workspace-engine/pkg/db/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 128 additions & 0 deletions apps/workspace-engine/pkg/db/plan_validation.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions apps/workspace-engine/pkg/db/queries/plan_validation.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-- name: ListPlanValidationOpaRulesForWorkspace :many
SELECT
r.id,
r.policy_id,
r.name,
r.description,
r.rego,
r.created_at,
p.selector AS policy_selector
FROM policy_rule_plan_validation_opa r
JOIN policy p ON p.id = r.policy_id
WHERE p.workspace_id = $1
AND p.enabled = true
ORDER BY p.priority DESC, r.created_at DESC;

-- name: GetCurrentVersionForPlanTarget :one
SELECT dv.*
FROM deployment_plan_target t
JOIN release rel ON rel.id = t.current_release_id
JOIN deployment_version dv ON dv.id = rel.version_id
WHERE t.id = $1;

-- name: UpsertPlanValidationResult :exec
INSERT INTO deployment_plan_target_result_validation (
result_id, rule_id, passed, violations, evaluated_at
)
VALUES (
sqlc.arg('result_id'),
sqlc.arg('rule_id'),
sqlc.arg('passed'),
sqlc.arg('violations'),
NOW()
)
ON CONFLICT (result_id, rule_id) DO UPDATE
SET passed = EXCLUDED.passed,
violations = EXCLUDED.violations,
evaluated_at = EXCLUDED.evaluated_at;
19 changes: 19 additions & 0 deletions apps/workspace-engine/pkg/db/queries/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -527,4 +527,23 @@ CREATE TABLE variable_set_variable (
key TEXT NOT NULL,
value JSONB NOT NULL,
UNIQUE (variable_set_id, key)
);

CREATE TABLE policy_rule_plan_validation_opa (
id UUID PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
policy_id UUID NOT NULL REFERENCES policy(id) ON DELETE CASCADE,
name TEXT NOT NULL,
description TEXT,
rego TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE deployment_plan_target_result_validation (
id UUID PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
result_id UUID NOT NULL REFERENCES deployment_plan_target_result(id) ON DELETE CASCADE,
rule_id UUID NOT NULL,
passed BOOLEAN NOT NULL,
violations JSONB NOT NULL DEFAULT '[]'::jsonb,
evaluated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (result_id, rule_id)
);
6 changes: 6 additions & 0 deletions apps/workspace-engine/pkg/db/sqlc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ sql:
- queries/deployment_plan.sql
- queries/release_targets.sql
- queries/variable_sets.sql
- queries/plan_validation.sql
database:
uri: "postgresql://ctrlplane:ctrlplane@127.0.0.1:5432/ctrlplane?sslmode=disable"
gen:
Expand Down Expand Up @@ -205,3 +206,8 @@ sql:
- column: "deployment_plan_target_result.agent_state"
go_type:
type: "[]byte"

# DeploymentPlanTargetResultValidation
- column: "deployment_plan_target_result_validation.violations"
go_type:
type: "[]byte"
Loading
Loading