MCPcopy Create free account
hub / github.com/TestSprite/testsprite-cli / readPlanStepsFileGuarded

Function readPlanStepsFileGuarded

src/commands/test.ts:1077–1127  ·  view source on GitHub ↗

* Read + validate the `--steps` file. Returns the parsed `planSteps` * array on success; throws a typed `VALIDATION_ERROR` envelope on any * schema problem with a `details.field` pointer the caller can act on. * * Stat-first guard mirrors piece-2's `readCodeFileGuarded`: oversize * payloads fai

(path: string)

Source from the content-addressed store, hash-verified

1075 * 256 KB (vs. 350 KB for code) per the piece-6 spec.
1076 */
1077function readPlanStepsFileGuarded(path: string): CliPlanStep[] {
1078 const absolute = resolveAbsolute(path);
1079
1080 let stat;
1081 try {
1082 stat = statSync(absolute);
1083 } catch (err) {
1084 const code = (err as NodeJS.ErrnoException).code;
1085 if (code === 'ENOENT') {
1086 throw localValidationError('steps', `file does not exist: ${path}`);
1087 }
1088 if (code === 'EACCES') {
1089 throw localValidationError('steps', `permission denied reading ${path}`);
1090 }
1091 const reason = err instanceof Error ? err.message : 'unknown error';
1092 throw localValidationError('steps', `cannot stat ${path}: ${reason}`);
1093 }
1094 if (stat.size > MAX_PLAN_STEPS_BODY_BYTES) {
1095 throw ApiError.fromEnvelope({
1096 error: {
1097 code: 'PAYLOAD_TOO_LARGE',
1098 message: `Plan-steps body exceeds the 256 KB CLI cap (${stat.size} bytes).`,
1099 nextAction: 'Split into multiple smaller tests or trim step descriptions.',
1100 requestId: 'local',
1101 details: {
1102 field: 'steps',
1103 sizeBytes: stat.size,
1104 maxBytes: MAX_PLAN_STEPS_BODY_BYTES,
1105 },
1106 },
1107 });
1108 }
1109
1110 let raw;
1111 try {
1112 raw = stripBom(readFileSync(absolute, 'utf8'));
1113 } catch (err) {
1114 const reason = err instanceof Error ? err.message : 'unknown error';
1115 throw localValidationError('steps', `cannot read ${path}: ${reason}`);
1116 }
1117
1118 let parsed: unknown;
1119 try {
1120 parsed = JSON.parse(raw);
1121 } catch (err) {
1122 const reason = err instanceof Error ? err.message : 'unknown error';
1123 throw localValidationError('steps', `not valid JSON: ${reason}`);
1124 }
1125
1126 return assertPlanStepsShape(parsed);
1127}
1128
1129/**
1130 * Type-narrow + validate a parsed `{ planSteps: [...] }` envelope.

Callers 1

runPlanPutFunction · 0.85

Calls 6

resolveAbsoluteFunction · 0.85
stripBomFunction · 0.85
readFileSyncFunction · 0.85
assertPlanStepsShapeFunction · 0.85
fromEnvelopeMethod · 0.80
localValidationErrorFunction · 0.70

Tested by

no test coverage detected