tlc-claude-code 1.4.7 → 1.4.9

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.
Files changed (170) hide show
  1. package/docker-compose.dev.yml +6 -3
  2. package/package.json +1 -1
  3. package/server/index.js +229 -14
  4. package/server/lib/compliance/control-mapper.js +401 -0
  5. package/server/lib/compliance/control-mapper.test.js +117 -0
  6. package/server/lib/compliance/evidence-linker.js +296 -0
  7. package/server/lib/compliance/evidence-linker.test.js +121 -0
  8. package/server/lib/compliance/gdpr-checklist.js +416 -0
  9. package/server/lib/compliance/gdpr-checklist.test.js +131 -0
  10. package/server/lib/compliance/hipaa-checklist.js +277 -0
  11. package/server/lib/compliance/hipaa-checklist.test.js +101 -0
  12. package/server/lib/compliance/iso27001-checklist.js +287 -0
  13. package/server/lib/compliance/iso27001-checklist.test.js +99 -0
  14. package/server/lib/compliance/multi-framework-reporter.js +284 -0
  15. package/server/lib/compliance/multi-framework-reporter.test.js +127 -0
  16. package/server/lib/compliance/pci-dss-checklist.js +214 -0
  17. package/server/lib/compliance/pci-dss-checklist.test.js +95 -0
  18. package/server/lib/compliance/trust-centre.js +187 -0
  19. package/server/lib/compliance/trust-centre.test.js +93 -0
  20. package/server/lib/dashboard/api-server.js +155 -0
  21. package/server/lib/dashboard/api-server.test.js +155 -0
  22. package/server/lib/dashboard/health-api.js +199 -0
  23. package/server/lib/dashboard/health-api.test.js +122 -0
  24. package/server/lib/dashboard/notes-api.js +234 -0
  25. package/server/lib/dashboard/notes-api.test.js +134 -0
  26. package/server/lib/dashboard/router-api.js +176 -0
  27. package/server/lib/dashboard/router-api.test.js +132 -0
  28. package/server/lib/dashboard/tasks-api.js +289 -0
  29. package/server/lib/dashboard/tasks-api.test.js +161 -0
  30. package/server/lib/dashboard/tlc-introspection.js +197 -0
  31. package/server/lib/dashboard/tlc-introspection.test.js +138 -0
  32. package/server/lib/dashboard/version-api.js +222 -0
  33. package/server/lib/dashboard/version-api.test.js +112 -0
  34. package/server/lib/dashboard/websocket-server.js +104 -0
  35. package/server/lib/dashboard/websocket-server.test.js +118 -0
  36. package/server/lib/deploy/branch-classifier.js +163 -0
  37. package/server/lib/deploy/branch-classifier.test.js +164 -0
  38. package/server/lib/deploy/deployment-approval.js +299 -0
  39. package/server/lib/deploy/deployment-approval.test.js +296 -0
  40. package/server/lib/deploy/deployment-audit.js +374 -0
  41. package/server/lib/deploy/deployment-audit.test.js +307 -0
  42. package/server/lib/deploy/deployment-executor.js +335 -0
  43. package/server/lib/deploy/deployment-executor.test.js +329 -0
  44. package/server/lib/deploy/deployment-rules.js +163 -0
  45. package/server/lib/deploy/deployment-rules.test.js +188 -0
  46. package/server/lib/deploy/rollback-manager.js +379 -0
  47. package/server/lib/deploy/rollback-manager.test.js +321 -0
  48. package/server/lib/deploy/security-gates.js +236 -0
  49. package/server/lib/deploy/security-gates.test.js +222 -0
  50. package/server/lib/k8s/gitops-config.js +188 -0
  51. package/server/lib/k8s/gitops-config.test.js +59 -0
  52. package/server/lib/k8s/helm-generator.js +196 -0
  53. package/server/lib/k8s/helm-generator.test.js +59 -0
  54. package/server/lib/k8s/kustomize-generator.js +176 -0
  55. package/server/lib/k8s/kustomize-generator.test.js +58 -0
  56. package/server/lib/k8s/network-policy.js +114 -0
  57. package/server/lib/k8s/network-policy.test.js +53 -0
  58. package/server/lib/k8s/pod-security.js +114 -0
  59. package/server/lib/k8s/pod-security.test.js +55 -0
  60. package/server/lib/k8s/rbac-generator.js +132 -0
  61. package/server/lib/k8s/rbac-generator.test.js +57 -0
  62. package/server/lib/k8s/resource-manager.js +172 -0
  63. package/server/lib/k8s/resource-manager.test.js +60 -0
  64. package/server/lib/k8s/secrets-encryption.js +168 -0
  65. package/server/lib/k8s/secrets-encryption.test.js +49 -0
  66. package/server/lib/monitoring/alert-manager.js +238 -0
  67. package/server/lib/monitoring/alert-manager.test.js +106 -0
  68. package/server/lib/monitoring/health-check.js +226 -0
  69. package/server/lib/monitoring/health-check.test.js +176 -0
  70. package/server/lib/monitoring/incident-manager.js +230 -0
  71. package/server/lib/monitoring/incident-manager.test.js +98 -0
  72. package/server/lib/monitoring/log-aggregator.js +147 -0
  73. package/server/lib/monitoring/log-aggregator.test.js +89 -0
  74. package/server/lib/monitoring/metrics-collector.js +337 -0
  75. package/server/lib/monitoring/metrics-collector.test.js +172 -0
  76. package/server/lib/monitoring/status-page.js +214 -0
  77. package/server/lib/monitoring/status-page.test.js +105 -0
  78. package/server/lib/monitoring/uptime-monitor.js +194 -0
  79. package/server/lib/monitoring/uptime-monitor.test.js +109 -0
  80. package/server/lib/network/fail2ban-config.js +294 -0
  81. package/server/lib/network/fail2ban-config.test.js +275 -0
  82. package/server/lib/network/firewall-manager.js +252 -0
  83. package/server/lib/network/firewall-manager.test.js +254 -0
  84. package/server/lib/network/geoip-filter.js +282 -0
  85. package/server/lib/network/geoip-filter.test.js +264 -0
  86. package/server/lib/network/rate-limiter.js +229 -0
  87. package/server/lib/network/rate-limiter.test.js +293 -0
  88. package/server/lib/network/request-validator.js +351 -0
  89. package/server/lib/network/request-validator.test.js +345 -0
  90. package/server/lib/network/security-headers.js +251 -0
  91. package/server/lib/network/security-headers.test.js +283 -0
  92. package/server/lib/network/tls-config.js +210 -0
  93. package/server/lib/network/tls-config.test.js +248 -0
  94. package/server/lib/security/auth-security.js +369 -0
  95. package/server/lib/security/auth-security.test.js +448 -0
  96. package/server/lib/security/cis-benchmark.js +152 -0
  97. package/server/lib/security/cis-benchmark.test.js +137 -0
  98. package/server/lib/security/compose-templates.js +312 -0
  99. package/server/lib/security/compose-templates.test.js +229 -0
  100. package/server/lib/security/container-runtime.js +456 -0
  101. package/server/lib/security/container-runtime.test.js +503 -0
  102. package/server/lib/security/cors-validator.js +278 -0
  103. package/server/lib/security/cors-validator.test.js +310 -0
  104. package/server/lib/security/crypto-utils.js +253 -0
  105. package/server/lib/security/crypto-utils.test.js +409 -0
  106. package/server/lib/security/dockerfile-linter.js +459 -0
  107. package/server/lib/security/dockerfile-linter.test.js +483 -0
  108. package/server/lib/security/dockerfile-templates.js +278 -0
  109. package/server/lib/security/dockerfile-templates.test.js +164 -0
  110. package/server/lib/security/error-sanitizer.js +426 -0
  111. package/server/lib/security/error-sanitizer.test.js +331 -0
  112. package/server/lib/security/headers-generator.js +368 -0
  113. package/server/lib/security/headers-generator.test.js +398 -0
  114. package/server/lib/security/image-scanner.js +83 -0
  115. package/server/lib/security/image-scanner.test.js +106 -0
  116. package/server/lib/security/input-validator.js +352 -0
  117. package/server/lib/security/input-validator.test.js +330 -0
  118. package/server/lib/security/network-policy.js +174 -0
  119. package/server/lib/security/network-policy.test.js +164 -0
  120. package/server/lib/security/output-encoder.js +237 -0
  121. package/server/lib/security/output-encoder.test.js +276 -0
  122. package/server/lib/security/path-validator.js +359 -0
  123. package/server/lib/security/path-validator.test.js +293 -0
  124. package/server/lib/security/query-builder.js +421 -0
  125. package/server/lib/security/query-builder.test.js +318 -0
  126. package/server/lib/security/secret-detector.js +290 -0
  127. package/server/lib/security/secret-detector.test.js +354 -0
  128. package/server/lib/security/secrets-validator.js +137 -0
  129. package/server/lib/security/secrets-validator.test.js +120 -0
  130. package/server/lib/security-testing/dast-runner.js +154 -0
  131. package/server/lib/security-testing/dast-runner.test.js +62 -0
  132. package/server/lib/security-testing/dependency-scanner.js +172 -0
  133. package/server/lib/security-testing/dependency-scanner.test.js +64 -0
  134. package/server/lib/security-testing/pentest-runner.js +230 -0
  135. package/server/lib/security-testing/pentest-runner.test.js +60 -0
  136. package/server/lib/security-testing/sast-runner.js +136 -0
  137. package/server/lib/security-testing/sast-runner.test.js +62 -0
  138. package/server/lib/security-testing/secret-scanner.js +153 -0
  139. package/server/lib/security-testing/secret-scanner.test.js +66 -0
  140. package/server/lib/security-testing/security-gate.js +216 -0
  141. package/server/lib/security-testing/security-gate.test.js +115 -0
  142. package/server/lib/security-testing/security-reporter.js +303 -0
  143. package/server/lib/security-testing/security-reporter.test.js +114 -0
  144. package/server/lib/standards/audit-checker.js +546 -0
  145. package/server/lib/standards/audit-checker.test.js +415 -0
  146. package/server/lib/standards/cleanup-executor.js +452 -0
  147. package/server/lib/standards/cleanup-executor.test.js +293 -0
  148. package/server/lib/standards/refactor-stepper.js +425 -0
  149. package/server/lib/standards/refactor-stepper.test.js +298 -0
  150. package/server/lib/standards/standards-injector.js +167 -0
  151. package/server/lib/standards/standards-injector.test.js +232 -0
  152. package/server/lib/user-management.test.js +284 -0
  153. package/server/lib/vps/backup-manager.js +157 -0
  154. package/server/lib/vps/backup-manager.test.js +59 -0
  155. package/server/lib/vps/caddy-config.js +159 -0
  156. package/server/lib/vps/caddy-config.test.js +48 -0
  157. package/server/lib/vps/compose-orchestrator.js +219 -0
  158. package/server/lib/vps/compose-orchestrator.test.js +50 -0
  159. package/server/lib/vps/database-config.js +208 -0
  160. package/server/lib/vps/database-config.test.js +47 -0
  161. package/server/lib/vps/deploy-script.js +211 -0
  162. package/server/lib/vps/deploy-script.test.js +53 -0
  163. package/server/lib/vps/secrets-manager.js +148 -0
  164. package/server/lib/vps/secrets-manager.test.js +58 -0
  165. package/server/lib/vps/server-hardening.js +174 -0
  166. package/server/lib/vps/server-hardening.test.js +70 -0
  167. package/server/package-lock.json +19 -0
  168. package/server/package.json +1 -0
  169. package/server/templates/CLAUDE.md +37 -0
  170. package/server/templates/CODING-STANDARDS.md +408 -0
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Deploy Script Generator
3
+ * Blue-green and rolling deployment scripts for VPS
4
+ */
5
+
6
+ /**
7
+ * Generates a blue-green deployment script
8
+ * @param {Object} options - Deployment options
9
+ * @param {string} options.service - Service name
10
+ * @returns {string} Blue-green deployment script
11
+ */
12
+ export function generateBlueGreenScript({ service }) {
13
+ return `#!/bin/bash
14
+ set -euo pipefail
15
+
16
+ # Blue-green deployment for ${service}
17
+ SERVICE="${service}"
18
+ CURRENT_COLOR=$(docker ps --filter "name=\${SERVICE}" --format '{{.Names}}' | grep -o 'blue\\|green' || echo "blue")
19
+
20
+ if [ "\$CURRENT_COLOR" = "blue" ]; then
21
+ NEW_COLOR="green"
22
+ else
23
+ NEW_COLOR="blue"
24
+ fi
25
+
26
+ echo "Current: \$CURRENT_COLOR, Deploying to: \$NEW_COLOR"
27
+
28
+ # Deploy to new color
29
+ docker-compose up -d "\${SERVICE}-\${NEW_COLOR}"
30
+
31
+ # Wait for health check
32
+ sleep 10
33
+
34
+ # Switch traffic
35
+ docker exec nginx nginx -s reload
36
+
37
+ # Stop old color
38
+ docker-compose stop "\${SERVICE}-\${CURRENT_COLOR}"
39
+
40
+ echo "Deployed \${SERVICE} to \${NEW_COLOR}"
41
+ `;
42
+ }
43
+
44
+ /**
45
+ * Generates a rolling update deployment script
46
+ * @param {Object} options - Deployment options
47
+ * @param {string} options.service - Service name
48
+ * @param {number} [options.replicas=3] - Number of replicas
49
+ * @returns {string} Rolling update script
50
+ */
51
+ export function generateRollingScript({ service, replicas = 3 }) {
52
+ return `#!/bin/bash
53
+ set -euo pipefail
54
+
55
+ # Rolling update for ${service}
56
+ SERVICE="${service}"
57
+ REPLICAS=${replicas}
58
+
59
+ echo "Starting rolling update for \${SERVICE} with \${REPLICAS} replicas"
60
+
61
+ for i in $(seq 1 \$REPLICAS); do
62
+ echo "Updating replica \$i of \$REPLICAS..."
63
+
64
+ # Stop old instance
65
+ docker-compose stop "\${SERVICE}-\$i" || true
66
+
67
+ # Start new instance
68
+ docker-compose up -d "\${SERVICE}-\$i"
69
+
70
+ # Wait for health
71
+ sleep 5
72
+
73
+ echo "Replica \$i updated"
74
+ done
75
+
76
+ echo "Rolling update complete"
77
+ `;
78
+ }
79
+
80
+ /**
81
+ * Adds health verification to deployment
82
+ * @param {Object} options - Health check options
83
+ * @param {string} options.endpoint - Health endpoint
84
+ * @param {number} [options.timeout=30] - Timeout in seconds
85
+ * @param {number} [options.retries=5] - Number of retries
86
+ * @returns {string} Health verification script snippet
87
+ */
88
+ export function addHealthVerification({ endpoint, timeout = 30, retries = 5 }) {
89
+ return `# Health check verification
90
+ HEALTH_ENDPOINT="${endpoint}"
91
+ TIMEOUT=${timeout}
92
+ RETRIES=${retries}
93
+
94
+ check_health() {
95
+ local attempt=1
96
+ while [ \$attempt -le \$RETRIES ]; do
97
+ echo "Health check attempt \$attempt/\$RETRIES..."
98
+ if curl -sf "\${HEALTH_ENDPOINT}" > /dev/null; then
99
+ echo "Health check passed"
100
+ return 0
101
+ fi
102
+ sleep \$(( TIMEOUT / RETRIES ))
103
+ attempt=\$((attempt + 1))
104
+ done
105
+ echo "Health check failed"
106
+ return 1
107
+ }
108
+ `;
109
+ }
110
+
111
+ /**
112
+ * Adds rollback support to deployment
113
+ * @param {Object} options - Rollback options
114
+ * @returns {string} Rollback script snippet
115
+ */
116
+ export function addRollbackSupport(options = {}) {
117
+ return `# Rollback support
118
+ PREVIOUS_VERSION=""
119
+
120
+ save_previous_version() {
121
+ PREVIOUS_VERSION=\$(docker images --format '{{.Tag}}' | head -1)
122
+ echo "Saved previous version: \$PREVIOUS_VERSION"
123
+ }
124
+
125
+ rollback() {
126
+ echo "Rolling back to \$PREVIOUS_VERSION..."
127
+ docker-compose down
128
+ docker tag "\${SERVICE}:\${PREVIOUS_VERSION}" "\${SERVICE}:latest"
129
+ docker-compose up -d
130
+ echo "Rollback complete"
131
+ }
132
+
133
+ # Call rollback on failure
134
+ trap 'rollback' ERR
135
+ `;
136
+ }
137
+
138
+ /**
139
+ * Generates pre and post deployment hooks
140
+ * @param {Object} options - Hook options
141
+ * @param {string} [options.pre] - Pre-deployment command
142
+ * @param {string} [options.post] - Post-deployment command
143
+ * @returns {Object} Generated hooks
144
+ */
145
+ export function generateHooks({ pre, post }) {
146
+ const hooks = {};
147
+
148
+ if (pre) {
149
+ hooks.pre = `# Pre-deployment hook
150
+ echo "Running pre-deployment hook..."
151
+ ${pre}
152
+ echo "Pre-deployment hook complete"
153
+ `;
154
+ }
155
+
156
+ if (post) {
157
+ hooks.post = `# Post-deployment hook
158
+ echo "Running post-deployment hook..."
159
+ ${post}
160
+ echo "Post-deployment hook complete"
161
+ `;
162
+ }
163
+
164
+ return hooks;
165
+ }
166
+
167
+ /**
168
+ * Creates a deploy script generator instance
169
+ * @returns {Object} Generator with blueGreen and rolling methods
170
+ */
171
+ export function createDeployScriptGenerator() {
172
+ return {
173
+ /**
174
+ * Generates a blue-green deployment script
175
+ * @param {Object} options - Deployment options
176
+ * @returns {string} Deployment script
177
+ */
178
+ blueGreen(options) {
179
+ let script = generateBlueGreenScript(options);
180
+
181
+ if (options.healthEndpoint) {
182
+ script += '\n' + addHealthVerification({ endpoint: options.healthEndpoint });
183
+ }
184
+
185
+ if (options.rollback !== false) {
186
+ script += '\n' + addRollbackSupport();
187
+ }
188
+
189
+ return script;
190
+ },
191
+
192
+ /**
193
+ * Generates a rolling update deployment script
194
+ * @param {Object} options - Deployment options
195
+ * @returns {string} Deployment script
196
+ */
197
+ rolling(options) {
198
+ let script = generateRollingScript(options);
199
+
200
+ if (options.healthEndpoint) {
201
+ script += '\n' + addHealthVerification({ endpoint: options.healthEndpoint });
202
+ }
203
+
204
+ if (options.rollback !== false) {
205
+ script += '\n' + addRollbackSupport();
206
+ }
207
+
208
+ return script;
209
+ }
210
+ };
211
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Deploy Script Generator Tests
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { generateBlueGreenScript, generateRollingScript, addHealthVerification, addRollbackSupport, generateHooks, createDeployScriptGenerator } from './deploy-script.js';
6
+
7
+ describe('deploy-script', () => {
8
+ describe('generateBlueGreenScript', () => {
9
+ it('generates blue-green deploy script', () => {
10
+ const script = generateBlueGreenScript({ service: 'app' });
11
+ expect(script).toContain('blue');
12
+ expect(script).toContain('green');
13
+ });
14
+ });
15
+
16
+ describe('generateRollingScript', () => {
17
+ it('generates rolling update script', () => {
18
+ const script = generateRollingScript({ service: 'app', replicas: 3 });
19
+ expect(script).toContain('rolling');
20
+ });
21
+ });
22
+
23
+ describe('addHealthVerification', () => {
24
+ it('includes health check', () => {
25
+ const script = addHealthVerification({ endpoint: '/health' });
26
+ expect(script).toContain('health');
27
+ expect(script).toContain('curl');
28
+ });
29
+ });
30
+
31
+ describe('addRollbackSupport', () => {
32
+ it('supports rollback on failure', () => {
33
+ const script = addRollbackSupport({});
34
+ expect(script).toContain('rollback');
35
+ });
36
+ });
37
+
38
+ describe('generateHooks', () => {
39
+ it('generates pre/post hooks', () => {
40
+ const hooks = generateHooks({ pre: 'npm run migrate', post: 'npm run notify' });
41
+ expect(hooks.pre).toContain('migrate');
42
+ expect(hooks.post).toContain('notify');
43
+ });
44
+ });
45
+
46
+ describe('createDeployScriptGenerator', () => {
47
+ it('creates generator', () => {
48
+ const generator = createDeployScriptGenerator();
49
+ expect(generator.blueGreen).toBeDefined();
50
+ expect(generator.rolling).toBeDefined();
51
+ });
52
+ });
53
+ });
@@ -0,0 +1,148 @@
1
+ /**
2
+ * VPS Secrets Manager
3
+ * Secrets generation and rotation for VPS deployments
4
+ */
5
+
6
+ import crypto from 'crypto';
7
+
8
+ /**
9
+ * Creates a secrets directory with secure permissions
10
+ * @param {Object} options - Directory options
11
+ * @param {string} options.path - Directory path
12
+ * @param {Function} [options.mkdir] - mkdir function
13
+ * @param {Function} [options.chmod] - chmod function
14
+ * @returns {Promise<Object>} Creation result
15
+ */
16
+ export async function createSecretsDir({ path, mkdir, chmod }) {
17
+ if (mkdir) {
18
+ await mkdir(path, { recursive: true });
19
+ }
20
+ if (chmod) {
21
+ await chmod(path, 0o600);
22
+ }
23
+ return { success: true, path };
24
+ }
25
+
26
+ /**
27
+ * Generates secrets from a template
28
+ * @param {Object} options - Generation options
29
+ * @param {Object} options.template - Secret template with name and length
30
+ * @returns {Object} Generated secrets
31
+ */
32
+ export function generateSecrets({ template }) {
33
+ const secrets = {};
34
+
35
+ for (const [name, config] of Object.entries(template)) {
36
+ const length = config.length || 32;
37
+ // Generate a random string of the specified length
38
+ secrets[name] = crypto.randomBytes(Math.ceil(length / 2))
39
+ .toString('hex')
40
+ .slice(0, length);
41
+ }
42
+
43
+ return secrets;
44
+ }
45
+
46
+ /**
47
+ * Rotates secrets safely
48
+ * @param {Object} options - Rotation options
49
+ * @param {string[]} options.secrets - Secret names to rotate
50
+ * @param {Function} [options.mockRotate] - Mock rotate function for testing
51
+ * @returns {Promise<Object>} Rotation result
52
+ */
53
+ export async function rotateSecrets({ secrets, mockRotate }) {
54
+ const rotated = [];
55
+
56
+ for (const secret of secrets) {
57
+ if (mockRotate) {
58
+ await mockRotate(secret);
59
+ }
60
+ rotated.push(secret);
61
+ }
62
+
63
+ return { rotated, timestamp: new Date().toISOString() };
64
+ }
65
+
66
+ /**
67
+ * Validates secret format
68
+ * @param {Object} options - Validation options
69
+ * @param {string} options.name - Secret name
70
+ * @param {string} options.value - Secret value
71
+ * @returns {Object} Validation result
72
+ */
73
+ export function validateSecretFormat({ name, value }) {
74
+ // Secret names should not contain spaces
75
+ if (name.includes(' ')) {
76
+ return { valid: false, error: 'Secret name cannot contain spaces' };
77
+ }
78
+
79
+ // Secret names should be uppercase with underscores
80
+ if (!/^[A-Z][A-Z0-9_]*$/.test(name)) {
81
+ return { valid: false, error: 'Secret name must be uppercase with underscores' };
82
+ }
83
+
84
+ // Value should not be empty
85
+ if (!value || value.length === 0) {
86
+ return { valid: false, error: 'Secret value cannot be empty' };
87
+ }
88
+
89
+ return { valid: true };
90
+ }
91
+
92
+ /**
93
+ * Creates a secrets manager instance
94
+ * @returns {Object} Secrets manager with get, set, and rotate methods
95
+ */
96
+ export function createSecretsManager() {
97
+ const secrets = new Map();
98
+
99
+ const manager = {
100
+ /**
101
+ * Gets a secret value
102
+ * @param {string} name - Secret name
103
+ * @returns {string|undefined} Secret value
104
+ */
105
+ get(name) {
106
+ return secrets.get(name);
107
+ },
108
+
109
+ /**
110
+ * Sets a secret value
111
+ * @param {string} name - Secret name
112
+ * @param {string} value - Secret value
113
+ * @returns {boolean} Success status
114
+ */
115
+ set(name, value) {
116
+ const validation = validateSecretFormat({ name, value });
117
+ if (!validation.valid) {
118
+ return false;
119
+ }
120
+ secrets.set(name, value);
121
+ return true;
122
+ },
123
+
124
+ /**
125
+ * Rotates a secret
126
+ * @param {string} name - Secret name to rotate
127
+ * @param {number} [length=32] - New secret length
128
+ * @returns {boolean} Success status
129
+ */
130
+ rotate(name, length = 32) {
131
+ const newValue = crypto.randomBytes(Math.ceil(length / 2))
132
+ .toString('hex')
133
+ .slice(0, length);
134
+ secrets.set(name, newValue);
135
+ return true;
136
+ },
137
+
138
+ /**
139
+ * Returns safe string representation (no secrets exposed)
140
+ * @returns {string} Safe string representation
141
+ */
142
+ toString() {
143
+ return `[SecretsManager: ${secrets.size} secrets]`;
144
+ }
145
+ };
146
+
147
+ return manager;
148
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * VPS Secrets Manager Tests
3
+ */
4
+ import { describe, it, expect, vi } from 'vitest';
5
+ import { createSecretsDir, generateSecrets, rotateSecrets, validateSecretFormat, createSecretsManager } from './secrets-manager.js';
6
+
7
+ describe('secrets-manager', () => {
8
+ describe('createSecretsDir', () => {
9
+ it('creates directory with 600 permissions', async () => {
10
+ const mockMkdir = vi.fn().mockResolvedValue(true);
11
+ const mockChmod = vi.fn().mockResolvedValue(true);
12
+ await createSecretsDir({ path: '/etc/tlc/secrets', mkdir: mockMkdir, chmod: mockChmod });
13
+ expect(mockChmod).toHaveBeenCalledWith('/etc/tlc/secrets', 0o600);
14
+ });
15
+ });
16
+
17
+ describe('generateSecrets', () => {
18
+ it('generates secrets from template', () => {
19
+ const secrets = generateSecrets({ template: { DB_PASSWORD: { length: 32 }, API_KEY: { length: 64 } } });
20
+ expect(secrets.DB_PASSWORD.length).toBe(32);
21
+ expect(secrets.API_KEY.length).toBe(64);
22
+ });
23
+ });
24
+
25
+ describe('rotateSecrets', () => {
26
+ it('rotates secrets safely', async () => {
27
+ const result = await rotateSecrets({ secrets: ['DB_PASSWORD'], mockRotate: vi.fn().mockResolvedValue(true) });
28
+ expect(result.rotated).toContain('DB_PASSWORD');
29
+ });
30
+ });
31
+
32
+ describe('validateSecretFormat', () => {
33
+ it('validates secret format', () => {
34
+ const result = validateSecretFormat({ name: 'API_KEY', value: 'abc123' });
35
+ expect(result.valid).toBe(true);
36
+ });
37
+
38
+ it('rejects secrets with spaces', () => {
39
+ const result = validateSecretFormat({ name: 'API KEY', value: 'abc' });
40
+ expect(result.valid).toBe(false);
41
+ });
42
+ });
43
+
44
+ describe('createSecretsManager', () => {
45
+ it('creates manager', () => {
46
+ const manager = createSecretsManager();
47
+ expect(manager.get).toBeDefined();
48
+ expect(manager.set).toBeDefined();
49
+ expect(manager.rotate).toBeDefined();
50
+ });
51
+
52
+ it('never exposes secrets in logs', () => {
53
+ const manager = createSecretsManager();
54
+ const output = manager.toString();
55
+ expect(output).not.toContain('password');
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Server Hardening Configuration
3
+ * SSH config, sysctl, user management, security limits
4
+ */
5
+
6
+ /**
7
+ * Generate SSH daemon configuration
8
+ * @param {Object} options - SSH configuration options
9
+ * @param {boolean} [options.passwordAuth=false] - Enable password authentication
10
+ * @param {number} [options.port=22] - SSH port
11
+ * @param {boolean} [options.permitRootLogin=false] - Allow root login
12
+ * @returns {string} SSH configuration
13
+ */
14
+ export function generateSshConfig(options = {}) {
15
+ const {
16
+ passwordAuth = false,
17
+ port = 22,
18
+ permitRootLogin = false,
19
+ } = options;
20
+
21
+ const lines = [
22
+ '# SSH Server Configuration',
23
+ '# Generated by TLC Server Hardening',
24
+ '',
25
+ `Port ${port}`,
26
+ 'Protocol 2',
27
+ '',
28
+ '# Authentication',
29
+ `PasswordAuthentication ${passwordAuth ? 'yes' : 'no'}`,
30
+ 'PubkeyAuthentication yes',
31
+ `PermitRootLogin ${permitRootLogin ? 'yes' : 'no'}`,
32
+ 'PermitEmptyPasswords no',
33
+ 'ChallengeResponseAuthentication no',
34
+ '',
35
+ '# Security',
36
+ 'X11Forwarding no',
37
+ 'MaxAuthTries 3',
38
+ 'LoginGraceTime 60',
39
+ 'ClientAliveInterval 300',
40
+ 'ClientAliveCountMax 2',
41
+ '',
42
+ '# Logging',
43
+ 'SyslogFacility AUTH',
44
+ 'LogLevel VERBOSE',
45
+ ];
46
+
47
+ return lines.join('\n');
48
+ }
49
+
50
+ /**
51
+ * Generate sysctl kernel parameter configuration
52
+ * @param {Object} options - Sysctl options
53
+ * @returns {string} Sysctl configuration
54
+ */
55
+ export function generateSysctlConfig(options = {}) {
56
+ const lines = [
57
+ '# Sysctl Security Configuration',
58
+ '# Generated by TLC Server Hardening',
59
+ '',
60
+ '# Disable IP forwarding',
61
+ 'net.ipv4.ip_forward = 0',
62
+ 'net.ipv6.conf.all.forwarding = 0',
63
+ '',
64
+ '# Disable source routing',
65
+ 'net.ipv4.conf.all.accept_source_route = 0',
66
+ 'net.ipv4.conf.default.accept_source_route = 0',
67
+ 'net.ipv6.conf.all.accept_source_route = 0',
68
+ '',
69
+ '# Disable ICMP redirects',
70
+ 'net.ipv4.conf.all.accept_redirects = 0',
71
+ 'net.ipv4.conf.default.accept_redirects = 0',
72
+ 'net.ipv4.conf.all.send_redirects = 0',
73
+ 'net.ipv4.conf.default.send_redirects = 0',
74
+ '',
75
+ '# Enable SYN flood protection',
76
+ 'net.ipv4.tcp_syncookies = 1',
77
+ 'net.ipv4.tcp_max_syn_backlog = 2048',
78
+ '',
79
+ '# Enable reverse path filtering',
80
+ 'net.ipv4.conf.all.rp_filter = 1',
81
+ 'net.ipv4.conf.default.rp_filter = 1',
82
+ '',
83
+ '# Log martian packets',
84
+ 'net.ipv4.conf.all.log_martians = 1',
85
+ '',
86
+ '# Ignore ICMP broadcast requests',
87
+ 'net.ipv4.icmp_echo_ignore_broadcasts = 1',
88
+ '',
89
+ '# Kernel hardening',
90
+ 'kernel.randomize_va_space = 2',
91
+ 'kernel.kptr_restrict = 2',
92
+ ];
93
+
94
+ return lines.join('\n');
95
+ }
96
+
97
+ /**
98
+ * Generate commands to disable unnecessary services
99
+ * @param {string[]} services - List of services to disable
100
+ * @returns {string[]} Array of systemctl commands
101
+ */
102
+ export function disableServices(services = []) {
103
+ const commands = [];
104
+
105
+ for (const service of services) {
106
+ commands.push(`systemctl stop ${service}`);
107
+ commands.push(`systemctl disable ${service}`);
108
+ commands.push(`systemctl mask ${service}`);
109
+ }
110
+
111
+ return commands;
112
+ }
113
+
114
+ /**
115
+ * Generate unattended-upgrades configuration
116
+ * @param {Object} options - Auto-update options
117
+ * @returns {string} Unattended-upgrades configuration
118
+ */
119
+ export function enableAutoUpdates(options = {}) {
120
+ const {
121
+ rebootTime = '02:00',
122
+ autoReboot = false,
123
+ } = options;
124
+
125
+ const lines = [
126
+ '// Unattended-Upgrade Configuration',
127
+ '// Generated by TLC Server Hardening',
128
+ '',
129
+ 'Unattended-Upgrade::Allowed-Origins {',
130
+ ' "${distro_id}:${distro_codename}";',
131
+ ' "${distro_id}:${distro_codename}-security";',
132
+ ' "${distro_id}ESMApps:${distro_codename}-apps-security";',
133
+ ' "${distro_id}ESM:${distro_codename}-infra-security";',
134
+ '};',
135
+ '',
136
+ 'Unattended-Upgrade::Package-Blacklist {',
137
+ '};',
138
+ '',
139
+ `Unattended-Upgrade::Automatic-Reboot "${autoReboot ? 'true' : 'false'}";`,
140
+ `Unattended-Upgrade::Automatic-Reboot-Time "${rebootTime}";`,
141
+ '',
142
+ 'Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";',
143
+ 'Unattended-Upgrade::Remove-Unused-Dependencies "true";',
144
+ ];
145
+
146
+ return lines.join('\n');
147
+ }
148
+
149
+ /**
150
+ * Create a server hardening manager
151
+ * @returns {Object} Server hardening manager with methods
152
+ */
153
+ export function createServerHardening() {
154
+ return {
155
+ generateSshConfig,
156
+ generateSysctl: generateSysctlConfig,
157
+ disableServices,
158
+ enableAutoUpdates,
159
+
160
+ /**
161
+ * Generate all hardening configurations
162
+ * @param {Object} options - Configuration options
163
+ * @returns {Object} All generated configurations
164
+ */
165
+ generateAll(options = {}) {
166
+ return {
167
+ ssh: generateSshConfig(options.ssh || {}),
168
+ sysctl: generateSysctlConfig(options.sysctl || {}),
169
+ disableCommands: disableServices(options.disableServices || []),
170
+ autoUpdates: enableAutoUpdates(options.autoUpdates || {}),
171
+ };
172
+ },
173
+ };
174
+ }