@fractary/faber-cli 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/plan/index.d.ts +11 -0
- package/dist/commands/plan/index.d.ts.map +1 -0
- package/dist/commands/plan/index.js +383 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/lib/anthropic-client.d.ts +69 -0
- package/dist/lib/anthropic-client.d.ts.map +1 -0
- package/dist/lib/anthropic-client.js +225 -0
- package/dist/lib/config.d.ts +30 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +127 -0
- package/dist/lib/repo-client.d.ts +81 -0
- package/dist/lib/repo-client.d.ts.map +1 -0
- package/dist/lib/repo-client.js +105 -0
- package/dist/types/config.d.ts +34 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +6 -0
- package/dist/utils/prompt.d.ts +8 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +19 -0
- package/dist/utils/validation.d.ts +71 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +157 -0
- package/package.json +1 -1
|
@@ -27,4 +27,75 @@ export declare function parseOptionalInteger(value: string | undefined, fieldNam
|
|
|
27
27
|
* @throws Error if value is not a valid positive integer
|
|
28
28
|
*/
|
|
29
29
|
export declare function parsePositiveInteger(value: string, fieldName: string): number;
|
|
30
|
+
/**
|
|
31
|
+
* Validates work ID format
|
|
32
|
+
* Work IDs must be numeric (GitHub issue numbers)
|
|
33
|
+
*
|
|
34
|
+
* @param workId - Work ID to validate
|
|
35
|
+
* @returns True if valid
|
|
36
|
+
* @throws Error if invalid
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateWorkId(workId: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Validates multiple comma-separated work IDs
|
|
41
|
+
*
|
|
42
|
+
* @param workIds - Comma-separated work IDs
|
|
43
|
+
* @returns Array of validated work IDs
|
|
44
|
+
* @throws Error if any ID is invalid
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateWorkIds(workIds: string): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Validates label format
|
|
49
|
+
* Labels must be alphanumeric with hyphens, colons, and underscores only
|
|
50
|
+
*
|
|
51
|
+
* @param label - Label to validate
|
|
52
|
+
* @returns True if valid
|
|
53
|
+
* @throws Error if invalid
|
|
54
|
+
*/
|
|
55
|
+
export declare function validateLabel(label: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Validates multiple comma-separated labels
|
|
58
|
+
*
|
|
59
|
+
* @param labels - Comma-separated labels
|
|
60
|
+
* @returns Array of validated labels
|
|
61
|
+
* @throws Error if any label is invalid
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateLabels(labels: string): string[];
|
|
64
|
+
/**
|
|
65
|
+
* Validates workflow name format
|
|
66
|
+
* Workflow names must be alphanumeric with hyphens and underscores
|
|
67
|
+
*
|
|
68
|
+
* @param workflowName - Workflow name to validate
|
|
69
|
+
* @returns True if valid
|
|
70
|
+
* @throws Error if invalid
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateWorkflowName(workflowName: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Validates and sanitizes file path to prevent path traversal
|
|
75
|
+
* Ensures path doesn't contain dangerous patterns like ../, absolute paths, etc.
|
|
76
|
+
*
|
|
77
|
+
* @param filePath - File path to validate
|
|
78
|
+
* @param baseDir - Base directory that path must be relative to (optional)
|
|
79
|
+
* @returns Sanitized path
|
|
80
|
+
* @throws Error if path is unsafe
|
|
81
|
+
*/
|
|
82
|
+
export declare function validateSafePath(filePath: string, baseDir?: string): string;
|
|
83
|
+
/**
|
|
84
|
+
* Validates JSON response size to prevent DoS attacks
|
|
85
|
+
*
|
|
86
|
+
* @param jsonString - JSON string to validate
|
|
87
|
+
* @param maxSizeBytes - Maximum allowed size in bytes (default: 1MB)
|
|
88
|
+
* @returns True if valid
|
|
89
|
+
* @throws Error if too large
|
|
90
|
+
*/
|
|
91
|
+
export declare function validateJsonSize(jsonString: string, maxSizeBytes?: number): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Validates plan ID format
|
|
94
|
+
* Plan IDs follow format: fractary-faber-{work-id}-{YYYYMMDD}-{HHMMSS}
|
|
95
|
+
*
|
|
96
|
+
* @param planId - Plan ID to validate
|
|
97
|
+
* @returns True if valid
|
|
98
|
+
* @throws Error if invalid
|
|
99
|
+
*/
|
|
100
|
+
export declare function validatePlanId(planId: string): boolean;
|
|
30
101
|
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAY1E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMrG;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ7E"}
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAY1E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMrG;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ7E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAWtD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBzD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAYpD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBvD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAYlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAoC3E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,GAAE,MAAoB,GAAG,OAAO,CAYhG;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAUtD"}
|
package/dist/utils/validation.js
CHANGED
|
@@ -47,3 +47,160 @@ export function parsePositiveInteger(value, fieldName) {
|
|
|
47
47
|
}
|
|
48
48
|
return parsed;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Validates work ID format
|
|
52
|
+
* Work IDs must be numeric (GitHub issue numbers)
|
|
53
|
+
*
|
|
54
|
+
* @param workId - Work ID to validate
|
|
55
|
+
* @returns True if valid
|
|
56
|
+
* @throws Error if invalid
|
|
57
|
+
*/
|
|
58
|
+
export function validateWorkId(workId) {
|
|
59
|
+
// Work IDs must be numeric (1-8 digits for GitHub issue numbers)
|
|
60
|
+
const workIdPattern = /^\d{1,8}$/;
|
|
61
|
+
if (!workIdPattern.test(workId)) {
|
|
62
|
+
throw new Error(`Invalid work ID format: "${workId}". Work IDs must be numeric (e.g., "123", "456").`);
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validates multiple comma-separated work IDs
|
|
68
|
+
*
|
|
69
|
+
* @param workIds - Comma-separated work IDs
|
|
70
|
+
* @returns Array of validated work IDs
|
|
71
|
+
* @throws Error if any ID is invalid
|
|
72
|
+
*/
|
|
73
|
+
export function validateWorkIds(workIds) {
|
|
74
|
+
const ids = workIds.split(',').map(id => id.trim()).filter(Boolean);
|
|
75
|
+
if (ids.length === 0) {
|
|
76
|
+
throw new Error('No work IDs provided');
|
|
77
|
+
}
|
|
78
|
+
if (ids.length > 50) {
|
|
79
|
+
throw new Error(`Too many work IDs (${ids.length}). Maximum is 50 to prevent API overload.`);
|
|
80
|
+
}
|
|
81
|
+
// Validate each ID
|
|
82
|
+
ids.forEach(id => validateWorkId(id));
|
|
83
|
+
return ids;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validates label format
|
|
87
|
+
* Labels must be alphanumeric with hyphens, colons, and underscores only
|
|
88
|
+
*
|
|
89
|
+
* @param label - Label to validate
|
|
90
|
+
* @returns True if valid
|
|
91
|
+
* @throws Error if invalid
|
|
92
|
+
*/
|
|
93
|
+
export function validateLabel(label) {
|
|
94
|
+
// Labels: alphanumeric, hyphens, colons, underscores (GitHub label format)
|
|
95
|
+
// Examples: "workflow:etl", "status:approved", "priority-high"
|
|
96
|
+
const labelPattern = /^[a-zA-Z0-9_:-]{1,50}$/;
|
|
97
|
+
if (!labelPattern.test(label)) {
|
|
98
|
+
throw new Error(`Invalid label format: "${label}". Labels must be alphanumeric with hyphens, colons, or underscores (max 50 chars).`);
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Validates multiple comma-separated labels
|
|
104
|
+
*
|
|
105
|
+
* @param labels - Comma-separated labels
|
|
106
|
+
* @returns Array of validated labels
|
|
107
|
+
* @throws Error if any label is invalid
|
|
108
|
+
*/
|
|
109
|
+
export function validateLabels(labels) {
|
|
110
|
+
const labelArray = labels.split(',').map(l => l.trim()).filter(Boolean);
|
|
111
|
+
if (labelArray.length === 0) {
|
|
112
|
+
throw new Error('No labels provided');
|
|
113
|
+
}
|
|
114
|
+
if (labelArray.length > 20) {
|
|
115
|
+
throw new Error(`Too many labels (${labelArray.length}). Maximum is 20.`);
|
|
116
|
+
}
|
|
117
|
+
// Validate each label
|
|
118
|
+
labelArray.forEach(label => validateLabel(label));
|
|
119
|
+
return labelArray;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Validates workflow name format
|
|
123
|
+
* Workflow names must be alphanumeric with hyphens and underscores
|
|
124
|
+
*
|
|
125
|
+
* @param workflowName - Workflow name to validate
|
|
126
|
+
* @returns True if valid
|
|
127
|
+
* @throws Error if invalid
|
|
128
|
+
*/
|
|
129
|
+
export function validateWorkflowName(workflowName) {
|
|
130
|
+
// Workflow names: alphanumeric, hyphens, underscores
|
|
131
|
+
// Examples: "etl", "data-pipeline", "bugfix"
|
|
132
|
+
const workflowPattern = /^[a-zA-Z0-9_-]{1,50}$/;
|
|
133
|
+
if (!workflowPattern.test(workflowName)) {
|
|
134
|
+
throw new Error(`Invalid workflow name: "${workflowName}". Workflow names must be alphanumeric with hyphens or underscores (max 50 chars).`);
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Validates and sanitizes file path to prevent path traversal
|
|
140
|
+
* Ensures path doesn't contain dangerous patterns like ../, absolute paths, etc.
|
|
141
|
+
*
|
|
142
|
+
* @param filePath - File path to validate
|
|
143
|
+
* @param baseDir - Base directory that path must be relative to (optional)
|
|
144
|
+
* @returns Sanitized path
|
|
145
|
+
* @throws Error if path is unsafe
|
|
146
|
+
*/
|
|
147
|
+
export function validateSafePath(filePath, baseDir) {
|
|
148
|
+
// Remove any null bytes
|
|
149
|
+
if (filePath.includes('\0')) {
|
|
150
|
+
throw new Error('Path contains null bytes');
|
|
151
|
+
}
|
|
152
|
+
// Check for path traversal patterns
|
|
153
|
+
const dangerousPatterns = [
|
|
154
|
+
/\.\./, // Parent directory (..)
|
|
155
|
+
/^\//, // Absolute path
|
|
156
|
+
/^[a-zA-Z]:\\/, // Windows absolute path
|
|
157
|
+
/^~\//, // Home directory
|
|
158
|
+
];
|
|
159
|
+
for (const pattern of dangerousPatterns) {
|
|
160
|
+
if (pattern.test(filePath)) {
|
|
161
|
+
throw new Error(`Unsafe path detected: "${filePath}". Paths must be relative and cannot contain "..", absolute paths, or home directory references.`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Normalize path (remove redundant separators, etc.)
|
|
165
|
+
const normalized = filePath.replace(/\/+/g, '/').replace(/\\/g, '/');
|
|
166
|
+
// If base directory provided, ensure path starts with it
|
|
167
|
+
if (baseDir) {
|
|
168
|
+
const normalizedBase = baseDir.replace(/\/+$/, '');
|
|
169
|
+
if (!normalized.startsWith(normalizedBase)) {
|
|
170
|
+
throw new Error(`Path "${filePath}" must be within base directory "${baseDir}"`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return normalized;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Validates JSON response size to prevent DoS attacks
|
|
177
|
+
*
|
|
178
|
+
* @param jsonString - JSON string to validate
|
|
179
|
+
* @param maxSizeBytes - Maximum allowed size in bytes (default: 1MB)
|
|
180
|
+
* @returns True if valid
|
|
181
|
+
* @throws Error if too large
|
|
182
|
+
*/
|
|
183
|
+
export function validateJsonSize(jsonString, maxSizeBytes = 1024 * 1024) {
|
|
184
|
+
const sizeBytes = Buffer.byteLength(jsonString, 'utf8');
|
|
185
|
+
if (sizeBytes > maxSizeBytes) {
|
|
186
|
+
const sizeMB = (sizeBytes / 1024 / 1024).toFixed(2);
|
|
187
|
+
const maxMB = (maxSizeBytes / 1024 / 1024).toFixed(2);
|
|
188
|
+
throw new Error(`JSON response too large: ${sizeMB}MB (maximum: ${maxMB}MB). This may indicate an API error or DoS attempt.`);
|
|
189
|
+
}
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Validates plan ID format
|
|
194
|
+
* Plan IDs follow format: fractary-faber-{work-id}-{YYYYMMDD}-{HHMMSS}
|
|
195
|
+
*
|
|
196
|
+
* @param planId - Plan ID to validate
|
|
197
|
+
* @returns True if valid
|
|
198
|
+
* @throws Error if invalid
|
|
199
|
+
*/
|
|
200
|
+
export function validatePlanId(planId) {
|
|
201
|
+
const planIdPattern = /^fractary-faber-\d+-\d{8}-\d{6}$/;
|
|
202
|
+
if (!planIdPattern.test(planId)) {
|
|
203
|
+
throw new Error(`Invalid plan ID format: "${planId}". Expected format: fractary-faber-{work-id}-{YYYYMMDD}-{HHMMSS}`);
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
}
|