diff --git a/apps/event-worker/src/releases/evaluate/index.ts b/apps/event-worker/src/releases/evaluate/index.ts index e155dd464..569f5b09b 100644 --- a/apps/event-worker/src/releases/evaluate/index.ts +++ b/apps/event-worker/src/releases/evaluate/index.ts @@ -40,12 +40,16 @@ export const createReleaseEvaluateWorker = () => // just return releases from the latest deployed release to the current // version. We need to account for upgrades and downgrades. put this // function in @ctrlplane/rule-engine/utils as we will call it elsewhere - const getReleases = async (_: Policy) => { + const getReleases = async (policy: Policy) => { await db.query.release.findMany({ where: and( eq(schema.release.deploymentId, ctx.deploymentId), eq(schema.release.resourceId, ctx.resourceId), eq(schema.release.environmentId, ctx.environmentId), + schema.deploymentVersionMatchesCondition( + db, + policy.deploymentVersionSelector?.deploymentVersionSelector, + ), // TODO: Apply the conditions, if it exists. Its part of the // policy pass into this function. We might not be able to use // dirzzle query pattern here. diff --git a/packages/db/src/schema/policy-relations.ts b/packages/db/src/schema/policy-relations.ts index ad414cf5a..c910540ac 100644 --- a/packages/db/src/schema/policy-relations.ts +++ b/packages/db/src/schema/policy-relations.ts @@ -1,6 +1,11 @@ import { relations } from "drizzle-orm"; -import { policy, policyRuleDenyWindow, policyTarget } from "./policy.js"; +import { + policy, + policyDeploymentVersionSelector, + policyRuleDenyWindow, + policyTarget, +} from "./policy.js"; import { workspace } from "./workspace.js"; export const policyRelations = relations(policy, ({ many, one }) => ({ @@ -10,6 +15,10 @@ export const policyRelations = relations(policy, ({ many, one }) => ({ }), targets: many(policyTarget), denyWindows: many(policyRuleDenyWindow), + deploymentVersionSelector: one(policyDeploymentVersionSelector, { + fields: [policy.id], + references: [policyDeploymentVersionSelector.policyId], + }), })); export const policyTargetRelations = relations(policyTarget, ({ one }) => ({ diff --git a/packages/rule-engine/src/db/get-applicable-policies.ts b/packages/rule-engine/src/db/get-applicable-policies.ts index 1c27da039..da44799db 100644 --- a/packages/rule-engine/src/db/get-applicable-policies.ts +++ b/packages/rule-engine/src/db/get-applicable-policies.ts @@ -112,7 +112,7 @@ export const getApplicablePolicies = async ( ) => { const policy = await tx.query.policy.findMany({ where: eq(schema.policy.workspaceId, workspaceId), - with: { targets: true, denyWindows: true }, + with: { targets: true, denyWindows: true, deploymentVersionSelector: true }, orderBy: [desc(schema.policy.priority)], }); diff --git a/packages/rule-engine/src/utils/merge-policies.ts b/packages/rule-engine/src/utils/merge-policies.ts index aa1225a1b..b4ca5cf0d 100644 --- a/packages/rule-engine/src/utils/merge-policies.ts +++ b/packages/rule-engine/src/utils/merge-policies.ts @@ -1,11 +1,37 @@ +import type { DeploymentVersionCondition } from "@ctrlplane/validators/releases"; import _ from "lodash"; +import { isPresent } from "ts-is-present"; + +import { + ComparisonOperator, + ConditionType, +} from "@ctrlplane/validators/conditions"; import type { Policy } from "../types.js"; +const mergeVersionSelectors = ( + policies: Policy[], +): DeploymentVersionCondition | null => { + const versionSelectors = policies + .map((p) => p.deploymentVersionSelector?.deploymentVersionSelector) + .filter(isPresent); + + if (versionSelectors.length === 0) return null; + if (versionSelectors.length === 1) return versionSelectors[0]!; + + return { + type: ConditionType.Comparison, + operator: ComparisonOperator.And, + conditions: versionSelectors, + }; +}; + export const mergePolicies = (policies: Policy[]): Policy | null => { if (policies.length === 0) return null; if (policies.length === 1) return policies[0]!; - return _.mergeWith( + + const mergedVersionSelector = mergeVersionSelectors(policies); + const merged = _.mergeWith( policies[0], ...policies.slice(1), (objValue: any, sourceValue: any) => { @@ -13,4 +39,9 @@ export const mergePolicies = (policies: Policy[]): Policy | null => { return objValue.concat(sourceValue); }, ); + + return { + ...merged, + deploymentVersionSelector: mergedVersionSelector, + }; };