migrate security parser to sh-syntax and async validation

This commit is contained in:
2026-02-23 16:13:32 -05:00
parent 1363bceecc
commit c65b9ed007
9 changed files with 492 additions and 369 deletions

View File

@@ -83,6 +83,80 @@ export function parseExecutionEnvPolicy(input: unknown): ExecutionEnvPolicy {
};
}
export const commandTargetSchema = z
.object({
binary: stringTokenSchema,
args: z.array(stringTokenSchema).default([]),
})
.strict();
export type CommandTarget = z.infer<typeof commandTargetSchema>;
export const commandTargetsSchema = z.array(commandTargetSchema);
export function parseCommandTargets(input: unknown): CommandTarget[] {
const parsed = commandTargetsSchema.parse(input);
return parsed.map((target) => ({
binary: target.binary,
args: [...target.args],
}));
}
export const parsedShellAssignmentSchema = z
.object({
raw: stringTokenSchema,
key: stringTokenSchema,
value: z.string(),
})
.strict();
export type ParsedShellAssignment = z.infer<typeof parsedShellAssignmentSchema>;
export const parsedShellCommandSchema = z
.object({
binary: stringTokenSchema,
args: z.array(stringTokenSchema).default([]),
flags: z.array(stringTokenSchema).default([]),
assignments: z.array(parsedShellAssignmentSchema).default([]),
redirects: z.array(stringTokenSchema).default([]),
words: z.array(stringTokenSchema).default([]),
})
.strict();
export type ParsedShellCommand = z.infer<typeof parsedShellCommandSchema>;
export const parsedShellScriptSchema = z
.object({
commandCount: z.number().int().nonnegative(),
commands: z.array(parsedShellCommandSchema).default([]),
})
.strict()
.refine((value) => value.commandCount === value.commands.length, {
message: "commandCount must match commands.length",
path: ["commandCount"],
});
export type ParsedShellScript = z.infer<typeof parsedShellScriptSchema>;
export function parseParsedShellScript(input: unknown): ParsedShellScript {
const parsed = parsedShellScriptSchema.parse(input);
return {
commandCount: parsed.commandCount,
commands: parsed.commands.map((command) => ({
binary: command.binary,
args: [...command.args],
flags: [...command.flags],
assignments: command.assignments.map((assignment) => ({
raw: assignment.raw,
key: assignment.key,
value: assignment.value,
})),
redirects: [...command.redirects],
words: [...command.words],
})),
};
}
export type SecurityViolationHandling = "hard_abort" | "validation_fail";
export const securityViolationHandlingSchema = z.union([