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
90 changes: 90 additions & 0 deletions apps/workspace-engine/pkg/db/policies.sql.go

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

27 changes: 27 additions & 0 deletions apps/workspace-engine/pkg/db/queries/policies.sql
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,30 @@ SET description = EXCLUDED.description, selector = EXCLUDED.selector;

-- name: DeleteVersionSelectorRulesByPolicyID :exec
DELETE FROM policy_rule_version_selector WHERE policy_id = $1;

-- name: ListPoliciesWithRulesByWorkspaceID :many
SELECT
p.id, p.name, p.description, p.selector, p.metadata, p.priority, p.enabled, p.workspace_id, p.created_at,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'min_approvals', r.min_approvals, 'created_at', r.created_at))
FROM policy_rule_any_approval r WHERE r.policy_id = p.id), '[]')::jsonb AS any_approval_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'depends_on', r.depends_on, 'created_at', r.created_at))
FROM policy_rule_deployment_dependency r WHERE r.policy_id = p.id), '[]')::jsonb AS deployment_dependency_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'allow_window', r.allow_window, 'duration_minutes', r.duration_minutes, 'rrule', r.rrule, 'timezone', r.timezone, 'created_at', r.created_at))
FROM policy_rule_deployment_window r WHERE r.policy_id = p.id), '[]')::jsonb AS deployment_window_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'depends_on_environment_selector', r.depends_on_environment_selector, 'maximum_age_hours', r.maximum_age_hours, 'minimum_soak_time_minutes', r.minimum_soak_time_minutes, 'minimum_success_percentage', r.minimum_success_percentage, 'success_statuses', r.success_statuses, 'created_at', r.created_at))
FROM policy_rule_environment_progression r WHERE r.policy_id = p.id), '[]')::jsonb AS environment_progression_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'rollout_type', r.rollout_type, 'time_scale_interval', r.time_scale_interval, 'created_at', r.created_at))
FROM policy_rule_gradual_rollout r WHERE r.policy_id = p.id), '[]')::jsonb AS gradual_rollout_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'max_retries', r.max_retries, 'backoff_seconds', r.backoff_seconds, 'backoff_strategy', r.backoff_strategy, 'max_backoff_seconds', r.max_backoff_seconds, 'retry_on_statuses', r.retry_on_statuses, 'created_at', r.created_at))
FROM policy_rule_retry r WHERE r.policy_id = p.id), '[]')::jsonb AS retry_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'on_job_statuses', r.on_job_statuses, 'on_verification_failure', r.on_verification_failure, 'created_at', r.created_at))
FROM policy_rule_rollback r WHERE r.policy_id = p.id), '[]')::jsonb AS rollback_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'metrics', r.metrics, 'trigger_on', r.trigger_on, 'created_at', r.created_at))
FROM policy_rule_verification r WHERE r.policy_id = p.id), '[]')::jsonb AS verification_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'interval_seconds', r.interval_seconds, 'created_at', r.created_at))
FROM policy_rule_version_cooldown r WHERE r.policy_id = p.id), '[]')::jsonb AS version_cooldown_rules,
COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'description', r.description, 'selector', r.selector, 'created_at', r.created_at))
FROM policy_rule_version_selector r WHERE r.policy_id = p.id), '[]')::jsonb AS version_selector_rules
Comment on lines +223 to +242
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make aggregated rule array ordering deterministic.

Each json_agg(...) here has no ORDER BY, so element order is not guaranteed. That can make API responses unstable across runs.

💡 Suggested pattern (apply to each rule subquery)
-  COALESCE((SELECT json_agg(json_build_object('id', r.id, 'policy_id', r.policy_id, 'min_approvals', r.min_approvals, 'created_at', r.created_at))
+  COALESCE((SELECT json_agg(
+      json_build_object('id', r.id, 'policy_id', r.policy_id, 'min_approvals', r.min_approvals, 'created_at', r.created_at)
+      ORDER BY r.created_at, r.id
+    )
     FROM policy_rule_any_approval r WHERE r.policy_id = p.id), '[]')::jsonb AS any_approval_rules,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/workspace-engine/pkg/db/queries/policies.sql` around lines 223 - 242,
The JSON aggregate subqueries (e.g., any_approval_rules /
policy_rule_any_approval, deployment_dependency_rules /
policy_rule_deployment_dependency, deployment_window_rules /
policy_rule_deployment_window, environment_progression_rules /
policy_rule_environment_progression, gradual_rollout_rules /
policy_rule_gradual_rollout, retry_rules / policy_rule_retry, rollback_rules /
policy_rule_rollback, verification_rules / policy_rule_verification,
version_cooldown_rules / policy_rule_version_cooldown, version_selector_rules /
policy_rule_version_selector) are using json_agg(...) without ORDER BY so their
element order is non-deterministic; fix each subquery by adding a deterministic
ORDER BY (for example ORDER BY r.id ASC or ORDER BY r.created_at ASC) inside the
SELECT ... FROM ... WHERE r.policy_id = p.id subquery so json_agg produces a
stable ordering for API responses.

FROM policy p
WHERE p.workspace_id = $1
ORDER BY p.priority DESC, p.created_at DESC;
Loading
Loading