tlc-claude-code 1.4.8 → 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 (169) hide show
  1. package/package.json +1 -1
  2. package/server/index.js +229 -14
  3. package/server/lib/compliance/control-mapper.js +401 -0
  4. package/server/lib/compliance/control-mapper.test.js +117 -0
  5. package/server/lib/compliance/evidence-linker.js +296 -0
  6. package/server/lib/compliance/evidence-linker.test.js +121 -0
  7. package/server/lib/compliance/gdpr-checklist.js +416 -0
  8. package/server/lib/compliance/gdpr-checklist.test.js +131 -0
  9. package/server/lib/compliance/hipaa-checklist.js +277 -0
  10. package/server/lib/compliance/hipaa-checklist.test.js +101 -0
  11. package/server/lib/compliance/iso27001-checklist.js +287 -0
  12. package/server/lib/compliance/iso27001-checklist.test.js +99 -0
  13. package/server/lib/compliance/multi-framework-reporter.js +284 -0
  14. package/server/lib/compliance/multi-framework-reporter.test.js +127 -0
  15. package/server/lib/compliance/pci-dss-checklist.js +214 -0
  16. package/server/lib/compliance/pci-dss-checklist.test.js +95 -0
  17. package/server/lib/compliance/trust-centre.js +187 -0
  18. package/server/lib/compliance/trust-centre.test.js +93 -0
  19. package/server/lib/dashboard/api-server.js +155 -0
  20. package/server/lib/dashboard/api-server.test.js +155 -0
  21. package/server/lib/dashboard/health-api.js +199 -0
  22. package/server/lib/dashboard/health-api.test.js +122 -0
  23. package/server/lib/dashboard/notes-api.js +234 -0
  24. package/server/lib/dashboard/notes-api.test.js +134 -0
  25. package/server/lib/dashboard/router-api.js +176 -0
  26. package/server/lib/dashboard/router-api.test.js +132 -0
  27. package/server/lib/dashboard/tasks-api.js +289 -0
  28. package/server/lib/dashboard/tasks-api.test.js +161 -0
  29. package/server/lib/dashboard/tlc-introspection.js +197 -0
  30. package/server/lib/dashboard/tlc-introspection.test.js +138 -0
  31. package/server/lib/dashboard/version-api.js +222 -0
  32. package/server/lib/dashboard/version-api.test.js +112 -0
  33. package/server/lib/dashboard/websocket-server.js +104 -0
  34. package/server/lib/dashboard/websocket-server.test.js +118 -0
  35. package/server/lib/deploy/branch-classifier.js +163 -0
  36. package/server/lib/deploy/branch-classifier.test.js +164 -0
  37. package/server/lib/deploy/deployment-approval.js +299 -0
  38. package/server/lib/deploy/deployment-approval.test.js +296 -0
  39. package/server/lib/deploy/deployment-audit.js +374 -0
  40. package/server/lib/deploy/deployment-audit.test.js +307 -0
  41. package/server/lib/deploy/deployment-executor.js +335 -0
  42. package/server/lib/deploy/deployment-executor.test.js +329 -0
  43. package/server/lib/deploy/deployment-rules.js +163 -0
  44. package/server/lib/deploy/deployment-rules.test.js +188 -0
  45. package/server/lib/deploy/rollback-manager.js +379 -0
  46. package/server/lib/deploy/rollback-manager.test.js +321 -0
  47. package/server/lib/deploy/security-gates.js +236 -0
  48. package/server/lib/deploy/security-gates.test.js +222 -0
  49. package/server/lib/k8s/gitops-config.js +188 -0
  50. package/server/lib/k8s/gitops-config.test.js +59 -0
  51. package/server/lib/k8s/helm-generator.js +196 -0
  52. package/server/lib/k8s/helm-generator.test.js +59 -0
  53. package/server/lib/k8s/kustomize-generator.js +176 -0
  54. package/server/lib/k8s/kustomize-generator.test.js +58 -0
  55. package/server/lib/k8s/network-policy.js +114 -0
  56. package/server/lib/k8s/network-policy.test.js +53 -0
  57. package/server/lib/k8s/pod-security.js +114 -0
  58. package/server/lib/k8s/pod-security.test.js +55 -0
  59. package/server/lib/k8s/rbac-generator.js +132 -0
  60. package/server/lib/k8s/rbac-generator.test.js +57 -0
  61. package/server/lib/k8s/resource-manager.js +172 -0
  62. package/server/lib/k8s/resource-manager.test.js +60 -0
  63. package/server/lib/k8s/secrets-encryption.js +168 -0
  64. package/server/lib/k8s/secrets-encryption.test.js +49 -0
  65. package/server/lib/monitoring/alert-manager.js +238 -0
  66. package/server/lib/monitoring/alert-manager.test.js +106 -0
  67. package/server/lib/monitoring/health-check.js +226 -0
  68. package/server/lib/monitoring/health-check.test.js +176 -0
  69. package/server/lib/monitoring/incident-manager.js +230 -0
  70. package/server/lib/monitoring/incident-manager.test.js +98 -0
  71. package/server/lib/monitoring/log-aggregator.js +147 -0
  72. package/server/lib/monitoring/log-aggregator.test.js +89 -0
  73. package/server/lib/monitoring/metrics-collector.js +337 -0
  74. package/server/lib/monitoring/metrics-collector.test.js +172 -0
  75. package/server/lib/monitoring/status-page.js +214 -0
  76. package/server/lib/monitoring/status-page.test.js +105 -0
  77. package/server/lib/monitoring/uptime-monitor.js +194 -0
  78. package/server/lib/monitoring/uptime-monitor.test.js +109 -0
  79. package/server/lib/network/fail2ban-config.js +294 -0
  80. package/server/lib/network/fail2ban-config.test.js +275 -0
  81. package/server/lib/network/firewall-manager.js +252 -0
  82. package/server/lib/network/firewall-manager.test.js +254 -0
  83. package/server/lib/network/geoip-filter.js +282 -0
  84. package/server/lib/network/geoip-filter.test.js +264 -0
  85. package/server/lib/network/rate-limiter.js +229 -0
  86. package/server/lib/network/rate-limiter.test.js +293 -0
  87. package/server/lib/network/request-validator.js +351 -0
  88. package/server/lib/network/request-validator.test.js +345 -0
  89. package/server/lib/network/security-headers.js +251 -0
  90. package/server/lib/network/security-headers.test.js +283 -0
  91. package/server/lib/network/tls-config.js +210 -0
  92. package/server/lib/network/tls-config.test.js +248 -0
  93. package/server/lib/security/auth-security.js +369 -0
  94. package/server/lib/security/auth-security.test.js +448 -0
  95. package/server/lib/security/cis-benchmark.js +152 -0
  96. package/server/lib/security/cis-benchmark.test.js +137 -0
  97. package/server/lib/security/compose-templates.js +312 -0
  98. package/server/lib/security/compose-templates.test.js +229 -0
  99. package/server/lib/security/container-runtime.js +456 -0
  100. package/server/lib/security/container-runtime.test.js +503 -0
  101. package/server/lib/security/cors-validator.js +278 -0
  102. package/server/lib/security/cors-validator.test.js +310 -0
  103. package/server/lib/security/crypto-utils.js +253 -0
  104. package/server/lib/security/crypto-utils.test.js +409 -0
  105. package/server/lib/security/dockerfile-linter.js +459 -0
  106. package/server/lib/security/dockerfile-linter.test.js +483 -0
  107. package/server/lib/security/dockerfile-templates.js +278 -0
  108. package/server/lib/security/dockerfile-templates.test.js +164 -0
  109. package/server/lib/security/error-sanitizer.js +426 -0
  110. package/server/lib/security/error-sanitizer.test.js +331 -0
  111. package/server/lib/security/headers-generator.js +368 -0
  112. package/server/lib/security/headers-generator.test.js +398 -0
  113. package/server/lib/security/image-scanner.js +83 -0
  114. package/server/lib/security/image-scanner.test.js +106 -0
  115. package/server/lib/security/input-validator.js +352 -0
  116. package/server/lib/security/input-validator.test.js +330 -0
  117. package/server/lib/security/network-policy.js +174 -0
  118. package/server/lib/security/network-policy.test.js +164 -0
  119. package/server/lib/security/output-encoder.js +237 -0
  120. package/server/lib/security/output-encoder.test.js +276 -0
  121. package/server/lib/security/path-validator.js +359 -0
  122. package/server/lib/security/path-validator.test.js +293 -0
  123. package/server/lib/security/query-builder.js +421 -0
  124. package/server/lib/security/query-builder.test.js +318 -0
  125. package/server/lib/security/secret-detector.js +290 -0
  126. package/server/lib/security/secret-detector.test.js +354 -0
  127. package/server/lib/security/secrets-validator.js +137 -0
  128. package/server/lib/security/secrets-validator.test.js +120 -0
  129. package/server/lib/security-testing/dast-runner.js +154 -0
  130. package/server/lib/security-testing/dast-runner.test.js +62 -0
  131. package/server/lib/security-testing/dependency-scanner.js +172 -0
  132. package/server/lib/security-testing/dependency-scanner.test.js +64 -0
  133. package/server/lib/security-testing/pentest-runner.js +230 -0
  134. package/server/lib/security-testing/pentest-runner.test.js +60 -0
  135. package/server/lib/security-testing/sast-runner.js +136 -0
  136. package/server/lib/security-testing/sast-runner.test.js +62 -0
  137. package/server/lib/security-testing/secret-scanner.js +153 -0
  138. package/server/lib/security-testing/secret-scanner.test.js +66 -0
  139. package/server/lib/security-testing/security-gate.js +216 -0
  140. package/server/lib/security-testing/security-gate.test.js +115 -0
  141. package/server/lib/security-testing/security-reporter.js +303 -0
  142. package/server/lib/security-testing/security-reporter.test.js +114 -0
  143. package/server/lib/standards/audit-checker.js +546 -0
  144. package/server/lib/standards/audit-checker.test.js +415 -0
  145. package/server/lib/standards/cleanup-executor.js +452 -0
  146. package/server/lib/standards/cleanup-executor.test.js +293 -0
  147. package/server/lib/standards/refactor-stepper.js +425 -0
  148. package/server/lib/standards/refactor-stepper.test.js +298 -0
  149. package/server/lib/standards/standards-injector.js +167 -0
  150. package/server/lib/standards/standards-injector.test.js +232 -0
  151. package/server/lib/user-management.test.js +284 -0
  152. package/server/lib/vps/backup-manager.js +157 -0
  153. package/server/lib/vps/backup-manager.test.js +59 -0
  154. package/server/lib/vps/caddy-config.js +159 -0
  155. package/server/lib/vps/caddy-config.test.js +48 -0
  156. package/server/lib/vps/compose-orchestrator.js +219 -0
  157. package/server/lib/vps/compose-orchestrator.test.js +50 -0
  158. package/server/lib/vps/database-config.js +208 -0
  159. package/server/lib/vps/database-config.test.js +47 -0
  160. package/server/lib/vps/deploy-script.js +211 -0
  161. package/server/lib/vps/deploy-script.test.js +53 -0
  162. package/server/lib/vps/secrets-manager.js +148 -0
  163. package/server/lib/vps/secrets-manager.test.js +58 -0
  164. package/server/lib/vps/server-hardening.js +174 -0
  165. package/server/lib/vps/server-hardening.test.js +70 -0
  166. package/server/package-lock.json +19 -0
  167. package/server/package.json +1 -0
  168. package/server/templates/CLAUDE.md +37 -0
  169. package/server/templates/CODING-STANDARDS.md +408 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Pod Security Standards (Baseline, Restricted)
3
+ */
4
+
5
+ /**
6
+ * Generates a security context based on the specified level
7
+ * @param {Object} options - Configuration options
8
+ * @param {string} options.level - Security level ('restricted', 'baseline', 'privileged')
9
+ * @returns {Object} Security context configuration
10
+ */
11
+ export function generateSecurityContext({ level = 'restricted' } = {}) {
12
+ const context = {
13
+ capabilities: {
14
+ drop: ['ALL']
15
+ }
16
+ };
17
+
18
+ if (level === 'restricted') {
19
+ context.runAsNonRoot = true;
20
+ context.readOnlyRootFilesystem = true;
21
+ context.allowPrivilegeEscalation = false;
22
+ } else if (level === 'baseline') {
23
+ context.runAsNonRoot = false;
24
+ context.readOnlyRootFilesystem = false;
25
+ }
26
+
27
+ return context;
28
+ }
29
+
30
+ /**
31
+ * Enforces Pod Security Standards at namespace level
32
+ * @param {Object} options - Configuration options
33
+ * @param {string} options.namespace - Target namespace
34
+ * @param {string} options.level - Enforcement level (default: 'restricted')
35
+ * @returns {Object} Namespace labels for Pod Security Standards
36
+ */
37
+ export function enforceRestricted({ namespace, level = 'restricted' } = {}) {
38
+ return {
39
+ 'pod-security.kubernetes.io/enforce': level,
40
+ 'pod-security.kubernetes.io/enforce-version': 'latest',
41
+ 'pod-security.kubernetes.io/audit': level,
42
+ 'pod-security.kubernetes.io/warn': level
43
+ };
44
+ }
45
+
46
+ /**
47
+ * Blocks privileged container settings
48
+ * @param {Object} options - Configuration options
49
+ * @param {boolean} options.includeHostSettings - Whether to include host namespace settings
50
+ * @returns {Object} Security settings that block privileged access
51
+ */
52
+ export function blockPrivileged({ includeHostSettings = false } = {}) {
53
+ const settings = {
54
+ privileged: false,
55
+ allowPrivilegeEscalation: false
56
+ };
57
+
58
+ if (includeHostSettings) {
59
+ settings.hostNetwork = false;
60
+ settings.hostPID = false;
61
+ settings.hostIPC = false;
62
+ }
63
+
64
+ return settings;
65
+ }
66
+
67
+ /**
68
+ * Sets seccomp profile configuration
69
+ * @param {Object} options - Configuration options
70
+ * @param {string} options.type - Seccomp profile type ('RuntimeDefault', 'Localhost', 'Unconfined')
71
+ * @param {string} options.localhostProfile - Path to localhost profile (if type is 'Localhost')
72
+ * @returns {Object} Seccomp profile configuration
73
+ */
74
+ export function setSeccomp({ type = 'RuntimeDefault', localhostProfile } = {}) {
75
+ const profile = {
76
+ type
77
+ };
78
+
79
+ if (type === 'Localhost' && localhostProfile) {
80
+ profile.localhostProfile = localhostProfile;
81
+ }
82
+
83
+ return profile;
84
+ }
85
+
86
+ /**
87
+ * Creates a pod security manager
88
+ * @returns {Object} Pod security manager with generate and validate methods
89
+ */
90
+ export function createPodSecurity() {
91
+ return {
92
+ generate: (options) => generateSecurityContext(options),
93
+ validate: (spec) => {
94
+ const issues = [];
95
+
96
+ if (spec.privileged === true) {
97
+ issues.push('privileged-container');
98
+ }
99
+
100
+ if (spec.runAsNonRoot !== true) {
101
+ issues.push('runs-as-root');
102
+ }
103
+
104
+ if (!spec.capabilities?.drop?.includes('ALL')) {
105
+ issues.push('capabilities-not-dropped');
106
+ }
107
+
108
+ return {
109
+ valid: issues.length === 0,
110
+ issues
111
+ };
112
+ }
113
+ };
114
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Pod Security Tests
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { generateSecurityContext, enforceRestricted, blockPrivileged, setSeccomp, createPodSecurity } from './pod-security.js';
6
+
7
+ describe('pod-security', () => {
8
+ describe('generateSecurityContext', () => {
9
+ it('generates restricted security context', () => {
10
+ const ctx = generateSecurityContext({ level: 'restricted' });
11
+ expect(ctx.runAsNonRoot).toBe(true);
12
+ expect(ctx.readOnlyRootFilesystem).toBe(true);
13
+ });
14
+
15
+ it('drops all capabilities', () => {
16
+ const ctx = generateSecurityContext({ level: 'restricted' });
17
+ expect(ctx.capabilities.drop).toContain('ALL');
18
+ });
19
+ });
20
+
21
+ describe('enforceRestricted', () => {
22
+ it('enforces Pod Security Standards', () => {
23
+ const labels = enforceRestricted({ namespace: 'default' });
24
+ expect(labels['pod-security.kubernetes.io/enforce']).toBe('restricted');
25
+ });
26
+ });
27
+
28
+ describe('blockPrivileged', () => {
29
+ it('blocks privileged containers', () => {
30
+ const ctx = blockPrivileged({});
31
+ expect(ctx.privileged).toBe(false);
32
+ });
33
+
34
+ it('blocks host namespaces', () => {
35
+ const spec = blockPrivileged({ includeHostSettings: true });
36
+ expect(spec.hostNetwork).toBe(false);
37
+ expect(spec.hostPID).toBe(false);
38
+ });
39
+ });
40
+
41
+ describe('setSeccomp', () => {
42
+ it('sets RuntimeDefault seccomp', () => {
43
+ const profile = setSeccomp({ type: 'RuntimeDefault' });
44
+ expect(profile.type).toBe('RuntimeDefault');
45
+ });
46
+ });
47
+
48
+ describe('createPodSecurity', () => {
49
+ it('creates security manager', () => {
50
+ const manager = createPodSecurity();
51
+ expect(manager.generate).toBeDefined();
52
+ expect(manager.validate).toBeDefined();
53
+ });
54
+ });
55
+ });
@@ -0,0 +1,132 @@
1
+ /**
2
+ * RBAC Role and Binding Generator
3
+ */
4
+
5
+ /**
6
+ * Creates a minimal service account
7
+ * @param {Object} options - Configuration options
8
+ * @param {string} options.name - Service account name
9
+ * @param {string} options.namespace - Target namespace (default: 'default')
10
+ * @returns {Object} ServiceAccount resource
11
+ */
12
+ export function createServiceAccount({ name, namespace = 'default' } = {}) {
13
+ return {
14
+ apiVersion: 'v1',
15
+ kind: 'ServiceAccount',
16
+ metadata: {
17
+ name,
18
+ namespace
19
+ },
20
+ automountServiceAccountToken: false
21
+ };
22
+ }
23
+
24
+ /**
25
+ * Creates a role with least privilege
26
+ * @param {Object} options - Configuration options
27
+ * @param {string} options.name - Role name
28
+ * @param {string} options.namespace - Target namespace (default: 'default')
29
+ * @param {Array} options.rules - Array of policy rules
30
+ * @returns {Object} Role resource with optional warnings
31
+ */
32
+ export function createRole({ name, namespace = 'default', rules = [] } = {}) {
33
+ const role = {
34
+ apiVersion: 'rbac.authorization.k8s.io/v1',
35
+ kind: 'Role',
36
+ metadata: {
37
+ name,
38
+ namespace
39
+ },
40
+ rules
41
+ };
42
+
43
+ // Check for excessive permissions (wildcard usage)
44
+ const hasWildcardPermissions = rules.some(rule =>
45
+ rule.apiGroups?.includes('*') ||
46
+ rule.resources?.includes('*') ||
47
+ rule.verbs?.includes('*')
48
+ );
49
+
50
+ if (hasWildcardPermissions) {
51
+ role.warnings = ['excessive-permissions'];
52
+ }
53
+
54
+ return role;
55
+ }
56
+
57
+ /**
58
+ * Creates a role binding
59
+ * @param {Object} options - Configuration options
60
+ * @param {string} options.name - Binding name
61
+ * @param {string} options.roleName - Name of the role to bind
62
+ * @param {string} options.serviceAccount - Service account name (optional)
63
+ * @param {string} options.namespace - Target namespace (default: 'default')
64
+ * @returns {Object} RoleBinding resource
65
+ */
66
+ export function createRoleBinding({ name, roleName, serviceAccount, namespace = 'default' } = {}) {
67
+ const binding = {
68
+ apiVersion: 'rbac.authorization.k8s.io/v1',
69
+ kind: 'RoleBinding',
70
+ metadata: {
71
+ name,
72
+ namespace
73
+ },
74
+ roleRef: {
75
+ apiGroup: 'rbac.authorization.k8s.io',
76
+ kind: 'Role',
77
+ name: roleName
78
+ },
79
+ subjects: []
80
+ };
81
+
82
+ if (serviceAccount) {
83
+ binding.subjects.push({
84
+ kind: 'ServiceAccount',
85
+ name: serviceAccount,
86
+ namespace
87
+ });
88
+ }
89
+
90
+ return binding;
91
+ }
92
+
93
+ /**
94
+ * Validates RBAC resource syntax
95
+ * @param {Object} resource - RBAC resource to validate
96
+ * @returns {Object} Validation result with valid boolean and issues array
97
+ */
98
+ export function validateRbac(resource) {
99
+ const issues = [];
100
+
101
+ if (!resource.kind) {
102
+ issues.push('missing-kind');
103
+ }
104
+
105
+ if (!resource.metadata?.name) {
106
+ issues.push('missing-name');
107
+ }
108
+
109
+ if (resource.kind === 'Role' || resource.kind === 'ClusterRole') {
110
+ if (!Array.isArray(resource.rules)) {
111
+ issues.push('missing-rules');
112
+ }
113
+ }
114
+
115
+ return {
116
+ valid: issues.length === 0,
117
+ issues
118
+ };
119
+ }
120
+
121
+ /**
122
+ * Creates an RBAC generator
123
+ * @returns {Object} Generator with serviceAccount, role, and binding methods
124
+ */
125
+ export function createRbacGenerator() {
126
+ return {
127
+ serviceAccount: (options) => createServiceAccount(options),
128
+ role: (options) => createRole(options),
129
+ binding: (options) => createRoleBinding(options),
130
+ validate: (resource) => validateRbac(resource)
131
+ };
132
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * RBAC Generator Tests
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { createServiceAccount, createRole, createRoleBinding, validateRbac, createRbacGenerator } from './rbac-generator.js';
6
+
7
+ describe('rbac-generator', () => {
8
+ describe('createServiceAccount', () => {
9
+ it('creates minimal service account', () => {
10
+ const sa = createServiceAccount({ name: 'app-sa', namespace: 'default' });
11
+ expect(sa.kind).toBe('ServiceAccount');
12
+ expect(sa.metadata.name).toBe('app-sa');
13
+ });
14
+ });
15
+
16
+ describe('createRole', () => {
17
+ it('generates role with least privilege', () => {
18
+ const role = createRole({ name: 'app-role', rules: [{ apiGroups: [''], resources: ['pods'], verbs: ['get', 'list'] }] });
19
+ expect(role.kind).toBe('Role');
20
+ expect(role.rules[0].verbs).not.toContain('*');
21
+ });
22
+
23
+ it('blocks cluster-admin for apps', () => {
24
+ const role = createRole({ name: 'app-role', rules: [{ apiGroups: ['*'], resources: ['*'], verbs: ['*'] }] });
25
+ expect(role.warnings).toContain('excessive-permissions');
26
+ });
27
+ });
28
+
29
+ describe('createRoleBinding', () => {
30
+ it('creates role binding', () => {
31
+ const binding = createRoleBinding({ name: 'app-binding', roleName: 'app-role', serviceAccount: 'app-sa' });
32
+ expect(binding.kind).toBe('RoleBinding');
33
+ expect(binding.roleRef.name).toBe('app-role');
34
+ });
35
+
36
+ it('supports namespace-scoped roles', () => {
37
+ const binding = createRoleBinding({ name: 'app-binding', roleName: 'app-role', namespace: 'production' });
38
+ expect(binding.metadata.namespace).toBe('production');
39
+ });
40
+ });
41
+
42
+ describe('validateRbac', () => {
43
+ it('validates RBAC syntax', () => {
44
+ const result = validateRbac({ kind: 'Role', metadata: { name: 'test' }, rules: [] });
45
+ expect(result.valid).toBe(true);
46
+ });
47
+ });
48
+
49
+ describe('createRbacGenerator', () => {
50
+ it('creates generator', () => {
51
+ const generator = createRbacGenerator();
52
+ expect(generator.serviceAccount).toBeDefined();
53
+ expect(generator.role).toBeDefined();
54
+ expect(generator.binding).toBeDefined();
55
+ });
56
+ });
57
+ });
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Resource Quotas and Limits Manager
3
+ */
4
+
5
+ /**
6
+ * Sets resource requests
7
+ * @param {Object} options - Configuration options
8
+ * @param {string} options.cpu - CPU request (e.g., '100m')
9
+ * @param {string} options.memory - Memory request (e.g., '128Mi')
10
+ * @returns {Object} Resource configuration with requests
11
+ */
12
+ export function setResourceRequests({ cpu, memory } = {}) {
13
+ return {
14
+ requests: {
15
+ ...(cpu && { cpu }),
16
+ ...(memory && { memory })
17
+ }
18
+ };
19
+ }
20
+
21
+ /**
22
+ * Sets resource limits
23
+ * @param {Object} options - Configuration options
24
+ * @param {string} options.cpu - CPU limit (e.g., '500m')
25
+ * @param {string} options.memory - Memory limit (e.g., '512Mi')
26
+ * @returns {Object} Resource configuration with limits
27
+ */
28
+ export function setResourceLimits({ cpu, memory } = {}) {
29
+ return {
30
+ limits: {
31
+ ...(cpu && { cpu }),
32
+ ...(memory && { memory })
33
+ }
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Generates a Horizontal Pod Autoscaler configuration
39
+ * @param {Object} options - Configuration options
40
+ * @param {string} options.name - Target deployment name
41
+ * @param {number} options.minReplicas - Minimum replicas
42
+ * @param {number} options.maxReplicas - Maximum replicas
43
+ * @param {number} options.targetCpu - Target CPU utilization percentage
44
+ * @param {string} options.namespace - Target namespace (default: 'default')
45
+ * @returns {Object} HorizontalPodAutoscaler resource
46
+ */
47
+ export function generateHpa({ name, minReplicas = 1, maxReplicas = 10, targetCpu = 80, namespace = 'default' } = {}) {
48
+ return {
49
+ apiVersion: 'autoscaling/v2',
50
+ kind: 'HorizontalPodAutoscaler',
51
+ metadata: {
52
+ name: `${name}-hpa`,
53
+ namespace
54
+ },
55
+ spec: {
56
+ scaleTargetRef: {
57
+ apiVersion: 'apps/v1',
58
+ kind: 'Deployment',
59
+ name
60
+ },
61
+ minReplicas,
62
+ maxReplicas,
63
+ metrics: [{
64
+ type: 'Resource',
65
+ resource: {
66
+ name: 'cpu',
67
+ target: {
68
+ type: 'Utilization',
69
+ averageUtilization: targetCpu
70
+ }
71
+ }
72
+ }]
73
+ }
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Generates a Pod Disruption Budget configuration
79
+ * @param {Object} options - Configuration options
80
+ * @param {string} options.name - Target deployment name
81
+ * @param {number} options.minAvailable - Minimum available pods (optional)
82
+ * @param {number} options.maxUnavailable - Maximum unavailable pods (optional)
83
+ * @param {Object} options.selector - Pod selector (default: matches app label)
84
+ * @param {string} options.namespace - Target namespace (default: 'default')
85
+ * @returns {Object} PodDisruptionBudget resource
86
+ */
87
+ export function generatePdb({ name, minAvailable, maxUnavailable, selector, namespace = 'default' } = {}) {
88
+ const pdb = {
89
+ apiVersion: 'policy/v1',
90
+ kind: 'PodDisruptionBudget',
91
+ metadata: {
92
+ name: `${name}-pdb`,
93
+ namespace
94
+ },
95
+ spec: {
96
+ selector: selector || {
97
+ matchLabels: {
98
+ app: name
99
+ }
100
+ }
101
+ }
102
+ };
103
+
104
+ if (minAvailable !== undefined) {
105
+ pdb.spec.minAvailable = minAvailable;
106
+ } else if (maxUnavailable !== undefined) {
107
+ pdb.spec.maxUnavailable = maxUnavailable;
108
+ }
109
+
110
+ return pdb;
111
+ }
112
+
113
+ /**
114
+ * Sets a priority class configuration
115
+ * @param {Object} options - Configuration options
116
+ * @param {string} options.name - Priority class name
117
+ * @param {number} options.value - Priority value
118
+ * @param {boolean} options.globalDefault - Whether this is the global default
119
+ * @param {string} options.description - Description of the priority class
120
+ * @returns {Object} PriorityClass resource
121
+ */
122
+ export function setPriorityClass({ name, value, globalDefault = false, description } = {}) {
123
+ return {
124
+ apiVersion: 'scheduling.k8s.io/v1',
125
+ kind: 'PriorityClass',
126
+ metadata: {
127
+ name
128
+ },
129
+ value,
130
+ globalDefault,
131
+ description: description || `Priority class: ${name}`
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Validates resource syntax
137
+ * @param {Object} resources - Resource configuration to validate
138
+ * @returns {Object} Validation result with valid boolean and issues array
139
+ */
140
+ function validateResources(resources) {
141
+ const issues = [];
142
+ const cpuPattern = /^\d+m?$/;
143
+ const memoryPattern = /^\d+(Ki|Mi|Gi|Ti|Pi|Ei)?$/;
144
+
145
+ if (resources.cpu && !cpuPattern.test(resources.cpu)) {
146
+ issues.push('invalid-cpu-format');
147
+ }
148
+
149
+ if (resources.memory && !memoryPattern.test(resources.memory)) {
150
+ issues.push('invalid-memory-format');
151
+ }
152
+
153
+ return {
154
+ valid: issues.length === 0,
155
+ issues
156
+ };
157
+ }
158
+
159
+ /**
160
+ * Creates a resource manager
161
+ * @returns {Object} Manager with setRequests, setLimits, generateHpa, and validate methods
162
+ */
163
+ export function createResourceManager() {
164
+ return {
165
+ setRequests: (options) => setResourceRequests(options),
166
+ setLimits: (options) => setResourceLimits(options),
167
+ generateHpa: (options) => generateHpa(options),
168
+ generatePdb: (options) => generatePdb(options),
169
+ setPriorityClass: (options) => setPriorityClass(options),
170
+ validate: (resources) => validateResources(resources)
171
+ };
172
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Resource Manager Tests
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { setResourceRequests, setResourceLimits, generateHpa, generatePdb, setPriorityClass, createResourceManager } from './resource-manager.js';
6
+
7
+ describe('resource-manager', () => {
8
+ describe('setResourceRequests', () => {
9
+ it('sets resource requests', () => {
10
+ const resources = setResourceRequests({ cpu: '100m', memory: '128Mi' });
11
+ expect(resources.requests.cpu).toBe('100m');
12
+ expect(resources.requests.memory).toBe('128Mi');
13
+ });
14
+ });
15
+
16
+ describe('setResourceLimits', () => {
17
+ it('sets resource limits', () => {
18
+ const resources = setResourceLimits({ cpu: '500m', memory: '512Mi' });
19
+ expect(resources.limits.cpu).toBe('500m');
20
+ });
21
+ });
22
+
23
+ describe('generateHpa', () => {
24
+ it('generates HPA config', () => {
25
+ const hpa = generateHpa({ name: 'app', minReplicas: 2, maxReplicas: 10, targetCpu: 80 });
26
+ expect(hpa.kind).toBe('HorizontalPodAutoscaler');
27
+ expect(hpa.spec.minReplicas).toBe(2);
28
+ });
29
+ });
30
+
31
+ describe('generatePdb', () => {
32
+ it('generates PDB config', () => {
33
+ const pdb = generatePdb({ name: 'app', minAvailable: 1 });
34
+ expect(pdb.kind).toBe('PodDisruptionBudget');
35
+ expect(pdb.spec.minAvailable).toBe(1);
36
+ });
37
+ });
38
+
39
+ describe('setPriorityClass', () => {
40
+ it('configures priority classes', () => {
41
+ const pc = setPriorityClass({ name: 'high-priority', value: 1000000 });
42
+ expect(pc.kind).toBe('PriorityClass');
43
+ });
44
+ });
45
+
46
+ describe('createResourceManager', () => {
47
+ it('creates manager', () => {
48
+ const manager = createResourceManager();
49
+ expect(manager.setRequests).toBeDefined();
50
+ expect(manager.setLimits).toBeDefined();
51
+ expect(manager.generateHpa).toBeDefined();
52
+ });
53
+
54
+ it('validates resource syntax', () => {
55
+ const manager = createResourceManager();
56
+ const result = manager.validate({ cpu: '100m', memory: '128Mi' });
57
+ expect(result.valid).toBe(true);
58
+ });
59
+ });
60
+ });