@aifabrix/builder 2.7.0 → 2.8.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/.cursor/rules/project-rules.mdc +680 -0
- package/lib/app-config.js +10 -0
- package/lib/app-deploy.js +18 -0
- package/lib/app-dockerfile.js +15 -0
- package/lib/app-prompts.js +172 -9
- package/lib/app-push.js +15 -0
- package/lib/app-register.js +14 -0
- package/lib/app-run.js +25 -0
- package/lib/app.js +30 -13
- package/lib/audit-logger.js +9 -4
- package/lib/build.js +8 -0
- package/lib/cli.js +48 -0
- package/lib/commands/login.js +40 -3
- package/lib/config.js +121 -114
- package/lib/environment-deploy.js +305 -0
- package/lib/external-system-deploy.js +262 -0
- package/lib/external-system-generator.js +187 -0
- package/lib/schema/application-schema.json +894 -865
- package/lib/schema/external-datasource.schema.json +49 -1
- package/lib/schema/external-system.schema.json +4 -4
- package/lib/schema/infrastructure-schema.json +1 -1
- package/lib/templates.js +32 -1
- package/lib/utils/device-code.js +10 -2
- package/lib/utils/token-encryption.js +68 -0
- package/lib/validator.js +47 -3
- package/package.json +1 -1
- package/tatus +181 -0
- package/templates/external-system/external-datasource.json.hbs +55 -0
- package/templates/external-system/external-system.json.hbs +37 -0
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: true
|
|
3
|
+
---
|
|
4
|
+
# AI Fabrix Builder - Cursor Rules - ISO 27001 Compliant Development Standards
|
|
5
|
+
|
|
6
|
+
## Project Overview
|
|
7
|
+
|
|
8
|
+
This is the AI Fabrix Builder - a CLI tool for local development infrastructure and Azure deployment. The builder provides:
|
|
9
|
+
- **Local Infrastructure** - Postgres + Redis via Docker Compose
|
|
10
|
+
- **Application Scaffolding** - Generate configuration files for apps
|
|
11
|
+
- **Docker Generation** - Auto-detect runtime and generate Dockerfiles
|
|
12
|
+
- **Template System** - Handlebars-based templates for TypeScript and Python
|
|
13
|
+
- **Azure Deployment** - Push to ACR and deploy via Miso Controller
|
|
14
|
+
- **Configuration Management** - YAML-based config with schema validation
|
|
15
|
+
|
|
16
|
+
Technologies:
|
|
17
|
+
- Node.js/JavaScript (CommonJS modules)
|
|
18
|
+
- Commander.js for CLI
|
|
19
|
+
- Handlebars for template generation
|
|
20
|
+
- js-yaml for YAML parsing
|
|
21
|
+
- AJV for JSON schema validation
|
|
22
|
+
- Jest for testing
|
|
23
|
+
- Docker for containerization
|
|
24
|
+
|
|
25
|
+
## Architecture Patterns
|
|
26
|
+
|
|
27
|
+
### Module Structure
|
|
28
|
+
- All modules use CommonJS (`require`/`module.exports`)
|
|
29
|
+
- Main entry point: `bin/aifabrix.js`
|
|
30
|
+
- Core logic in `lib/` directory
|
|
31
|
+
- Commands in `lib/cli.js` and `lib/commands/`
|
|
32
|
+
- Utilities in `lib/utils/`
|
|
33
|
+
- Schemas in `lib/schema/`
|
|
34
|
+
- Templates in `templates/` directory
|
|
35
|
+
|
|
36
|
+
### File Organization
|
|
37
|
+
```yaml
|
|
38
|
+
lib/
|
|
39
|
+
├── cli.js # CLI command definitions (Commander.js)
|
|
40
|
+
├── commands/ # Command implementations
|
|
41
|
+
├── app.js # App creation and management
|
|
42
|
+
├── generator.js # Deployment JSON generation
|
|
43
|
+
├── validator.js # Schema validation
|
|
44
|
+
├── build.js # Docker build logic
|
|
45
|
+
├── infra.js # Infrastructure management
|
|
46
|
+
├── deployer.js # Azure deployment
|
|
47
|
+
├── templates.js # Template rendering
|
|
48
|
+
├── secrets.js # Secret resolution (kv://)
|
|
49
|
+
├── config.js # Configuration management
|
|
50
|
+
├── utils/ # Utility functions
|
|
51
|
+
└── schema/ # JSON schemas
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### CLI Command Pattern
|
|
55
|
+
Commands are defined in `lib/cli.js` using Commander.js:
|
|
56
|
+
```javascript
|
|
57
|
+
program.command('command-name')
|
|
58
|
+
.description('Command description')
|
|
59
|
+
.option('-f, --flag <value>', 'Option description', defaultValue)
|
|
60
|
+
.action(async (options) => {
|
|
61
|
+
try {
|
|
62
|
+
// Command implementation
|
|
63
|
+
await commandFunction(options);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Module Export Pattern
|
|
72
|
+
- Use named exports for multiple functions
|
|
73
|
+
- Use default exports for single-purpose modules
|
|
74
|
+
- Pattern:
|
|
75
|
+
```javascript
|
|
76
|
+
/**
|
|
77
|
+
* Module description
|
|
78
|
+
* @fileoverview Brief description
|
|
79
|
+
* @author AI Fabrix Team
|
|
80
|
+
* @version 2.0.0
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
const dependency = require('./dependency');
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Function description
|
|
87
|
+
* @async
|
|
88
|
+
* @function functionName
|
|
89
|
+
* @param {string} param - Parameter description
|
|
90
|
+
* @returns {Promise<Type>} Return description
|
|
91
|
+
* @throws {Error} Error description
|
|
92
|
+
*/
|
|
93
|
+
async function functionName(param) {
|
|
94
|
+
// Implementation
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = { functionName };
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Template Generation Pattern
|
|
101
|
+
Templates use Handlebars and are stored in `templates/`:
|
|
102
|
+
```javascript
|
|
103
|
+
const Handlebars = require('handlebars');
|
|
104
|
+
const fs = require('fs');
|
|
105
|
+
|
|
106
|
+
const templateContent = fs.readFileSync(templatePath, 'utf8');
|
|
107
|
+
const template = Handlebars.compile(templateContent);
|
|
108
|
+
const rendered = template(context);
|
|
109
|
+
fs.writeFileSync(outputPath, rendered, 'utf8');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### YAML Processing Pattern
|
|
113
|
+
All YAML files use js-yaml with proper error handling:
|
|
114
|
+
```javascript
|
|
115
|
+
const yaml = require('js-yaml');
|
|
116
|
+
const fs = require('fs');
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const content = fs.readFileSync(yamlPath, 'utf8');
|
|
120
|
+
const parsed = yaml.load(content);
|
|
121
|
+
// Process parsed YAML
|
|
122
|
+
} catch (error) {
|
|
123
|
+
throw new Error(`Invalid YAML syntax: ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Schema Validation Pattern
|
|
128
|
+
Use AJV for JSON schema validation:
|
|
129
|
+
```javascript
|
|
130
|
+
const Ajv = require('ajv');
|
|
131
|
+
const schema = require('./schema/application-schema.json');
|
|
132
|
+
|
|
133
|
+
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
134
|
+
const validate = ajv.compile(schema);
|
|
135
|
+
const valid = validate(data);
|
|
136
|
+
|
|
137
|
+
if (!valid) {
|
|
138
|
+
const errors = formatValidationErrors(validate.errors);
|
|
139
|
+
throw new Error(`Validation failed: ${errors.join(', ')}`);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Code Style
|
|
144
|
+
|
|
145
|
+
### JavaScript Conventions
|
|
146
|
+
- Use strict mode where applicable
|
|
147
|
+
- Use async/await for asynchronous operations
|
|
148
|
+
- Use try-catch for error handling
|
|
149
|
+
- Prefer const over let, avoid var
|
|
150
|
+
- Use template literals for string interpolation
|
|
151
|
+
- Use object destructuring where appropriate
|
|
152
|
+
|
|
153
|
+
### Naming Conventions
|
|
154
|
+
- **Files**: kebab-case (`app-deploy.js`, `env-reader.js`)
|
|
155
|
+
- **Functions**: camelCase (`createApp`, `validateVariables`)
|
|
156
|
+
- **Constants**: UPPER_SNAKE_CASE (`MAX_FILE_SIZE`, `DEFAULT_PORT`)
|
|
157
|
+
- **Classes**: PascalCase (not common in this project, but if used)
|
|
158
|
+
- **Private functions**: prefix with underscore if needed (rare in CommonJS)
|
|
159
|
+
|
|
160
|
+
### Error Handling
|
|
161
|
+
- Always wrap async operations in try-catch
|
|
162
|
+
- Provide meaningful error messages
|
|
163
|
+
- Include context in error messages (file path, app name, etc.)
|
|
164
|
+
- Use chalk for colored error output
|
|
165
|
+
- Pattern:
|
|
166
|
+
```javascript
|
|
167
|
+
try {
|
|
168
|
+
await operation();
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
171
|
+
throw new Error(`Operation failed: ${error.message}`);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Input Validation
|
|
176
|
+
- Validate all function parameters
|
|
177
|
+
- Check for null/undefined values
|
|
178
|
+
- Validate file paths and existence
|
|
179
|
+
- Validate app names (alphanumeric, hyphens, underscores)
|
|
180
|
+
- Pattern:
|
|
181
|
+
```javascript
|
|
182
|
+
function validateAppName(appName) {
|
|
183
|
+
if (!appName || typeof appName !== 'string') {
|
|
184
|
+
throw new Error('App name is required and must be a string');
|
|
185
|
+
}
|
|
186
|
+
if (!/^[a-z0-9-_]+$/.test(appName)) {
|
|
187
|
+
throw new Error('App name must contain only lowercase letters, numbers, hyphens, and underscores');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Async/Await
|
|
193
|
+
- Always use async/await, never raw promises
|
|
194
|
+
- Always use try-catch with async operations
|
|
195
|
+
- Return appropriate default values on error (empty arrays, null, etc.)
|
|
196
|
+
- Pattern:
|
|
197
|
+
```javascript
|
|
198
|
+
async function getItems() {
|
|
199
|
+
try {
|
|
200
|
+
const items = await fetchItems();
|
|
201
|
+
return items || [];
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error('Failed to get items:', error);
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### File Operations
|
|
210
|
+
- Use `fs.promises` for async file operations
|
|
211
|
+
- Use `fs.existsSync` for synchronous checks when needed
|
|
212
|
+
- Always handle file not found errors
|
|
213
|
+
- Use `path.join()` for cross-platform path construction
|
|
214
|
+
- Pattern:
|
|
215
|
+
```javascript
|
|
216
|
+
const fs = require('fs').promises;
|
|
217
|
+
const path = require('path');
|
|
218
|
+
|
|
219
|
+
const filePath = path.join(process.cwd(), 'builder', appName, 'variables.yaml');
|
|
220
|
+
try {
|
|
221
|
+
const content = await fs.readFileSync(filePath, 'utf8');
|
|
222
|
+
// Process content
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (error.code === 'ENOENT') {
|
|
225
|
+
throw new Error(`File not found: ${filePath}`);
|
|
226
|
+
}
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Testing Conventions
|
|
232
|
+
|
|
233
|
+
### Test File Structure
|
|
234
|
+
- Test files mirror source structure: `tests/lib/app.test.js`
|
|
235
|
+
- Use Jest for testing framework
|
|
236
|
+
- Mock all external dependencies (fs, axios, child_process)
|
|
237
|
+
- Test both success and error paths
|
|
238
|
+
- Test edge cases (missing files, invalid YAML, etc.)
|
|
239
|
+
|
|
240
|
+
### Test Organization
|
|
241
|
+
```yaml
|
|
242
|
+
tests/
|
|
243
|
+
├── lib/
|
|
244
|
+
│ ├── app.test.js
|
|
245
|
+
│ ├── validator.test.js
|
|
246
|
+
│ ├── cli.test.js
|
|
247
|
+
│ └── generator.test.js
|
|
248
|
+
├── bin/
|
|
249
|
+
│ └── aifabrix.test.js
|
|
250
|
+
└── integration/
|
|
251
|
+
├── build.test.js
|
|
252
|
+
└── deploy.test.js
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Mock Patterns
|
|
256
|
+
- Mock fs operations: `jest.mock('fs')` or `jest.mock('fs').promises`
|
|
257
|
+
- Mock axios: `jest.mock('axios')` or use `makeApiCall` mock
|
|
258
|
+
- Mock child_process: `jest.mock('child_process')`
|
|
259
|
+
- Mock templates: provide test templates in `tests/fixtures/`
|
|
260
|
+
- Pattern:
|
|
261
|
+
```javascript
|
|
262
|
+
jest.mock('fs');
|
|
263
|
+
jest.mock('fs').promises;
|
|
264
|
+
|
|
265
|
+
const fs = require('fs');
|
|
266
|
+
const fsp = require('fs').promises;
|
|
267
|
+
|
|
268
|
+
describe('ModuleName', () => {
|
|
269
|
+
beforeEach(() => {
|
|
270
|
+
jest.clearAllMocks();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should handle success case', async () => {
|
|
274
|
+
fsp.readFile = jest.fn().resolves('content');
|
|
275
|
+
// Test implementation
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should handle error case', async () => {
|
|
279
|
+
fsp.readFile = jest.fn().rejects(new Error('File not found'));
|
|
280
|
+
// Test error handling
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Test Coverage
|
|
286
|
+
- Aim for 80%+ branch coverage
|
|
287
|
+
- Test edge cases (null tokens, empty arrays, file errors)
|
|
288
|
+
- Test validation failures
|
|
289
|
+
- Test template rendering
|
|
290
|
+
- Test Docker operations (mocked)
|
|
291
|
+
|
|
292
|
+
## Security & Compliance (ISO 27001)
|
|
293
|
+
|
|
294
|
+
### Information Security Management
|
|
295
|
+
- All code must follow ISO 27001 information security standards
|
|
296
|
+
- Implement proper access controls and authentication mechanisms
|
|
297
|
+
- Ensure data confidentiality, integrity, and availability
|
|
298
|
+
- Document all security-related decisions and implementations
|
|
299
|
+
- Regular security reviews and vulnerability assessments required
|
|
300
|
+
|
|
301
|
+
### Data Protection
|
|
302
|
+
- **No hardcoded secrets, passwords, or sensitive data in code**
|
|
303
|
+
- Use environment variables and secure configuration management
|
|
304
|
+
- Implement proper input validation and sanitization
|
|
305
|
+
- Follow principle of least privilege for all operations
|
|
306
|
+
- Encrypt sensitive data at rest and in transit
|
|
307
|
+
- Never log sensitive information (passwords, tokens, secrets)
|
|
308
|
+
|
|
309
|
+
### Secret Management
|
|
310
|
+
- Use `kv://` references in env.template for secrets
|
|
311
|
+
- Resolve secrets via `lib/secrets.js` before deployment
|
|
312
|
+
- Never expose secrets in generated files
|
|
313
|
+
- Mask secrets in logs and error messages
|
|
314
|
+
- Pattern:
|
|
315
|
+
```javascript
|
|
316
|
+
// In env.template
|
|
317
|
+
DATABASE_PASSWORD=kv://secrets/database/password
|
|
318
|
+
|
|
319
|
+
// In secrets.js
|
|
320
|
+
function resolveSecret(key) {
|
|
321
|
+
// Resolve from secure key store
|
|
322
|
+
// Never log the actual value
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Audit & Compliance
|
|
327
|
+
- All actions must be logged and auditable
|
|
328
|
+
- Use `lib/audit-logger.js` for audit logging
|
|
329
|
+
- Maintain comprehensive documentation for compliance
|
|
330
|
+
- Regular code reviews and security assessments
|
|
331
|
+
- Version control all changes with proper commit messages
|
|
332
|
+
- Document all dependencies and their security implications
|
|
333
|
+
|
|
334
|
+
### Input Validation
|
|
335
|
+
- Sanitize all user inputs (app names, file paths, URLs)
|
|
336
|
+
- Validate YAML syntax before processing
|
|
337
|
+
- Validate JSON schemas before deployment
|
|
338
|
+
- Prevent path traversal attacks
|
|
339
|
+
- Validate URLs and endpoints
|
|
340
|
+
|
|
341
|
+
### Infrastructure Security
|
|
342
|
+
- Use secure container configurations
|
|
343
|
+
- Implement proper network security
|
|
344
|
+
- Follow Docker security best practices
|
|
345
|
+
- Use secure base images and dependencies
|
|
346
|
+
- Validate Dockerfile security before generation
|
|
347
|
+
|
|
348
|
+
## Code Quality Standards
|
|
349
|
+
|
|
350
|
+
### File Size Limits
|
|
351
|
+
- **Maximum 500 lines per file** - Split large files into smaller, focused modules
|
|
352
|
+
- **Maximum 50 lines per function/method** - Break down complex functions
|
|
353
|
+
- Use composition over inheritance to reduce complexity
|
|
354
|
+
- Extract reusable components and utilities
|
|
355
|
+
|
|
356
|
+
### Code Organization
|
|
357
|
+
- Follow single responsibility principle
|
|
358
|
+
- Use meaningful, descriptive names for variables and functions
|
|
359
|
+
- Implement proper error handling and logging
|
|
360
|
+
- Write self-documenting code with clear comments
|
|
361
|
+
- Use JSDoc for all public functions
|
|
362
|
+
|
|
363
|
+
### Documentation Requirements
|
|
364
|
+
- **JSDoc comments for all public functions**
|
|
365
|
+
- Include parameter types and return types
|
|
366
|
+
- Document error conditions
|
|
367
|
+
- Add examples in comments for complex methods
|
|
368
|
+
- Document security considerations
|
|
369
|
+
|
|
370
|
+
### Code Comments
|
|
371
|
+
- Use JSDoc format for function documentation
|
|
372
|
+
- Include `@fileoverview` at top of each file
|
|
373
|
+
- Include `@author` and `@version` tags
|
|
374
|
+
- Use inline comments for complex logic
|
|
375
|
+
- Pattern:
|
|
376
|
+
```javascript
|
|
377
|
+
/**
|
|
378
|
+
* Function description
|
|
379
|
+
* @async
|
|
380
|
+
* @function functionName
|
|
381
|
+
* @param {string} appName - Application name
|
|
382
|
+
* @param {Object} options - Configuration options
|
|
383
|
+
* @param {number} [options.port] - Application port (optional)
|
|
384
|
+
* @returns {Promise<void>} Resolves when operation completes
|
|
385
|
+
* @throws {Error} If app name is invalid or operation fails
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* await functionName('myapp', { port: 3000 });
|
|
389
|
+
*/
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Development Workflow
|
|
393
|
+
|
|
394
|
+
### Pre-Development
|
|
395
|
+
1. Analyze requirements and create detailed specifications
|
|
396
|
+
2. Design architecture following security best practices
|
|
397
|
+
3. Plan test cases before writing implementation
|
|
398
|
+
4. Review existing code for potential security vulnerabilities
|
|
399
|
+
|
|
400
|
+
### During Development
|
|
401
|
+
1. Write tests first (TDD approach)
|
|
402
|
+
2. Implement functionality with security in mind
|
|
403
|
+
3. Follow coding standards and file size limits
|
|
404
|
+
4. Document all security-related decisions
|
|
405
|
+
5. Use proper error handling and logging
|
|
406
|
+
6. Validate all inputs
|
|
407
|
+
7. Use JSDoc for documentation
|
|
408
|
+
|
|
409
|
+
### Post-Development
|
|
410
|
+
1. **Build project** - Run `npm run build` (lint + test)
|
|
411
|
+
2. **Validate linting** - Run `npm run lint` and fix all issues
|
|
412
|
+
3. **Run tests** - Execute `npm test` and ensure 100% pass rate
|
|
413
|
+
4. **Check coverage** - Ensure 80%+ coverage for new code
|
|
414
|
+
5. **Security review** - Check for vulnerabilities and compliance
|
|
415
|
+
6. **Code review** - Peer review for quality and security
|
|
416
|
+
|
|
417
|
+
## CLI Command Development
|
|
418
|
+
|
|
419
|
+
### Adding New Commands
|
|
420
|
+
1. Add command definition in `lib/cli.js`
|
|
421
|
+
2. Implement command logic in `lib/commands/` or appropriate module
|
|
422
|
+
3. Add input validation
|
|
423
|
+
4. Add error handling with user-friendly messages
|
|
424
|
+
5. Use chalk for colored output
|
|
425
|
+
6. Write tests for the command
|
|
426
|
+
|
|
427
|
+
### Command Pattern
|
|
428
|
+
```javascript
|
|
429
|
+
program.command('new-command')
|
|
430
|
+
.description('Clear description of what the command does')
|
|
431
|
+
.option('-f, --flag <value>', 'Option description', defaultValue)
|
|
432
|
+
.action(async (options) => {
|
|
433
|
+
try {
|
|
434
|
+
// Validate inputs
|
|
435
|
+
if (!options.required) {
|
|
436
|
+
throw new Error('Required option missing');
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Execute command
|
|
440
|
+
const result = await executeCommand(options);
|
|
441
|
+
|
|
442
|
+
// Success message
|
|
443
|
+
console.log(chalk.green(`✓ Success: ${result}`));
|
|
444
|
+
} catch (error) {
|
|
445
|
+
console.error(chalk.red(`✗ Error: ${error.message}`));
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### User Experience
|
|
452
|
+
- Provide clear, actionable error messages
|
|
453
|
+
- Use emoji/icons for visual feedback (✓, ✗, ⚠️, 🔐, etc.)
|
|
454
|
+
- Show progress for long-running operations (use ora spinner)
|
|
455
|
+
- Provide helpful hints in error messages
|
|
456
|
+
- Use consistent formatting across commands
|
|
457
|
+
|
|
458
|
+
## Template Development
|
|
459
|
+
|
|
460
|
+
### Template Location
|
|
461
|
+
- Templates in `templates/` directory
|
|
462
|
+
- Organize by type: `templates/typescript/`, `templates/python/`, `templates/github/`
|
|
463
|
+
- Use `.hbs` extension for Handlebars templates
|
|
464
|
+
|
|
465
|
+
### Template Patterns
|
|
466
|
+
- Use Handlebars helpers for conditionals: `{{#if condition}}`
|
|
467
|
+
- Use Handlebars loops: `{{#each items}}`
|
|
468
|
+
- Use context variables: `{{variableName}}`
|
|
469
|
+
- Provide default values: `{{variableName default="value"}}`
|
|
470
|
+
- Pattern:
|
|
471
|
+
```handlebars
|
|
472
|
+
# {{appName}} Dockerfile
|
|
473
|
+
FROM {{baseImage}}
|
|
474
|
+
{{#if hasDatabase}}
|
|
475
|
+
ENV DATABASE_URL={{databaseUrl}}
|
|
476
|
+
{{/if}}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### Template Context
|
|
480
|
+
- Build context object with all necessary variables
|
|
481
|
+
- Validate context before rendering
|
|
482
|
+
- Provide sensible defaults for optional values
|
|
483
|
+
- Document required context variables
|
|
484
|
+
|
|
485
|
+
## Validation Patterns
|
|
486
|
+
|
|
487
|
+
### Schema Validation
|
|
488
|
+
- Define schemas in `lib/schema/` directory
|
|
489
|
+
- Use JSON Schema format
|
|
490
|
+
- Validate before deployment
|
|
491
|
+
- Provide developer-friendly error messages
|
|
492
|
+
- Pattern:
|
|
493
|
+
```javascript
|
|
494
|
+
const schema = require('./schema/application-schema.json');
|
|
495
|
+
const ajv = new Ajv({ allErrors: true });
|
|
496
|
+
const validate = ajv.compile(schema);
|
|
497
|
+
|
|
498
|
+
if (!validate(data)) {
|
|
499
|
+
const errors = validate.errors.map(err =>
|
|
500
|
+
`${err.instancePath} ${err.message}`
|
|
501
|
+
).join(', ');
|
|
502
|
+
throw new Error(`Validation failed: ${errors}`);
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### YAML Validation
|
|
507
|
+
- Validate YAML syntax before parsing
|
|
508
|
+
- Validate against schemas after parsing
|
|
509
|
+
- Provide line numbers in error messages when possible
|
|
510
|
+
- Pattern:
|
|
511
|
+
```javascript
|
|
512
|
+
try {
|
|
513
|
+
const parsed = yaml.load(content);
|
|
514
|
+
await validateAgainstSchema(parsed);
|
|
515
|
+
} catch (error) {
|
|
516
|
+
if (error.message.includes('YAML')) {
|
|
517
|
+
throw new Error(`Invalid YAML syntax: ${error.message}`);
|
|
518
|
+
}
|
|
519
|
+
throw error;
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
## Docker & Infrastructure
|
|
524
|
+
|
|
525
|
+
### Dockerfile Generation
|
|
526
|
+
- Auto-detect runtime (TypeScript/Python)
|
|
527
|
+
- Use appropriate base images
|
|
528
|
+
- Follow security best practices
|
|
529
|
+
- Minimize image size
|
|
530
|
+
- Pattern in `lib/app-dockerfile.js`:
|
|
531
|
+
```javascript
|
|
532
|
+
function detectRuntime(appPath) {
|
|
533
|
+
// Check for package.json (Node.js/TypeScript)
|
|
534
|
+
// Check for requirements.txt (Python)
|
|
535
|
+
// Return appropriate template
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Docker Compose
|
|
540
|
+
- Infrastructure templates in `templates/infra/`
|
|
541
|
+
- Use environment variables for configuration
|
|
542
|
+
- Follow Docker security best practices
|
|
543
|
+
- Validate compose files before deployment
|
|
544
|
+
|
|
545
|
+
## Common Patterns
|
|
546
|
+
|
|
547
|
+
### App Name Validation
|
|
548
|
+
```javascript
|
|
549
|
+
function validateAppName(appName) {
|
|
550
|
+
if (!appName || typeof appName !== 'string') {
|
|
551
|
+
throw new Error('App name is required and must be a string');
|
|
552
|
+
}
|
|
553
|
+
if (!/^[a-z0-9-_]+$/.test(appName)) {
|
|
554
|
+
throw new Error('App name must contain only lowercase letters, numbers, hyphens, and underscores');
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### File Path Construction
|
|
560
|
+
```javascript
|
|
561
|
+
const path = require('path');
|
|
562
|
+
|
|
563
|
+
const appPath = path.join(process.cwd(), 'builder', appName);
|
|
564
|
+
const configPath = path.join(appPath, 'variables.yaml');
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Configuration Loading
|
|
568
|
+
```javascript
|
|
569
|
+
async function loadConfig(appName) {
|
|
570
|
+
const configPath = path.join(process.cwd(), 'builder', appName, 'variables.yaml');
|
|
571
|
+
const content = await fs.readFile(configPath, 'utf8');
|
|
572
|
+
return yaml.load(content);
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Template Rendering
|
|
577
|
+
```javascript
|
|
578
|
+
const Handlebars = require('handlebars');
|
|
579
|
+
const fs = require('fs');
|
|
580
|
+
|
|
581
|
+
const templatePath = path.join(__dirname, '../templates/typescript/Dockerfile.hbs');
|
|
582
|
+
const templateContent = fs.readFileSync(templatePath, 'utf8');
|
|
583
|
+
const template = Handlebars.compile(templateContent);
|
|
584
|
+
const rendered = template(context);
|
|
585
|
+
await fs.writeFile(outputPath, rendered, 'utf8');
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
## Quality Gates
|
|
589
|
+
|
|
590
|
+
### Mandatory Checks Before Commit
|
|
591
|
+
1. ✅ File size limits respected (≤500 lines, ≤50 lines per function)
|
|
592
|
+
2. ✅ All functions have corresponding tests
|
|
593
|
+
3. ✅ Tests are in `tests/` folder (not in code directories)
|
|
594
|
+
4. ✅ Build process completes successfully (`npm run build`)
|
|
595
|
+
5. ✅ Linting passes with no errors (`npm run lint`)
|
|
596
|
+
6. ✅ All tests pass (100% success rate)
|
|
597
|
+
7. ✅ Test coverage ≥80% for new code
|
|
598
|
+
8. ✅ Security review completed
|
|
599
|
+
9. ✅ Documentation updated (JSDoc comments)
|
|
600
|
+
10. ✅ No hardcoded secrets or sensitive data
|
|
601
|
+
|
|
602
|
+
### Continuous Integration
|
|
603
|
+
- Automated testing on all pull requests
|
|
604
|
+
- Security scanning and vulnerability assessment
|
|
605
|
+
- Code quality metrics and coverage reporting
|
|
606
|
+
- Automated deployment validation
|
|
607
|
+
- Linting enforcement
|
|
608
|
+
|
|
609
|
+
## Error Handling & Logging
|
|
610
|
+
|
|
611
|
+
### Error Handling
|
|
612
|
+
- Implement comprehensive error handling
|
|
613
|
+
- Use structured error messages with context
|
|
614
|
+
- Log all errors with appropriate context
|
|
615
|
+
- Never expose sensitive information in error messages
|
|
616
|
+
- Use chalk for colored error output
|
|
617
|
+
- Provide actionable error messages
|
|
618
|
+
|
|
619
|
+
### Logging Standards
|
|
620
|
+
- Use console.log for normal output (with chalk coloring)
|
|
621
|
+
- Use console.error for errors
|
|
622
|
+
- Use console.warn for warnings
|
|
623
|
+
- Use ora spinner for progress indication
|
|
624
|
+
- Never log secrets, passwords, or tokens
|
|
625
|
+
- Use structured logging for audit trail
|
|
626
|
+
|
|
627
|
+
## Dependencies & Security
|
|
628
|
+
|
|
629
|
+
### Dependency Management
|
|
630
|
+
- Regularly update dependencies for security patches
|
|
631
|
+
- Use only trusted and well-maintained packages
|
|
632
|
+
- Implement dependency scanning and vulnerability assessment
|
|
633
|
+
- Document all dependencies and their purposes
|
|
634
|
+
- Review security advisories regularly
|
|
635
|
+
|
|
636
|
+
### Security Scanning
|
|
637
|
+
- Regular security scans of dependencies
|
|
638
|
+
- Vulnerability assessment and remediation
|
|
639
|
+
- Security testing in CI/CD pipeline
|
|
640
|
+
- Regular security audits and reviews
|
|
641
|
+
- Use `npm audit` regularly
|
|
642
|
+
|
|
643
|
+
## When Adding New Features
|
|
644
|
+
|
|
645
|
+
1. **Plan** - Analyze requirements and design architecture
|
|
646
|
+
2. **Test First** - Write tests before implementation (TDD)
|
|
647
|
+
3. **Implement** - Write code following all patterns and standards
|
|
648
|
+
4. **Validate** - Run build, lint, and tests
|
|
649
|
+
5. **Document** - Add JSDoc comments and update README if needed
|
|
650
|
+
6. **Security Review** - Check for vulnerabilities and compliance
|
|
651
|
+
7. **Code Review** - Peer review for quality and security
|
|
652
|
+
|
|
653
|
+
## Critical Rules
|
|
654
|
+
|
|
655
|
+
### Must Do (✅)
|
|
656
|
+
- ✅ Validate all inputs (app names, file paths, URLs)
|
|
657
|
+
- ✅ Use try-catch for all async operations
|
|
658
|
+
- ✅ Provide meaningful error messages with context
|
|
659
|
+
- ✅ Use JSDoc for all public functions
|
|
660
|
+
- ✅ Write tests for all functions
|
|
661
|
+
- ✅ Keep files ≤500 lines and functions ≤50 lines
|
|
662
|
+
- ✅ Use chalk for colored output in CLI
|
|
663
|
+
- ✅ Use path.join() for cross-platform paths
|
|
664
|
+
- ✅ Validate YAML syntax before parsing
|
|
665
|
+
- ✅ Never log secrets or sensitive data
|
|
666
|
+
|
|
667
|
+
### Must Not Do (❌)
|
|
668
|
+
- ❌ Never hardcode secrets, passwords, or tokens
|
|
669
|
+
- ❌ Never expose sensitive data in error messages
|
|
670
|
+
- ❌ Never use synchronous file operations in async functions (unless necessary)
|
|
671
|
+
- ❌ Never ignore errors or use empty catch blocks
|
|
672
|
+
- ❌ Never commit files with secrets or sensitive data
|
|
673
|
+
- ❌ Never skip input validation
|
|
674
|
+
- ❌ Never skip tests for new functionality
|
|
675
|
+
- ❌ Never use `eval()` or `Function()` constructor
|
|
676
|
+
- ❌ Never use raw paths (always use path.join)
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
**Remember**: Security is not optional. Every line of code must be written with security and compliance in mind. When in doubt, choose the more secure option and document the decision.
|
package/lib/app-config.js
CHANGED
|
@@ -54,6 +54,11 @@ async function generateVariablesYamlFile(appPath, appName, config) {
|
|
|
54
54
|
* @param {Object} existingEnv - Existing environment variables
|
|
55
55
|
*/
|
|
56
56
|
async function generateEnvTemplateFile(appPath, config, existingEnv) {
|
|
57
|
+
// Skip env.template for external type
|
|
58
|
+
if (config.type === 'external') {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
57
62
|
const envTemplatePath = path.join(appPath, 'env.template');
|
|
58
63
|
if (!(await fileExists(envTemplatePath))) {
|
|
59
64
|
let envTemplate;
|
|
@@ -101,6 +106,11 @@ async function generateRbacYamlFile(appPath, appName, config) {
|
|
|
101
106
|
* @param {Object} config - Application configuration
|
|
102
107
|
*/
|
|
103
108
|
async function generateDeployJsonFile(appPath, appName, config) {
|
|
109
|
+
// Skip aifabrix-deploy.json for external type (uses pipeline API instead)
|
|
110
|
+
if (config.type === 'external') {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
104
114
|
const deployJson = {
|
|
105
115
|
apiVersion: 'v1',
|
|
106
116
|
kind: 'ApplicationDeployment',
|