-
Notifications
You must be signed in to change notification settings - Fork 11
clean up rule engine library #463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
863dde4
e85ac9e
f4bc202
b346a65
cf1fb1a
be1cf56
03c2baa
0ec389d
8e8697c
c0215fb
70c93c7
273f4e8
d123f2a
e7cf151
0e917ce
9a1f193
ffcc75a
1e5a43c
42e6415
45bc7ba
567aa7b
4c6b84f
6f07468
ad34e5a
6cf814f
3999320
6dac473
2723441
6061585
76b68c4
2115443
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,99 +7,136 @@ import * as schema from "@ctrlplane/db/schema"; | |||||||||||||||||||||||||||||
| import { Channel, createWorker, getQueue } from "@ctrlplane/events"; | ||||||||||||||||||||||||||||||
| import { logger } from "@ctrlplane/logger"; | ||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||
| DatabaseReleaseRepository, | ||||||||||||||||||||||||||||||
| evaluateRepository, | ||||||||||||||||||||||||||||||
| VariableReleaseManager, | ||||||||||||||||||||||||||||||
| VersionReleaseManager, | ||||||||||||||||||||||||||||||
| } from "@ctrlplane/rule-engine"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| import { env } from "../config.js"; | ||||||||||||||||||||||||||||||
| import { ReleaseTargetMutex } from "../releases/mutex.js"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const log = logger.child({ | ||||||||||||||||||||||||||||||
| worker: "policy-evaluate", | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| const log = logger.child({ worker: "policy-evaluate" }); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const createJobForRelease = async (tx: Tx, chosenReleaseId: string) => { | ||||||||||||||||||||||||||||||
| const release = await tx.query.release.findFirst({ | ||||||||||||||||||||||||||||||
| where: eq(schema.release.id, chosenReleaseId), | ||||||||||||||||||||||||||||||
| const createRelease = async ( | ||||||||||||||||||||||||||||||
| tx: Tx, | ||||||||||||||||||||||||||||||
| release: { id: string; versionReleaseId: string; variableReleaseId: string }, | ||||||||||||||||||||||||||||||
| ) => { | ||||||||||||||||||||||||||||||
| // Get version release and related data | ||||||||||||||||||||||||||||||
| const versionRelease = await tx.query.versionRelease.findFirst({ | ||||||||||||||||||||||||||||||
| where: eq(schema.versionRelease.id, release.versionReleaseId), | ||||||||||||||||||||||||||||||
| with: { | ||||||||||||||||||||||||||||||
| variables: true, | ||||||||||||||||||||||||||||||
| version: { with: { deployment: { with: { jobAgent: true } } } }, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| if (!versionRelease) throw new Error("Failed to get release"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (release == null) throw new Error("Failed to get release"); | ||||||||||||||||||||||||||||||
| // Extract job agent info | ||||||||||||||||||||||||||||||
| const { jobAgent, jobAgentConfig: deploymentJobAgentConfig } = | ||||||||||||||||||||||||||||||
| versionRelease.version.deployment; | ||||||||||||||||||||||||||||||
| if (!jobAgent) throw new Error("Deployment has no Job Agent"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const { version } = release; | ||||||||||||||||||||||||||||||
| const { deployment } = version; | ||||||||||||||||||||||||||||||
| const { jobAgent, jobAgentConfig: deploymentJobAgentConfig } = deployment; | ||||||||||||||||||||||||||||||
| if (jobAgent == null) throw new Error("Deployment has no Job Agent"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const jobAgentId = jobAgent.id; | ||||||||||||||||||||||||||||||
| const jobAgentConfig = _.merge(jobAgent.config, deploymentJobAgentConfig); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Get variable release data | ||||||||||||||||||||||||||||||
| const variableRelease = await tx.query.variableSetRelease.findFirst({ | ||||||||||||||||||||||||||||||
| where: eq(schema.variableSetRelease.id, release.variableReleaseId), | ||||||||||||||||||||||||||||||
| with: { values: { with: { variableValueSnapshot: true } } }, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| if (!variableRelease) throw new Error("Failed to get variable release"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Create job | ||||||||||||||||||||||||||||||
| const job = await tx | ||||||||||||||||||||||||||||||
| .insert(schema.job) | ||||||||||||||||||||||||||||||
| .values({ | ||||||||||||||||||||||||||||||
| jobAgentId, | ||||||||||||||||||||||||||||||
| jobAgentId: jobAgent.id, | ||||||||||||||||||||||||||||||
| jobAgentConfig, | ||||||||||||||||||||||||||||||
| status: "pending", | ||||||||||||||||||||||||||||||
| reason: "policy_passing", | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
| .returning() | ||||||||||||||||||||||||||||||
| .then(takeFirst); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (release.variables.length > 0) | ||||||||||||||||||||||||||||||
| // Add job variables if any exist | ||||||||||||||||||||||||||||||
| if (variableRelease.values.length > 0) { | ||||||||||||||||||||||||||||||
| await tx.insert(schema.jobVariable).values( | ||||||||||||||||||||||||||||||
| release.variables.map((v) => ({ | ||||||||||||||||||||||||||||||
| variableRelease.values.map((v) => ({ | ||||||||||||||||||||||||||||||
| jobId: job.id, | ||||||||||||||||||||||||||||||
| key: v.key, | ||||||||||||||||||||||||||||||
| sensitive: v.sensitive, | ||||||||||||||||||||||||||||||
| value: v.value, | ||||||||||||||||||||||||||||||
| key: v.variableValueSnapshot.key, | ||||||||||||||||||||||||||||||
| sensitive: v.variableValueSnapshot.sensitive, | ||||||||||||||||||||||||||||||
| value: v.variableValueSnapshot.value, | ||||||||||||||||||||||||||||||
| })), | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Create release record | ||||||||||||||||||||||||||||||
| await tx.insert(schema.releaseJob).values({ | ||||||||||||||||||||||||||||||
| releaseId: release.id, | ||||||||||||||||||||||||||||||
| jobId: job.id, | ||||||||||||||||||||||||||||||
| releaseId: chosenReleaseId, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return job; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const handleVersionRelease = async (releaseTarget: any) => { | ||||||||||||||||||||||||||||||
| const vrm = new VersionReleaseManager(db, { | ||||||||||||||||||||||||||||||
| ...releaseTarget, | ||||||||||||||||||||||||||||||
| workspaceId: releaseTarget.resource.workspaceId, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const { chosenCandidate } = await vrm.evaluate(); | ||||||||||||||||||||||||||||||
| if (!chosenCandidate) throw new Error("Failed to get chosen release"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const { release: versionRelease } = await vrm.upsertRelease( | ||||||||||||||||||||||||||||||
| chosenCandidate.id, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return versionRelease; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const handleVariableRelease = async (releaseTarget: any) => { | ||||||||||||||||||||||||||||||
| const varrm = new VariableReleaseManager(db, { | ||||||||||||||||||||||||||||||
| ...releaseTarget, | ||||||||||||||||||||||||||||||
| workspaceId: releaseTarget.resource.workspaceId, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
|
Comment on lines
+95
to
+99
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add proper typing to function parameter Similar to -const handleVariableRelease = async (releaseTarget: any) => {
+const handleVariableRelease = async (releaseTarget: schema.ReleaseTarget & {
+ resource: schema.Resource;
+ environment: schema.Environment;
+ deployment: schema.Deployment;
+}) => {
const varrm = new VariableReleaseManager(db, {
...releaseTarget,
workspaceId: releaseTarget.resource.workspaceId,
});📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const { chosenCandidate: variableValues } = await varrm.evaluate(); | ||||||||||||||||||||||||||||||
| const { release: variableRelease } = | ||||||||||||||||||||||||||||||
| await varrm.upsertRelease(variableValues); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return variableRelease; | ||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export const evaluateReleaseTarget = createWorker( | ||||||||||||||||||||||||||||||
| Channel.EvaluateReleaseTarget, | ||||||||||||||||||||||||||||||
| async (job) => { | ||||||||||||||||||||||||||||||
| const mutex = await ReleaseTargetMutex.lock(job.data); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| // Get release target | ||||||||||||||||||||||||||||||
| const releaseTarget = await db.query.releaseTarget.findFirst({ | ||||||||||||||||||||||||||||||
| where: and( | ||||||||||||||||||||||||||||||
| eq(schema.releaseTarget.resourceId, job.data.resourceId), | ||||||||||||||||||||||||||||||
| eq(schema.releaseTarget.environmentId, job.data.environmentId), | ||||||||||||||||||||||||||||||
| eq(schema.releaseTarget.deploymentId, job.data.deploymentId), | ||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||
| with: { | ||||||||||||||||||||||||||||||
| resource: true, | ||||||||||||||||||||||||||||||
| environment: true, | ||||||||||||||||||||||||||||||
| deployment: true, | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| with: { resource: true, environment: true, deployment: true }, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| if (releaseTarget == null) | ||||||||||||||||||||||||||||||
| throw new Error("Failed to get release target"); | ||||||||||||||||||||||||||||||
| if (!releaseTarget) throw new Error("Failed to get release target"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const releaseRepository = await DatabaseReleaseRepository.create({ | ||||||||||||||||||||||||||||||
| ...releaseTarget, | ||||||||||||||||||||||||||||||
| workspaceId: releaseTarget.resource.workspaceId, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| const versionRelease = await handleVersionRelease(releaseTarget); | ||||||||||||||||||||||||||||||
| const variableRelease = await handleVariableRelease(releaseTarget); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const { chosenRelease } = await evaluateRepository(releaseRepository); | ||||||||||||||||||||||||||||||
| if (chosenRelease == null) | ||||||||||||||||||||||||||||||
| throw new Error("Failed to get chosen release"); | ||||||||||||||||||||||||||||||
| const release = await db | ||||||||||||||||||||||||||||||
| .insert(schema.release) | ||||||||||||||||||||||||||||||
| .values({ | ||||||||||||||||||||||||||||||
| versionReleaseId: versionRelease.id, | ||||||||||||||||||||||||||||||
| variableReleaseId: variableRelease.id, | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
| .onConflictDoNothing() | ||||||||||||||||||||||||||||||
| .returning() | ||||||||||||||||||||||||||||||
| .then(takeFirst); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (env.NODE_ENV === "development") { | ||||||||||||||||||||||||||||||
| // In development dispatch the job immediately | ||||||||||||||||||||||||||||||
| const job = await db.transaction((tx) => | ||||||||||||||||||||||||||||||
| createJobForRelease(tx, chosenRelease.id), | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| const job = await db.transaction((tx) => createRelease(tx, release)); | ||||||||||||||||||||||||||||||
| getQueue(Channel.DispatchJob).add(job.id, { jobId: job.id }); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential security concern for sensitive values.
Storing sensitive variables in plain text might pose risks. Consider encrypting or masking sensitive values in the database or restricting access to these fields.
Also applies to: 68-68