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
25 changes: 13 additions & 12 deletions src/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,52 +185,53 @@ interface ValidationConstraints {
*/
function buildValidationFunction(
constraints: ValidationConstraints,
propertyName: string,
): ((value: unknown) => boolean) | undefined {
const checks: string[] = [];

// String length validation
if (constraints.minLength !== undefined) {
checks.push(
`if (typeof value === "string" && value.length < ${constraints.minLength}) return "Value must be at least ${constraints.minLength} characters"`,
`if (typeof value === "string" && value.length < ${constraints.minLength}) return "'${propertyName}' must be at least ${constraints.minLength} characters"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
}
if (constraints.maxLength !== undefined) {
checks.push(
`if (typeof value === "string" && value.length > ${constraints.maxLength}) return "Value must be at most ${constraints.maxLength} characters"`,
`if (typeof value === "string" && value.length > ${constraints.maxLength}) return "'${propertyName}' must be at most ${constraints.maxLength} characters"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
}

// Numeric validation
if (constraints.minValue !== undefined) {
checks.push(
`if (typeof value === "number" && value < ${constraints.minValue}) return "Value must be at least ${constraints.minValue}"`,
`if (typeof value === "number" && value < ${constraints.minValue}) return "'${propertyName}' must be at least ${constraints.minValue}"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
}
if (constraints.maxValue !== undefined) {
checks.push(
`if (typeof value === "number" && value > ${constraints.maxValue}) return "Value must be at most ${constraints.maxValue}"`,
`if (typeof value === "number" && value > ${constraints.maxValue}) return "'${propertyName}' must be at most ${constraints.maxValue}"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
}

// Integer validation
if (constraints.isInteger) {
checks.push(
`if (typeof value === "number" && !Number.isInteger(value)) return "Value must be an integer"`,
`if (typeof value === "number" && !Number.isInteger(value)) return "'${propertyName}' must be an integer"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
}

// Float validation (ensure it's a finite number)
if (constraints.isFloat) {
checks.push(
`if (typeof value === "number" && !Number.isFinite(value)) return "Value must be a finite number"`,
`if (typeof value === "number" && !Number.isFinite(value)) return "'${propertyName}' must be a finite number"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
}

// Pattern validation
if (constraints.pattern) {
const escapedPattern = constraints.pattern.replace(/\\/g, "\\\\");
checks.push(
`if (typeof value === "string" && !new RegExp("${escapedPattern}").test(value)) return "Value must match pattern ${escapedPattern}"`,
`if (typeof value === "string" && !new RegExp("${escapedPattern}").test(value)) return "'${propertyName}' must match pattern ${escapedPattern}"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
}

Expand All @@ -239,22 +240,22 @@ function buildValidationFunction(
switch (constraints.dateTimeType) {
case "utcDateTime":
checks.push(
`if (typeof value === "string") { const d = new Date(value); if (isNaN(d.getTime())) return "Value must be a valid UTC date-time string"; }`,
`if (typeof value === "string") { const d = new Date(value); if (isNaN(d.getTime())) return "'${propertyName}' must be a valid UTC date-time string"; }`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
break;
case "offsetDateTime":
checks.push(
`if (typeof value === "string") { const d = new Date(value); if (isNaN(d.getTime())) return "Value must be a valid offset date-time string"; }`,
`if (typeof value === "string") { const d = new Date(value); if (isNaN(d.getTime())) return "'${propertyName}' must be a valid offset date-time string"; }`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
break;
case "plainDate":
checks.push(
`if (typeof value === "string" && !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return "Value must be a valid date (YYYY-MM-DD)"`,
`if (typeof value === "string" && !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return "'${propertyName}' must be a valid date (YYYY-MM-DD)"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
break;
case "plainTime":
checks.push(
`if (typeof value === "string" && !/^\\d{2}:\\d{2}(:\\d{2})?(\\.\\d+)?$/.test(value)) return "Value must be a valid time (HH:MM:SS)"`,
`if (typeof value === "string" && !/^\\d{2}:\\d{2}(:\\d{2})?(\\.\\d+)?$/.test(value)) return "'${propertyName}' must be a valid time (HH:MM:SS)"`,
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The property name is being directly interpolated into error message strings that are later evaluated using eval(). This creates a potential code injection vulnerability if property names contain single quotes, backslashes, or other special characters. The property name should be escaped before being interpolated into the string to prevent breaking out of the string literal or injecting malicious code.

Copilot uses AI. Check for mistakes.
);
break;
}
Expand Down Expand Up @@ -642,7 +643,7 @@ function emitAttribute(ctx: EmitContext, prop: ModelProperty): Attribute {

// Add validation if constraints are present
const constraints = getValidationConstraints(ctx, prop);
const validateFn = buildValidationFunction(constraints);
const validateFn = buildValidationFunction(constraints, prop.name);
if (validateFn) {
// @ts-expect-error - validate is a valid ElectroDB attribute property
attr.validate = validateFn;
Expand Down
6 changes: 3 additions & 3 deletions test/electrodb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ suite("ElectroDB Runtime Validation", () => {
title: "Test Task",
settings: [],
}).params(),
/Value must be at least 25 characters/,
/'pk' must be at least 25 characters/,
);
});

Expand All @@ -85,7 +85,7 @@ suite("ElectroDB Runtime Validation", () => {
title: "Test Task",
settings: [],
}).params(),
/Value must be at most 25 characters/,
/'pk' must be at most 25 characters/,
);
});

Expand Down Expand Up @@ -154,7 +154,7 @@ suite("ElectroDB Runtime Validation", () => {
count: 3.14,
settings: [],
}).params(),
/Value must be an integer/,
/'count' must be an integer/,
);
});

Expand Down
14 changes: 7 additions & 7 deletions test/entities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ suite("Validation Functions", () => {
// Throws Error for invalid values
assert.throws(
() => validate("too-short"),
/Value must be at least 25 characters/,
/'pk' must be at least 25 characters/,
);
});

Expand All @@ -157,7 +157,7 @@ suite("Validation Functions", () => {
// Throws Error for invalid values
assert.throws(
() => validate("this-string-is-way-too-long-for-uuid"),
/Value must be at most 25 characters/,
/'pk' must be at most 25 characters/,
);
});
},
Expand All @@ -174,7 +174,7 @@ suite("Validation Functions", () => {
const validate = Person.attributes.firstName.validate;
assert.throws(
() => validate("A".repeat(65)),
/Value must be at most 64 characters/,
/'firstName' must be at most 64 characters/,
);
});
});
Expand All @@ -189,8 +189,8 @@ suite("Validation Functions", () => {

test("rejects non-integer values", () => {
const validate = Person.attributes.age.validate;
assert.throws(() => validate(25.5), /Value must be an integer/);
assert.throws(() => validate(Math.PI), /Value must be an integer/);
assert.throws(() => validate(25.5), /'age' must be an integer/);
assert.throws(() => validate(Math.PI), /'age' must be an integer/);
});
});

Expand All @@ -206,11 +206,11 @@ suite("Validation Functions", () => {
const validate = Person.attributes.birthDate.validate;
assert.throws(
() => validate("not-a-date"),
/Value must be a valid UTC date-time string/,
/'birthDate' must be a valid UTC date-time string/,
);
assert.throws(
() => validate("invalid"),
/Value must be a valid UTC date-time string/,
/'birthDate' must be a valid UTC date-time string/,
);
});
});
Expand Down