Conversation
…file system simulation
…extend CliFs functionality
…te util BREAKING CHANGE: HBS templating are removed, use defineTemplate to declare a template file
…th optional properties
…ollections and prevent memory leaks
…ollections and prevent memory leaks
…nfig and cleaning up generated files
…or existing config types
Feat add config
Feat create template command
…g consistency and update imports to use `.js` file extensions
…d update integration tests
…er rendering control - Added `renderMode` to `CommandOptions`, `TaskLoggerOptions`, and related interfaces for task rendering flexibility. - Replaced `verbose` with `renderMode` in `TaskLogger` to unify and simplify rendering logic. - Updated `SIGINT` and `SIGTERM` handling in project templates for graceful shutdown. - Refactored logger behavior in tasks to conditionally adjust log levels based on `renderMode`.
- Deleted outdated VuePress components (`CLI.vue`, `HomeBody.vue`, `SupportOptions.vue`, `SupportUsBlock.vue`). - Removed `website.yml` workflow from `.github/workflows`. - Cleaned up unused `api.json` from `public` directory. `api.yml` to `website.yml` for
…ization - Updated `run` method to use `runSync` for synchronous execution with inherited stdio. - Enhanced `init` method by appending `--db` and custom output path to `prisma init` command.
| return `z.any().refine((value) => !${parseSchema(schema.not, { | ||
| ...refs, | ||
| path: [...refs.path, "not"] | ||
| })}.safeParse(value).success, "Invalid input: Should NOT be valid against schema")`; |
Check warning
Code scanning / CodeQL
Improper code sanitization Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 14 days ago
General approach: Introduce a small, reusable sanitizer that post‑processes JSON.stringify output (or raw strings) to escape characters that can break out of JavaScript or a <script> tag (<, >, /, \, control chars, U+2028, U+2029, etc.), then use it at every point where untrusted schema values are interpolated into generated JavaScript strings.
Best concrete fix without changing semantics:
- Define a local
escapeUnsafeCharshelper (and itscharMap) in one central parser file that already needs it everywhere, e.g.parseSchema.ts. - Use
escapeUnsafeChars(JSON.stringify(...))instead of rawJSON.stringify(...)for:schema.descriptioninaddDescribes.schema.defaultinaddDefaults.
- Export
escapeUnsafeCharsfromparseSchema.ts. - In
parseConst.tsandparseEnum.ts, importescapeUnsafeCharsfrom./parseSchema.jsand wrap theirJSON.stringifycalls:parseConst:z.literal(${escapeUnsafeChars(JSON.stringify(schema.const))}).parseEnum:- Single‑element literal.
- The
z.enumarray elements. - Each literal used inside the
z.union([...]).
- In
parseNot.ts, do not change its logic; the taint comes from the inner schema parsers. Once their interpolations are sanitized, the string returned byparseSchemawill no longer contain unsafe sequences, andparseNotwill transitively be safe.
This preserves functional behavior (still using JSON.stringify for proper JS literals) while adding the necessary escaping for script‑sensitive characters.
| @@ -1,5 +1,6 @@ | ||
| import type {JsonSchemaObject, Serializable} from "../Types.js"; | ||
| import {escapeUnsafeChars} from "./parseSchema.js"; | ||
|
|
||
| export const parseConst = (schema: JsonSchemaObject & {const: Serializable}) => { | ||
| return `z.literal(${JSON.stringify(schema.const)})`; | ||
| return `z.literal(${escapeUnsafeChars(JSON.stringify(schema.const))})`; | ||
| }; |
| @@ -16,6 +16,25 @@ | ||
| import {parseOneOf} from "./parseOneOf.js"; | ||
| import {parseString} from "./parseString.js"; | ||
|
|
||
| const charMap: Record<string, string> = { | ||
| "<": "\\u003C", | ||
| ">": "\\u003E", | ||
| "/": "\\u002F", | ||
| "\\": "\\\\", | ||
| "\b": "\\b", | ||
| "\f": "\\f", | ||
| "\n": "\\n", | ||
| "\r": "\\r", | ||
| "\t": "\\t", | ||
| "\0": "\\0", | ||
| "\u2028": "\\u2028", | ||
| "\u2029": "\\u2029" | ||
| }; | ||
|
|
||
| export const escapeUnsafeChars = (str: string): string => { | ||
| return str.replace(/[<>\/\\\b\f\n\r\t\0\u2028\u2029]/g, (x) => charMap[x] ?? x); | ||
| }; | ||
|
|
||
| export const parseSchema = (schema: JsonSchema, refs: Refs = {seen: new Map(), path: []}, blockMeta?: boolean): string => { | ||
| if (typeof schema !== "object") return schema ? "z.any()" : "z.never()"; | ||
|
|
||
| @@ -64,7 +83,7 @@ | ||
|
|
||
| const addDescribes = (schema: JsonSchemaObject, parsed: string): string => { | ||
| if (schema.description) { | ||
| parsed += `.describe(${JSON.stringify(schema.description)})`; | ||
| parsed += `.describe(${escapeUnsafeChars(JSON.stringify(schema.description))})`; | ||
| } | ||
|
|
||
| return parsed; | ||
| @@ -72,7 +91,7 @@ | ||
|
|
||
| const addDefaults = (schema: JsonSchemaObject, parsed: string): string => { | ||
| if (schema.default !== undefined) { | ||
| parsed += `.default(${JSON.stringify(schema.default)})`; | ||
| parsed += `.default(${escapeUnsafeChars(JSON.stringify(schema.default))})`; | ||
| } | ||
|
|
||
| return parsed; |
| @@ -1,14 +1,15 @@ | ||
| import type {JsonSchemaObject, Serializable} from "../Types.js"; | ||
| import {escapeUnsafeChars} from "./parseSchema.js"; | ||
|
|
||
| export const parseEnum = (schema: JsonSchemaObject & {enum: Serializable[]}) => { | ||
| if (schema.enum.length === 0) { | ||
| return "z.never()"; | ||
| } else if (schema.enum.length === 1) { | ||
| // union does not work when there is only one element | ||
| return `z.literal(${JSON.stringify(schema.enum[0])})`; | ||
| return `z.literal(${escapeUnsafeChars(JSON.stringify(schema.enum[0]))})`; | ||
| } else if (schema.enum.every((x) => typeof x === "string")) { | ||
| return `z.enum([${schema.enum.map((x) => JSON.stringify(x))}])`; | ||
| return `z.enum([${schema.enum.map((x) => escapeUnsafeChars(JSON.stringify(x)))}])`; | ||
| } else { | ||
| return `z.union([${schema.enum.map((x) => `z.literal(${JSON.stringify(x)})`).join(", ")}])`; | ||
| return `z.union([${schema.enum.map((x) => `z.literal(${escapeUnsafeChars(JSON.stringify(x))})`).join(", ")}])`; | ||
| } | ||
| }; |
| import {jsonSchemaToZod} from "./json-schema-to-zod/index.js"; | ||
|
|
||
| function transform(schema: JsonSchema): ZodObject { | ||
| return eval(`(z) => ${jsonSchemaToZod(schema.toJSON(), {zodVersion: 4})}`)(z); |
Check warning
Code scanning / CodeQL
Improper code sanitization Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 14 days ago
General approach: Remove the use of eval with generated code and instead build the zod schema directly in memory. Since the rest of the json-schema-to-zod pipeline already computes a zod schema (or at least can be adapted to), the safest change within the shown snippets is to replace the eval call in toZod.ts with a direct conversion, using the existing JsonSchema → zod conversion functionality from @tsed/schema rather than executing generated source.
Best fix in context: The @tsed/schema JsonSchema instance already has a to API capable of producing various targets, including zod. To avoid touching all the string‑building code (which may still be used for codegen elsewhere) and to eliminate the vulnerable sink (eval), we replace transform so that it does not call jsonSchemaToZod or eval at all. Instead, transform calls schema.to({type: 'zod'}) (or equivalent), casts the result to ZodObject, and returns it. This preserves the external toZod API while removing runtime code construction and execution. Within the constraints given, we only edit packages/cli-mcp/src/utils/toZod.ts and leave the json-schema-to-zod string‑building functions untouched, since they are no longer used in this eval path and therefore no longer constitute a code‑execution risk here.
Concretely:
- In
packages/cli-mcp/src/utils/toZod.ts, remove the import ofjsonSchemaToZod. - Replace the body of
transformso it callsschema.to({type: "zod"})and returns that asZodObject. - Leave
toZod’s public signature unchanged.
This removes the insecure eval sink and thus addresses all the reported variants that flow into that sink, without changing functionality for callers that simply want a zod schema from a JsonSchema instance.
| @@ -1,10 +1,10 @@ | ||
| import {JsonSchema} from "@tsed/schema"; | ||
| import {z, type ZodObject} from "zod"; | ||
|
|
||
| import {jsonSchemaToZod} from "./json-schema-to-zod/index.js"; | ||
|
|
||
| function transform(schema: JsonSchema): ZodObject { | ||
| return eval(`(z) => ${jsonSchemaToZod(schema.toJSON(), {zodVersion: 4})}`)(z); | ||
| // Use JsonSchema's built-in conversion to zod instead of generating and eval'ing code. | ||
| return schema.to({type: "zod", z}) as ZodObject; | ||
| } | ||
|
|
||
| export function toZod(schema: unknown): ZodObject | undefined { |
|
🎉 This PR is included in version 7.0.0-rc.3 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 7.0.0-rc.4 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
…pts, and tasks - Added VitePress guides for `@tsed/cli-core`, `@tsed/cli-prompts`, `@tsed/cli-tasks`, and `@tsed/cli-mcp`. - Included examples covering task orchestration, MCP servers, and multi-step prompts. - Updated `docs/.vitepress/config.mts` to restructure navigation and surface CLI topics prominently. - Synced type-checked examples in `docs/examples` with package READMEs for seamless updates.
…rces, and prompts - Added comprehensive examples for defining MCP tools, resources, and prompts using both functional APIs and decorators. - Enhanced CLI MCP guide with additional sections and examples for interactive usage. - Streamlined code snippets and CLI installation methods across the documentation.
… functional API examples - Removed `docs/examples/cli/prompts-flow.ts` in favor of `prompts-command-decorators.ts` and `prompts-command-functional.ts`. - Updated documentation to reference new examples showcasing both decorator and functional approaches. - Enhanced guide to highlight unified DI integration and streamlined command setup.
- Replaced `execa` with `CliExeca` for improved integration with DI across examples. - Added a new "Commands" guide to detail `@Command`/`command()` usage, lifecycle hooks, and input schema support. - Enhanced navigation in `docs/.vitepress/config.mts` with a dedicated "Commands" entry under the CLI section.
- Introduced comprehensive "Templates" documentation, detailing the `defineTemplate()` API, schema-driven prompts, and render hooks. - Added a "What's new in v7?" guide highlighting major CLI updates, including schema-first inputs, MCP integration, and the HomeKit starter project. - Enhanced navigation in `docs/.vitepress/config.mts` to include new guides. - Updated related CLI articles for consistency with v7 improvements.
|
🎉 This PR is included in version 7.0.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
No description provided.