Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Template =
| "environment-selector"
| "relationship-entity"
| "relationship-rule"
| "policy-summary"
| "advanced";

const TEMPLATES: { value: Template; label: string; description: string }[] = [
Expand All @@ -57,6 +58,12 @@ const TEMPLATES: { value: Template; label: string; description: string }[] = [
description:
"Re-evaluate relationships for all entities in the workspace. Useful after changing a rule.",
},
{
value: "policy-summary",
label: "Policy Summary Eval",
description:
"Re-evaluate policy summaries for an environment + version pair.",
},
{
value: "advanced",
label: "Advanced",
Expand Down Expand Up @@ -307,6 +314,63 @@ function RelationshipRuleForm({
);
}

function PolicySummaryForm({
workspaceId,
onDone,
}: {
workspaceId: string;
onDone: () => void;
}) {
const [environmentId, setEnvironmentId] = useState("");
const [versionId, setVersionId] = useState("");
const invalidate = useInvalidateAll();
const mutation = trpc.reconcile.triggerPolicySummary.useMutation({
onSuccess: () => {
invalidate();
onDone();
},
});

return (
<form
onSubmit={(e) => {
e.preventDefault();
mutation.mutate({ workspaceId, environmentId, versionId });
}}
className="flex flex-col gap-4"
>
<div className="flex flex-col gap-1.5">
<Label htmlFor="ps-environmentId">Environment ID *</Label>
<Input
id="ps-environmentId"
placeholder="UUID of the environment"
value={environmentId}
onChange={(e) => setEnvironmentId(e.target.value)}
required
/>
</div>
<div className="flex flex-col gap-1.5">
<Label htmlFor="ps-versionId">Version ID *</Label>
<Input
id="ps-versionId"
placeholder="UUID of the deployment version"
value={versionId}
onChange={(e) => setVersionId(e.target.value)}
required
/>
</div>
<DialogFooter>
<Button type="submit" disabled={mutation.isPending}>
{mutation.isPending ? "Triggering…" : "Trigger Eval"}
</Button>
</DialogFooter>
{mutation.error && (
<p className="text-sm text-destructive">{mutation.error.message}</p>
)}
</form>
);
}

function AdvancedForm({
workspaceId,
onDone,
Expand Down Expand Up @@ -579,6 +643,9 @@ export const CreateWorkItemDialog: React.FC<{
{template === "relationship-rule" && (
<RelationshipRuleForm workspaceId={workspaceId} onDone={close} />
)}
{template === "policy-summary" && (
<PolicySummaryForm workspaceId={workspaceId} onDone={close} />
)}
{template === "advanced" && (
<AdvancedForm workspaceId={workspaceId} onDone={close} />
)}
Expand Down
2 changes: 2 additions & 0 deletions apps/workspace-engine/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"workspace-engine/svc/controllers/environmentresourceselectoreval"
"workspace-engine/svc/controllers/jobdispatch"
"workspace-engine/svc/controllers/jobverificationmetric"
"workspace-engine/svc/controllers/policysummary"
"workspace-engine/svc/controllers/relationshipeval"
httpsvc "workspace-engine/svc/http"
"workspace-engine/svc/routerregistrar"
Expand Down Expand Up @@ -67,6 +68,7 @@ func main() {
jobverificationmetric.New(WorkerID, db.GetPool(ctx)),
relationshipeval.New(WorkerID, db.GetPool(ctx)),
desiredrelease.New(WorkerID, db.GetPool(ctx)),
policysummary.New(WorkerID, db.GetPool(ctx)),
)

if err := runner.Run(ctx); err != nil {
Expand Down
87 changes: 87 additions & 0 deletions apps/workspace-engine/pkg/db/batch.go

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

15 changes: 15 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.

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

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

36 changes: 36 additions & 0 deletions apps/workspace-engine/pkg/db/queries/policy_rule_summary.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-- name: UpsertPolicyRuleSummary :batchexec
INSERT INTO policy_rule_summary (
id, rule_id,
environment_id, version_id,
allowed, action_required, action_type,
message, details,
satisfied_at, next_evaluation_at, evaluated_at
)
VALUES (
gen_random_uuid(), $1,
$2, $3,
$4, $5, $6,
$7, $8,
$9, $10, NOW()
)
ON CONFLICT (rule_id, environment_id, version_id) DO UPDATE
SET allowed = EXCLUDED.allowed,
action_required = EXCLUDED.action_required,
action_type = EXCLUDED.action_type,
message = EXCLUDED.message,
details = EXCLUDED.details,
satisfied_at = EXCLUDED.satisfied_at,
next_evaluation_at = EXCLUDED.next_evaluation_at,
evaluated_at = NOW();

-- name: ListPolicyRuleSummariesByEnvironmentAndVersion :many
SELECT id, rule_id,
environment_id, version_id,
allowed, action_required, action_type,
message, details,
satisfied_at, next_evaluation_at, evaluated_at
FROM policy_rule_summary
WHERE environment_id = $1 AND version_id = $2;

-- name: DeletePolicyRuleSummariesByRuleID :exec
DELETE FROM policy_rule_summary WHERE rule_id = $1;
18 changes: 18 additions & 0 deletions apps/workspace-engine/pkg/db/queries/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,21 @@ CREATE TABLE job_verification_metric_measurement (
message TEXT NOT NULL DEFAULT '',
status job_verification_status NOT NULL
);

CREATE TABLE policy_rule_summary (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
rule_id UUID NOT NULL,
environment_id UUID NOT NULL,
version_id UUID NOT NULL,
allowed BOOLEAN NOT NULL,
action_required BOOLEAN NOT NULL DEFAULT false,
action_type TEXT,
message TEXT NOT NULL,
details JSONB NOT NULL DEFAULT '{}'::jsonb,
satisfied_at TIMESTAMPTZ,
next_evaluation_at TIMESTAMPTZ,
evaluated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE UNIQUE INDEX policy_rule_summary_scope_idx
ON policy_rule_summary (rule_id, environment_id, version_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 @@ -29,6 +29,7 @@ sql:
- queries/jobs.sql
- queries/computed_relationships.sql
- queries/relationship_rules.sql
- queries/policy_rule_summary.sql
database:
uri: "postgresql://ctrlplane:ctrlplane@127.0.0.1:5432/ctrlplane?sslmode=disable"
gen:
Expand Down Expand Up @@ -124,6 +125,11 @@ sql:
go_type:
type: "map[string]string"

# PolicyRuleSummary
- column: "policy_rule_summary.details"
go_type:
type: "map[string]any"

# ResourceVariable
- column: "resource_variable.value"
go_type:
Expand Down
1 change: 0 additions & 1 deletion apps/workspace-engine/pkg/events/handler/jobs/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ func HandleJobUpdated(
if jobUpdateEvent.FieldsToUpdate == nil || len(*jobUpdateEvent.FieldsToUpdate) == 0 {
ws.Jobs().Upsert(ctx, &jobUpdateEvent.Job)
dirtyStateForJob(ctx, ws, &jobUpdateEvent.Job)
// Trigger actions on status change
triggerActionsOnStatusChange(ctx, ws, &jobUpdateEvent.Job, previousStatus)
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions apps/workspace-engine/pkg/events/handler/policies/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package policies

import (
"context"
"encoding/json"

"workspace-engine/pkg/events/handler"
"workspace-engine/pkg/oapi"
"workspace-engine/pkg/workspace"
"workspace-engine/pkg/workspace/releasemanager"
"workspace-engine/pkg/workspace/releasemanager/trace"

"encoding/json"

"github.com/charmbracelet/log"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
Expand Down
Loading
Loading