@tamyla/clodo-framework 3.1.21 → 3.1.22
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/CHANGELOG.md +9 -0
- package/README.md +53 -0
- package/dist/bin/clodo-service.js +47 -15
- package/dist/bin/commands/deploy.js +115 -83
- package/dist/bin/commands/helpers/deployment-ui.js +138 -0
- package/dist/bin/commands/helpers/deployment-verification.js +251 -0
- package/dist/bin/commands/helpers/error-recovery.js +80 -0
- package/dist/bin/commands/helpers/resource-detection.js +113 -0
- package/dist/bin/commands/validate.js +1 -1
- package/dist/bin/security/security-cli.js +1 -1
- package/dist/bin/shared/cache/configuration-cache.js +82 -0
- package/dist/bin/shared/cloudflare/domain-manager.js +1 -1
- package/dist/bin/shared/cloudflare/index.js +1 -1
- package/dist/bin/shared/cloudflare/ops.js +6 -4
- package/dist/bin/shared/config/ConfigurationManager.js +23 -1
- package/dist/bin/shared/config/command-config-manager.js +19 -3
- package/dist/bin/shared/config/index.js +1 -1
- package/dist/bin/shared/deployment/credential-collector.js +30 -7
- package/dist/bin/shared/deployment/index.js +2 -2
- package/dist/bin/shared/deployment/rollback-manager.js +4 -520
- package/dist/bin/shared/deployment/utilities/d1-error-recovery.js +177 -0
- package/dist/bin/shared/deployment/validator.js +40 -10
- package/dist/bin/shared/deployment/workflows/deployment-summary.js +214 -0
- package/dist/bin/shared/deployment/workflows/interactive-confirmation.js +188 -0
- package/dist/bin/shared/deployment/workflows/interactive-database-workflow.js +234 -0
- package/dist/bin/shared/deployment/workflows/interactive-domain-info-gatherer.js +240 -0
- package/dist/bin/shared/deployment/workflows/interactive-secret-workflow.js +228 -0
- package/dist/bin/shared/deployment/workflows/interactive-testing-workflow.js +235 -0
- package/dist/bin/shared/deployment/workflows/interactive-validation.js +218 -0
- package/dist/bin/shared/error-handling/error-classifier.js +46 -0
- package/dist/bin/shared/monitoring/health-checker.js +129 -1
- package/dist/bin/shared/monitoring/memory-manager.js +17 -6
- package/dist/bin/shared/routing/domain-router.js +1 -1
- package/dist/bin/shared/utils/deployment-validator.js +97 -0
- package/dist/bin/shared/utils/formatters.js +10 -0
- package/dist/bin/shared/utils/index.js +13 -1
- package/dist/bin/shared/utils/interactive-prompts.js +34 -18
- package/dist/bin/shared/utils/progress-manager.js +2 -2
- package/dist/bin/shared/utils/progress-spinner.js +53 -0
- package/dist/bin/shared/utils/sensitive-redactor.js +91 -0
- package/dist/bin/shared/validation/ValidationRegistry.js +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/patterns/insecure-patterns.js +1 -1
- package/dist/utils/constants.js +102 -0
- package/dist/utils/deployment/wrangler-config-manager.js +215 -48
- package/dist/utils/framework-config.js +2 -2
- package/dist/utils/interactive-prompts.js +10 -59
- package/package.json +16 -8
- package/dist/bin/clodo-service-old.js +0 -868
- package/dist/bin/clodo-service-test.js +0 -10
- package/dist/bin/commands/assess.js +0 -91
- package/dist/bin/commands/create.js +0 -77
- package/dist/bin/commands/diagnose.js +0 -83
- package/dist/bin/commands/helpers.js +0 -138
- package/dist/bin/commands/update.js +0 -75
- package/dist/bin/database/deployment-db-manager.js +0 -423
- package/dist/bin/database/enterprise-db-manager.js +0 -457
- package/dist/bin/database/wrangler-d1-manager.js +0 -685
- package/dist/bin/deployment/enterprise-deploy.js +0 -877
- package/dist/bin/deployment/master-deploy.js +0 -1376
- package/dist/bin/deployment/modular-enterprise-deploy.js +0 -466
- package/dist/bin/deployment/modules/DeploymentConfiguration.js +0 -395
- package/dist/bin/deployment/modules/DeploymentOrchestrator.js +0 -492
- package/dist/bin/deployment/modules/EnvironmentManager.js +0 -517
- package/dist/bin/deployment/modules/MonitoringIntegration.js +0 -560
- package/dist/bin/deployment/modules/ValidationManager.js +0 -342
- package/dist/bin/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
- package/dist/bin/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
- package/dist/bin/deployment/orchestration/PortfolioOrchestrator.js +0 -273
- package/dist/bin/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
- package/dist/bin/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
- package/dist/bin/deployment/test-interactive-utils.js +0 -66
- package/dist/bin/portfolio/portfolio-manager.js +0 -487
- package/dist/bin/service-management/create-service.js +0 -122
- package/dist/bin/service-management/init-service.js +0 -79
- package/dist/config/customers.js +0 -623
- package/dist/config/domains.js +0 -186
- package/dist/config/index.js +0 -6
- package/dist/database/database-orchestrator.js +0 -795
- package/dist/database/index.js +0 -4
- package/dist/deployment/index.js +0 -11
- package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +0 -426
- package/dist/deployment/orchestration/EnterpriseOrchestrator.js +0 -401
- package/dist/deployment/orchestration/PortfolioOrchestrator.js +0 -273
- package/dist/deployment/orchestration/SingleServiceOrchestrator.js +0 -231
- package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +0 -662
- package/dist/deployment/orchestration/index.js +0 -17
- package/dist/deployment/rollback-manager.js +0 -36
- package/dist/deployment/wrangler-deployer.js +0 -640
- package/dist/handlers/GenericRouteHandler.js +0 -532
- package/dist/migration/MigrationAdapters.js +0 -562
- package/dist/modules/ModuleManager.js +0 -668
- package/dist/modules/security.js +0 -96
- package/dist/orchestration/cross-domain-coordinator.js +0 -1083
- package/dist/orchestration/index.js +0 -5
- package/dist/orchestration/modules/DeploymentCoordinator.js +0 -368
- package/dist/orchestration/modules/DomainResolver.js +0 -198
- package/dist/orchestration/modules/StateManager.js +0 -332
- package/dist/orchestration/multi-domain-orchestrator.js +0 -724
- package/dist/routing/EnhancedRouter.js +0 -158
- package/dist/schema/SchemaManager.js +0 -778
- package/dist/service-management/ConfirmationEngine.js +0 -412
- package/dist/service-management/ErrorTracker.js +0 -299
- package/dist/service-management/GenerationEngine.js +0 -447
- package/dist/service-management/InputCollector.js +0 -619
- package/dist/service-management/ServiceCreator.js +0 -265
- package/dist/service-management/ServiceInitializer.js +0 -453
- package/dist/service-management/ServiceOrchestrator.js +0 -633
- package/dist/service-management/generators/BaseGenerator.js +0 -233
- package/dist/service-management/generators/GeneratorRegistry.js +0 -254
- package/dist/service-management/generators/cicd/CiWorkflowGenerator.js +0 -87
- package/dist/service-management/generators/cicd/DeployWorkflowGenerator.js +0 -106
- package/dist/service-management/generators/code/ServiceHandlersGenerator.js +0 -235
- package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +0 -116
- package/dist/service-management/generators/code/ServiceUtilsGenerator.js +0 -246
- package/dist/service-management/generators/code/WorkerIndexGenerator.js +0 -143
- package/dist/service-management/generators/config/DevelopmentEnvGenerator.js +0 -101
- package/dist/service-management/generators/config/DomainsConfigGenerator.js +0 -175
- package/dist/service-management/generators/config/EnvExampleGenerator.js +0 -178
- package/dist/service-management/generators/config/ProductionEnvGenerator.js +0 -97
- package/dist/service-management/generators/config/StagingEnvGenerator.js +0 -97
- package/dist/service-management/generators/config/WranglerTomlGenerator.js +0 -238
- package/dist/service-management/generators/core/PackageJsonGenerator.js +0 -243
- package/dist/service-management/generators/core/SiteConfigGenerator.js +0 -115
- package/dist/service-management/generators/documentation/ApiDocsGenerator.js +0 -331
- package/dist/service-management/generators/documentation/ConfigurationDocsGenerator.js +0 -294
- package/dist/service-management/generators/documentation/DeploymentDocsGenerator.js +0 -244
- package/dist/service-management/generators/documentation/ReadmeGenerator.js +0 -196
- package/dist/service-management/generators/schemas/ServiceSchemaGenerator.js +0 -190
- package/dist/service-management/generators/scripts/DeployScriptGenerator.js +0 -123
- package/dist/service-management/generators/scripts/HealthCheckScriptGenerator.js +0 -101
- package/dist/service-management/generators/scripts/SetupScriptGenerator.js +0 -88
- package/dist/service-management/generators/service-types/StaticSiteGenerator.js +0 -342
- package/dist/service-management/generators/testing/EslintConfigGenerator.js +0 -85
- package/dist/service-management/generators/testing/IntegrationTestsGenerator.js +0 -237
- package/dist/service-management/generators/testing/JestConfigGenerator.js +0 -72
- package/dist/service-management/generators/testing/UnitTestsGenerator.js +0 -277
- package/dist/service-management/generators/tooling/DockerComposeGenerator.js +0 -71
- package/dist/service-management/generators/tooling/GitignoreGenerator.js +0 -143
- package/dist/service-management/generators/utils/FileWriter.js +0 -179
- package/dist/service-management/generators/utils/PathResolver.js +0 -157
- package/dist/service-management/generators/utils/ServiceManifestGenerator.js +0 -111
- package/dist/service-management/generators/utils/TemplateEngine.js +0 -185
- package/dist/service-management/generators/utils/index.js +0 -18
- package/dist/service-management/handlers/ConfirmationHandler.js +0 -71
- package/dist/service-management/handlers/GenerationHandler.js +0 -80
- package/dist/service-management/handlers/InputHandler.js +0 -59
- package/dist/service-management/handlers/ValidationHandler.js +0 -203
- package/dist/service-management/index.js +0 -14
- package/dist/service-management/routing/DomainRouteMapper.js +0 -311
- package/dist/service-management/routing/RouteGenerator.js +0 -266
- package/dist/service-management/routing/WranglerRoutesBuilder.js +0 -273
- package/dist/service-management/routing/index.js +0 -14
- package/dist/service-management/services/DirectoryStructureService.js +0 -56
- package/dist/service-management/services/GenerationCoordinator.js +0 -208
- package/dist/service-management/services/GeneratorRegistry.js +0 -174
- package/dist/services/GenericDataService.js +0 -501
- package/dist/ui-structures/concepts/second-order-acquisition-strategy.md +0 -286
- package/dist/ui-structures/concepts/service-lifecycle-management.md +0 -150
- package/dist/ui-structures/concepts/service-manifest-guide.md +0 -309
- package/dist/ui-structures/concepts/three-tier-categorization-strategy.md +0 -231
- package/dist/ui-structures/creation/automated-generation-ui.json +0 -246
- package/dist/ui-structures/creation/core-inputs-ui.json +0 -217
- package/dist/ui-structures/creation/smart-confirmable-ui.json +0 -451
- package/dist/ui-structures/reference/absolutely-required-inputs.json +0 -315
- package/dist/ui-structures/reference/service-manifest-template.json +0 -342
- package/dist/version/VersionDetector.js +0 -723
- package/dist/worker/index.js +0 -4
- package/dist/worker/integration.js +0 -351
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment Validator Utility
|
|
3
|
+
* Pre-deployment validation and prerequisite checking
|
|
4
|
+
* Extracted from clodo-service-old.js for modular reuse
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Validate deployment prerequisites before proceeding
|
|
13
|
+
* @param {Object} coreInputs - Core deployment inputs
|
|
14
|
+
* @param {Object} options - Deployment options
|
|
15
|
+
* @returns {Promise<boolean>} True if all prerequisites are valid
|
|
16
|
+
*/
|
|
17
|
+
export async function validateDeploymentPrerequisites(coreInputs, options) {
|
|
18
|
+
const issues = [];
|
|
19
|
+
console.log(chalk.cyan('\n🔍 Pre-deployment Validation'));
|
|
20
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
21
|
+
|
|
22
|
+
// Check required fields
|
|
23
|
+
if (!coreInputs.customer) {
|
|
24
|
+
issues.push('Customer name is required');
|
|
25
|
+
}
|
|
26
|
+
if (!coreInputs.environment) {
|
|
27
|
+
issues.push('Environment is required');
|
|
28
|
+
}
|
|
29
|
+
if (!coreInputs.domainName) {
|
|
30
|
+
issues.push('Domain name is required');
|
|
31
|
+
}
|
|
32
|
+
if (!coreInputs.cloudflareToken) {
|
|
33
|
+
issues.push('Cloudflare API token is required');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Check Cloudflare token format (basic validation)
|
|
37
|
+
if (coreInputs.cloudflareToken && !coreInputs.cloudflareToken.startsWith('CLOUDFLARE_API_TOKEN=')) {
|
|
38
|
+
if (coreInputs.cloudflareToken.length < 40) {
|
|
39
|
+
issues.push('Cloudflare API token appears to be invalid (too short)');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Check if service path exists
|
|
44
|
+
if (options.servicePath && options.servicePath !== '.') {
|
|
45
|
+
if (!existsSync(options.servicePath)) {
|
|
46
|
+
issues.push(`Service path does not exist: ${options.servicePath}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check for wrangler.toml if not dry run
|
|
51
|
+
if (!options.dryRun) {
|
|
52
|
+
const wranglerPath = join(options.servicePath || '.', 'wrangler.toml');
|
|
53
|
+
if (!existsSync(wranglerPath)) {
|
|
54
|
+
issues.push('wrangler.toml not found in service directory');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Report issues
|
|
59
|
+
if (issues.length > 0) {
|
|
60
|
+
console.log(chalk.red('\n❌ Validation Failed:'));
|
|
61
|
+
issues.forEach(issue => {
|
|
62
|
+
console.log(chalk.red(` • ${issue}`));
|
|
63
|
+
});
|
|
64
|
+
console.log(chalk.gray('\n─'.repeat(40)));
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
console.log(chalk.green('✅ All prerequisites validated'));
|
|
68
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Validate basic deployment inputs
|
|
74
|
+
* @param {Object} inputs - Input object to validate
|
|
75
|
+
* @param {Array<string>} requiredFields - Required field names
|
|
76
|
+
* @returns {Object} Validation result { valid, errors }
|
|
77
|
+
*/
|
|
78
|
+
export function validateDeploymentInputs(inputs, requiredFields = ['customer', 'environment', 'domainName', 'cloudflareToken']) {
|
|
79
|
+
const result = {
|
|
80
|
+
valid: true,
|
|
81
|
+
errors: []
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Handle null/undefined inputs
|
|
85
|
+
if (!inputs) {
|
|
86
|
+
result.errors.push('Input object is required');
|
|
87
|
+
result.valid = false;
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
requiredFields.forEach(field => {
|
|
91
|
+
if (!inputs[field]) {
|
|
92
|
+
result.errors.push(`${field} is required`);
|
|
93
|
+
result.valid = false;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
@@ -118,6 +118,16 @@ export const ResourceFormatters = {
|
|
|
118
118
|
*/
|
|
119
119
|
configKey(camelCase) {
|
|
120
120
|
return NameFormatters.toKebabCase(camelCase);
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* Format package name for NPM
|
|
124
|
+
* Example: 'my-service' → 'my-service'
|
|
125
|
+
*/
|
|
126
|
+
packageName(serviceName) {
|
|
127
|
+
if (!serviceName) return '';
|
|
128
|
+
// For NPM packages, just use the service name as-is
|
|
129
|
+
// Scoped packages would be handled separately (e.g., @company/my-service)
|
|
130
|
+
return serviceName;
|
|
121
131
|
}
|
|
122
132
|
};
|
|
123
133
|
|
|
@@ -16,4 +16,16 @@ export { GracefulShutdownManager, getShutdownManager, initializeGracefulShutdown
|
|
|
16
16
|
export { executeWithRateLimit, queueRequest, getRateLimitStatus, clearQueues, RATE_LIMITS } from './rate-limiter.js';
|
|
17
17
|
|
|
18
18
|
// Unified error handling module (Phase 3.2.3d - consolidated from 5 sources)
|
|
19
|
-
export { default as ErrorHandler, createErrorResponse, createContextualError, createErrorHandler } from './ErrorHandler.js';
|
|
19
|
+
export { default as ErrorHandler, createErrorResponse, createContextualError, createErrorHandler } from './ErrorHandler.js';
|
|
20
|
+
|
|
21
|
+
// Progress display utilities
|
|
22
|
+
export { showProgressSpinner, showProgressWithSpinner } from './progress-spinner.js';
|
|
23
|
+
|
|
24
|
+
// Deployment validation
|
|
25
|
+
export { validateDeploymentPrerequisites, validateDeploymentInputs } from './deployment-validator.js';
|
|
26
|
+
|
|
27
|
+
// Sensitive information redaction
|
|
28
|
+
export { redactSensitiveInfo, redactSensitiveObject } from './sensitive-redactor.js';
|
|
29
|
+
|
|
30
|
+
// Configuration loading
|
|
31
|
+
export { ConfigLoader } from './config-loader.js';
|
|
@@ -98,6 +98,7 @@ export function showProgress(message, steps = ['⏳', '⚡', '✅']) {
|
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
100
|
* Ask for sensitive input (like API tokens) with hidden input
|
|
101
|
+
* Supports pasting with Ctrl+V or right-click paste
|
|
101
102
|
*/
|
|
102
103
|
export function askPassword(question) {
|
|
103
104
|
return new Promise(resolve => {
|
|
@@ -107,26 +108,41 @@ export function askPassword(question) {
|
|
|
107
108
|
// Hide input for sensitive data
|
|
108
109
|
process.stdin.setRawMode(true);
|
|
109
110
|
process.stdin.resume();
|
|
111
|
+
process.stdin.setEncoding('utf8');
|
|
110
112
|
let password = '';
|
|
111
|
-
const onData =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
113
|
+
const onData = chunk => {
|
|
114
|
+
// Handle multi-character input (paste operations)
|
|
115
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
116
|
+
const char = chunk[i];
|
|
117
|
+
const charCode = char.charCodeAt(0);
|
|
118
|
+
if (charCode === 13 || charCode === 10) {
|
|
119
|
+
// Enter key (CR or LF)
|
|
120
|
+
process.stdin.setRawMode(false);
|
|
121
|
+
process.stdin.pause();
|
|
122
|
+
process.stdin.removeListener('data', onData);
|
|
123
|
+
process.stdout.write('\n');
|
|
124
|
+
resolve(password);
|
|
125
|
+
return;
|
|
126
|
+
} else if (charCode === 127 || charCode === 8) {
|
|
127
|
+
// Backspace
|
|
128
|
+
if (password.length > 0) {
|
|
129
|
+
password = password.slice(0, -1);
|
|
130
|
+
process.stdout.write('\b \b');
|
|
131
|
+
}
|
|
132
|
+
} else if (charCode === 3) {
|
|
133
|
+
// Ctrl+C
|
|
134
|
+
process.stdin.setRawMode(false);
|
|
135
|
+
process.stdin.pause();
|
|
136
|
+
process.stdin.removeListener('data', onData);
|
|
137
|
+
process.stdout.write('\n');
|
|
138
|
+
console.log('\nOperation cancelled');
|
|
139
|
+
process.exit(0);
|
|
140
|
+
} else if (charCode >= 32 && charCode <= 126) {
|
|
141
|
+
// Printable characters
|
|
142
|
+
password += char;
|
|
143
|
+
process.stdout.write('*');
|
|
125
144
|
}
|
|
126
|
-
|
|
127
|
-
// Printable characters
|
|
128
|
-
password += char.toString();
|
|
129
|
-
process.stdout.write('*');
|
|
145
|
+
// Ignore other control characters (allows paste to work)
|
|
130
146
|
}
|
|
131
147
|
};
|
|
132
148
|
process.stdin.on('data', onData);
|
|
@@ -71,11 +71,11 @@ export class ProgressManager {
|
|
|
71
71
|
* @returns {ProgressManager} This instance for chaining
|
|
72
72
|
*/
|
|
73
73
|
nextStep(stepName = null) {
|
|
74
|
+
this.currentStep++;
|
|
75
|
+
this.stepStartTime = Date.now();
|
|
74
76
|
if (this.quiet) {
|
|
75
77
|
return this;
|
|
76
78
|
}
|
|
77
|
-
this.currentStep++;
|
|
78
|
-
this.stepStartTime = Date.now();
|
|
79
79
|
const name = stepName || this.steps[this.currentStep - 1] || `Step ${this.currentStep}`;
|
|
80
80
|
const progress = this.totalSteps > 0 ? Math.round(this.currentStep / this.totalSteps * 100) : 0;
|
|
81
81
|
if (this.output) {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress Spinner Utility
|
|
3
|
+
* Enhanced progress display with spinner animation
|
|
4
|
+
* Extracted from clodo-service-old.js for modular reuse
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Display progress with animated spinner
|
|
11
|
+
* @param {string} message - Progress message to display
|
|
12
|
+
* @param {number} duration - Duration in milliseconds (default: 2000)
|
|
13
|
+
* @returns {Promise} Resolves when progress completes
|
|
14
|
+
*/
|
|
15
|
+
export function showProgressSpinner(message, duration = 2000) {
|
|
16
|
+
return new Promise(resolve => {
|
|
17
|
+
process.stdout.write(chalk.cyan(`⏳ ${message}...`));
|
|
18
|
+
const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
19
|
+
let i = 0;
|
|
20
|
+
const interval = setInterval(() => {
|
|
21
|
+
process.stdout.write(`\r${chalk.cyan(spinner[i])} ${message}...`);
|
|
22
|
+
i = (i + 1) % spinner.length;
|
|
23
|
+
}, 100);
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
clearInterval(interval);
|
|
26
|
+
process.stdout.write(`\r${chalk.green('✅')} ${message}... Done!\n`);
|
|
27
|
+
resolve();
|
|
28
|
+
}, duration);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Display progress with custom spinner characters
|
|
34
|
+
* @param {string} message - Progress message
|
|
35
|
+
* @param {Array<string>} spinnerChars - Custom spinner characters
|
|
36
|
+
* @param {number} duration - Duration in milliseconds
|
|
37
|
+
* @returns {Promise} Resolves when complete
|
|
38
|
+
*/
|
|
39
|
+
export function showProgressWithSpinner(message, spinnerChars = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'], duration = 2000) {
|
|
40
|
+
return new Promise(resolve => {
|
|
41
|
+
process.stdout.write(chalk.cyan(`⏳ ${message}...`));
|
|
42
|
+
let i = 0;
|
|
43
|
+
const interval = setInterval(() => {
|
|
44
|
+
process.stdout.write(`\r${chalk.cyan(spinnerChars[i])} ${message}...`);
|
|
45
|
+
i = (i + 1) % spinnerChars.length;
|
|
46
|
+
}, 100);
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
clearInterval(interval);
|
|
49
|
+
process.stdout.write(`\r${chalk.green('✅')} ${message}... Done!\n`);
|
|
50
|
+
resolve();
|
|
51
|
+
}, duration);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensitive Information Redactor
|
|
3
|
+
* Advanced pattern-based redaction for logs and output
|
|
4
|
+
* Extracted from clodo-service-old.js for modular reuse
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Redact sensitive information from text using pattern matching
|
|
9
|
+
* @param {string} text - Text to redact
|
|
10
|
+
* @returns {string} Redacted text
|
|
11
|
+
*/
|
|
12
|
+
export function redactSensitiveInfo(text) {
|
|
13
|
+
if (typeof text !== 'string') return text;
|
|
14
|
+
|
|
15
|
+
// Patterns to redact
|
|
16
|
+
const patterns = [
|
|
17
|
+
// Cloudflare API tokens
|
|
18
|
+
[/(CLOUDFLARE_API_TOKEN=?)(\w{20,})/gi, '$1[REDACTED]'],
|
|
19
|
+
// Generic API tokens/keys - require minimum length
|
|
20
|
+
[/(token|api[_-]?token|api[_-]?key|auth[_-]?token)["']?[:=]\s*([a-zA-Z0-9_-]{6,})/gi, '$1: [REDACTED]'],
|
|
21
|
+
// Passwords - require minimum length
|
|
22
|
+
[/(password|passwd|pwd)["']?[:=]\s*([^"'\s]{4,})/gi, '$1: [REDACTED]'],
|
|
23
|
+
// Secrets - require minimum length
|
|
24
|
+
[/(secret|key)["']?[:=]\s*([a-zA-Z0-9_-]{6,})/gi, '$1: [REDACTED]'],
|
|
25
|
+
// Account IDs (partial redaction) - match 8+ characters
|
|
26
|
+
[/(account[_-]?id|zone[_-]?id)["']?[:=]\s*["']?([a-zA-Z0-9]{8})([a-zA-Z0-9]*)/gi, '$1: $2[REDACTED]']];
|
|
27
|
+
let redacted = text;
|
|
28
|
+
patterns.forEach(([pattern, replacement]) => {
|
|
29
|
+
redacted = redacted.replace(pattern, replacement);
|
|
30
|
+
});
|
|
31
|
+
return redacted;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Redact sensitive information from an object recursively
|
|
36
|
+
* @param {any} obj - Object to redact
|
|
37
|
+
* @param {Set} visited - Set of visited objects to prevent circular references
|
|
38
|
+
* @returns {any} Redacted object
|
|
39
|
+
*/
|
|
40
|
+
export function redactSensitiveObject(obj, visited = new Set()) {
|
|
41
|
+
// Handle circular references by returning a placeholder
|
|
42
|
+
if (obj && typeof obj === 'object') {
|
|
43
|
+
if (visited.has(obj)) {
|
|
44
|
+
return '[CIRCULAR REFERENCE]';
|
|
45
|
+
}
|
|
46
|
+
visited.add(obj);
|
|
47
|
+
}
|
|
48
|
+
if (typeof obj === 'string') {
|
|
49
|
+
return redactSensitiveInfo(obj);
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(obj)) {
|
|
52
|
+
// Process each array element individually
|
|
53
|
+
return obj.map(item => redactSensitiveObject(item, visited));
|
|
54
|
+
}
|
|
55
|
+
if (obj && typeof obj === 'object') {
|
|
56
|
+
const redacted = {};
|
|
57
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
58
|
+
const lowerKey = key.toLowerCase();
|
|
59
|
+
// Special handling for accountId and zoneId - allow partial redaction via regex
|
|
60
|
+
if (lowerKey.includes('accountid') || lowerKey.includes('zoneid')) {
|
|
61
|
+
if (typeof value === 'string') {
|
|
62
|
+
// Apply partial redaction for account/zone IDs
|
|
63
|
+
redacted[key] = value.replace(/^([a-zA-Z0-9]{8})([a-zA-Z0-9]*)$/, '$1[REDACTED]');
|
|
64
|
+
} else {
|
|
65
|
+
redacted[key] = redactSensitiveObject(value, visited);
|
|
66
|
+
}
|
|
67
|
+
} else if (isSensitiveKey(key)) {
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
// Redact each element in sensitive arrays
|
|
70
|
+
redacted[key] = value.map(() => '[REDACTED]');
|
|
71
|
+
} else {
|
|
72
|
+
redacted[key] = '[REDACTED]';
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
redacted[key] = redactSensitiveObject(value, visited);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return redacted;
|
|
79
|
+
}
|
|
80
|
+
return obj;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if a key name indicates sensitive information
|
|
85
|
+
* @param {string} key - Key name to check
|
|
86
|
+
* @returns {boolean} True if key is sensitive
|
|
87
|
+
*/
|
|
88
|
+
function isSensitiveKey(key) {
|
|
89
|
+
const sensitiveKeys = ['password', 'passwd', 'pwd', 'secret', 'key', 'token', 'apikey', 'cloudflaretoken', 'apitoken', 'authkey', 'privatekey'];
|
|
90
|
+
return sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive.toLowerCase()));
|
|
91
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
/**
|
|
9
9
|
* Import validators from src/utils (source of truth)
|
|
10
10
|
*/
|
|
11
|
-
import { validateServiceName, validateDomainName, validateCloudflareToken, validateCloudflareId, validateServiceType, validateEnvironment } from
|
|
11
|
+
import { validateServiceName, validateDomainName, validateCloudflareToken, validateCloudflareId, validateServiceType, validateEnvironment } from '../../../utils/validation.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Validation Registry - Single source of truth for all validators
|
package/dist/security/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { ConfigurationValidator } from './ConfigurationValidator.js';
|
|
7
7
|
// DeploymentManager removed - replaced by MultiDomainOrchestrator + WranglerConfigManager
|
|
8
8
|
import { SecretGenerator } from './SecretGenerator.js';
|
|
9
|
-
import { ErrorHandler } from
|
|
9
|
+
import { ErrorHandler } from '../../bin/shared/utils/index.js';
|
|
10
10
|
// InteractiveDeploymentConfigurator removed - replaced by InputCollector
|
|
11
11
|
|
|
12
12
|
export { ConfigurationValidator } from './ConfigurationValidator.js';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
export const INSECURE_PATTERNS = {
|
|
7
7
|
// Development/dummy API keys
|
|
8
|
-
DUMMY_API_KEYS: ['content-skimmer-dev-key', 'logger-service-dev-key', 'auth-service-dev-key', 'test-key', 'dev-key', 'dummy-key', 'placeholder-key', 'example-key', 'sample-key', 'demo-key', 'test-api-key-*', 'dummy-*-key', 'dev-*-secret', 'placeholder-*', 'example-*-token', 'fake-*-credential', 'mock-*-password'],
|
|
8
|
+
DUMMY_API_KEYS: ['content-skimmer-dev-key', 'logger-service-dev-key', 'auth-service-dev-key', 'test-key', 'dev-key', 'dummy-key', 'dummy-api-key', 'placeholder-key', 'example-key', 'sample-key', 'demo-key', 'test-api-key-*', 'dummy-*-key', 'dev-*-secret', 'placeholder-*', 'example-*-token', 'fake-*-credential', 'mock-*-password'],
|
|
9
9
|
// Weak secrets (common insecure values)
|
|
10
10
|
WEAK_SECRETS: ['secret', 'password', '123456', 'admin', 'test', 'changeme', 'default', 'password123', 'admin123', 'root', 'guest'],
|
|
11
11
|
// Development URLs that shouldn't be in production
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Constants
|
|
3
|
+
* Loads constants from validation-config.json to avoid duplication
|
|
4
|
+
* Provides easy access to domain templates, timeouts, and other config
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readFileSync } from 'fs';
|
|
8
|
+
import { join, dirname } from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
|
|
13
|
+
// Load validation config
|
|
14
|
+
let validationConfig;
|
|
15
|
+
try {
|
|
16
|
+
const configPath = join(__dirname, '..', '..', 'config', 'validation-config.json');
|
|
17
|
+
validationConfig = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.warn('⚠️ Could not load validation-config.json, using fallback constants');
|
|
20
|
+
validationConfig = null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get domain template for environment
|
|
25
|
+
* @param {string} environment - Environment name (development, staging, production)
|
|
26
|
+
* @returns {string} Domain template pattern
|
|
27
|
+
*/
|
|
28
|
+
export function getDomainTemplate(environment = 'production') {
|
|
29
|
+
if (validationConfig?.environments?.[environment]?.domainTemplate) {
|
|
30
|
+
return validationConfig.environments[environment].domainTemplate;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Fallback templates if config not available
|
|
34
|
+
const fallbacks = {
|
|
35
|
+
production: '{service}.{domain}',
|
|
36
|
+
staging: 'staging-{service}.{domain}',
|
|
37
|
+
development: 'dev-{service}.{domain}'
|
|
38
|
+
};
|
|
39
|
+
return fallbacks[environment] || fallbacks.production;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Build custom domain URL from template
|
|
44
|
+
* @param {string} serviceName - Service name
|
|
45
|
+
* @param {string} domain - Base domain (e.g., clodo.dev)
|
|
46
|
+
* @param {string} environment - Environment name
|
|
47
|
+
* @returns {string} Full custom domain URL
|
|
48
|
+
*/
|
|
49
|
+
export function buildCustomDomain(serviceName, domain, environment = 'production') {
|
|
50
|
+
const template = getDomainTemplate(environment);
|
|
51
|
+
const subdomain = template.replace('{service}', serviceName).replace('{domain}', domain);
|
|
52
|
+
return `https://${subdomain}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get environment-specific worker suffix
|
|
57
|
+
* @param {string} environment - Environment name
|
|
58
|
+
* @returns {string} Worker suffix (e.g., '-dev', '-staging', '')
|
|
59
|
+
*/
|
|
60
|
+
export function getWorkerSuffix(environment = 'production') {
|
|
61
|
+
return validationConfig?.environments?.[environment]?.workerSuffix || '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get environment-specific database suffix
|
|
66
|
+
* @param {string} environment - Environment name
|
|
67
|
+
* @returns {string} Database suffix (e.g., '-dev', '-staging', '')
|
|
68
|
+
*/
|
|
69
|
+
export function getDatabaseSuffix(environment = 'production') {
|
|
70
|
+
return validationConfig?.environments?.[environment]?.databaseSuffix || '';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get timing configuration
|
|
75
|
+
* @param {string} key - Timing key
|
|
76
|
+
* @returns {number} Timeout in milliseconds
|
|
77
|
+
*/
|
|
78
|
+
export function getTimeout(key) {
|
|
79
|
+
return validationConfig?.timing?.[key] || 30000; // Default 30s
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get all service types
|
|
84
|
+
* @returns {string[]} Array of valid service types
|
|
85
|
+
*/
|
|
86
|
+
export function getServiceTypes() {
|
|
87
|
+
return validationConfig?.validation?.serviceTypes || ['data-service', 'auth-service', 'content-service', 'api-gateway', 'static-site', 'generic'];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Export full config for direct access if needed
|
|
92
|
+
*/
|
|
93
|
+
export const VALIDATION_CONFIG = validationConfig;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Common constants
|
|
97
|
+
*/
|
|
98
|
+
export const CONSTANTS = {
|
|
99
|
+
DEFAULT_ENVIRONMENT: 'production',
|
|
100
|
+
SUPPORTED_ENVIRONMENTS: ['development', 'staging', 'production'],
|
|
101
|
+
WORKERS_DEV_SUFFIX: '.workers.dev'
|
|
102
|
+
};
|