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.
- package/package.json +1 -1
- package/server/index.js +229 -14
- package/server/lib/compliance/control-mapper.js +401 -0
- package/server/lib/compliance/control-mapper.test.js +117 -0
- package/server/lib/compliance/evidence-linker.js +296 -0
- package/server/lib/compliance/evidence-linker.test.js +121 -0
- package/server/lib/compliance/gdpr-checklist.js +416 -0
- package/server/lib/compliance/gdpr-checklist.test.js +131 -0
- package/server/lib/compliance/hipaa-checklist.js +277 -0
- package/server/lib/compliance/hipaa-checklist.test.js +101 -0
- package/server/lib/compliance/iso27001-checklist.js +287 -0
- package/server/lib/compliance/iso27001-checklist.test.js +99 -0
- package/server/lib/compliance/multi-framework-reporter.js +284 -0
- package/server/lib/compliance/multi-framework-reporter.test.js +127 -0
- package/server/lib/compliance/pci-dss-checklist.js +214 -0
- package/server/lib/compliance/pci-dss-checklist.test.js +95 -0
- package/server/lib/compliance/trust-centre.js +187 -0
- package/server/lib/compliance/trust-centre.test.js +93 -0
- package/server/lib/dashboard/api-server.js +155 -0
- package/server/lib/dashboard/api-server.test.js +155 -0
- package/server/lib/dashboard/health-api.js +199 -0
- package/server/lib/dashboard/health-api.test.js +122 -0
- package/server/lib/dashboard/notes-api.js +234 -0
- package/server/lib/dashboard/notes-api.test.js +134 -0
- package/server/lib/dashboard/router-api.js +176 -0
- package/server/lib/dashboard/router-api.test.js +132 -0
- package/server/lib/dashboard/tasks-api.js +289 -0
- package/server/lib/dashboard/tasks-api.test.js +161 -0
- package/server/lib/dashboard/tlc-introspection.js +197 -0
- package/server/lib/dashboard/tlc-introspection.test.js +138 -0
- package/server/lib/dashboard/version-api.js +222 -0
- package/server/lib/dashboard/version-api.test.js +112 -0
- package/server/lib/dashboard/websocket-server.js +104 -0
- package/server/lib/dashboard/websocket-server.test.js +118 -0
- package/server/lib/deploy/branch-classifier.js +163 -0
- package/server/lib/deploy/branch-classifier.test.js +164 -0
- package/server/lib/deploy/deployment-approval.js +299 -0
- package/server/lib/deploy/deployment-approval.test.js +296 -0
- package/server/lib/deploy/deployment-audit.js +374 -0
- package/server/lib/deploy/deployment-audit.test.js +307 -0
- package/server/lib/deploy/deployment-executor.js +335 -0
- package/server/lib/deploy/deployment-executor.test.js +329 -0
- package/server/lib/deploy/deployment-rules.js +163 -0
- package/server/lib/deploy/deployment-rules.test.js +188 -0
- package/server/lib/deploy/rollback-manager.js +379 -0
- package/server/lib/deploy/rollback-manager.test.js +321 -0
- package/server/lib/deploy/security-gates.js +236 -0
- package/server/lib/deploy/security-gates.test.js +222 -0
- package/server/lib/k8s/gitops-config.js +188 -0
- package/server/lib/k8s/gitops-config.test.js +59 -0
- package/server/lib/k8s/helm-generator.js +196 -0
- package/server/lib/k8s/helm-generator.test.js +59 -0
- package/server/lib/k8s/kustomize-generator.js +176 -0
- package/server/lib/k8s/kustomize-generator.test.js +58 -0
- package/server/lib/k8s/network-policy.js +114 -0
- package/server/lib/k8s/network-policy.test.js +53 -0
- package/server/lib/k8s/pod-security.js +114 -0
- package/server/lib/k8s/pod-security.test.js +55 -0
- package/server/lib/k8s/rbac-generator.js +132 -0
- package/server/lib/k8s/rbac-generator.test.js +57 -0
- package/server/lib/k8s/resource-manager.js +172 -0
- package/server/lib/k8s/resource-manager.test.js +60 -0
- package/server/lib/k8s/secrets-encryption.js +168 -0
- package/server/lib/k8s/secrets-encryption.test.js +49 -0
- package/server/lib/monitoring/alert-manager.js +238 -0
- package/server/lib/monitoring/alert-manager.test.js +106 -0
- package/server/lib/monitoring/health-check.js +226 -0
- package/server/lib/monitoring/health-check.test.js +176 -0
- package/server/lib/monitoring/incident-manager.js +230 -0
- package/server/lib/monitoring/incident-manager.test.js +98 -0
- package/server/lib/monitoring/log-aggregator.js +147 -0
- package/server/lib/monitoring/log-aggregator.test.js +89 -0
- package/server/lib/monitoring/metrics-collector.js +337 -0
- package/server/lib/monitoring/metrics-collector.test.js +172 -0
- package/server/lib/monitoring/status-page.js +214 -0
- package/server/lib/monitoring/status-page.test.js +105 -0
- package/server/lib/monitoring/uptime-monitor.js +194 -0
- package/server/lib/monitoring/uptime-monitor.test.js +109 -0
- package/server/lib/network/fail2ban-config.js +294 -0
- package/server/lib/network/fail2ban-config.test.js +275 -0
- package/server/lib/network/firewall-manager.js +252 -0
- package/server/lib/network/firewall-manager.test.js +254 -0
- package/server/lib/network/geoip-filter.js +282 -0
- package/server/lib/network/geoip-filter.test.js +264 -0
- package/server/lib/network/rate-limiter.js +229 -0
- package/server/lib/network/rate-limiter.test.js +293 -0
- package/server/lib/network/request-validator.js +351 -0
- package/server/lib/network/request-validator.test.js +345 -0
- package/server/lib/network/security-headers.js +251 -0
- package/server/lib/network/security-headers.test.js +283 -0
- package/server/lib/network/tls-config.js +210 -0
- package/server/lib/network/tls-config.test.js +248 -0
- package/server/lib/security/auth-security.js +369 -0
- package/server/lib/security/auth-security.test.js +448 -0
- package/server/lib/security/cis-benchmark.js +152 -0
- package/server/lib/security/cis-benchmark.test.js +137 -0
- package/server/lib/security/compose-templates.js +312 -0
- package/server/lib/security/compose-templates.test.js +229 -0
- package/server/lib/security/container-runtime.js +456 -0
- package/server/lib/security/container-runtime.test.js +503 -0
- package/server/lib/security/cors-validator.js +278 -0
- package/server/lib/security/cors-validator.test.js +310 -0
- package/server/lib/security/crypto-utils.js +253 -0
- package/server/lib/security/crypto-utils.test.js +409 -0
- package/server/lib/security/dockerfile-linter.js +459 -0
- package/server/lib/security/dockerfile-linter.test.js +483 -0
- package/server/lib/security/dockerfile-templates.js +278 -0
- package/server/lib/security/dockerfile-templates.test.js +164 -0
- package/server/lib/security/error-sanitizer.js +426 -0
- package/server/lib/security/error-sanitizer.test.js +331 -0
- package/server/lib/security/headers-generator.js +368 -0
- package/server/lib/security/headers-generator.test.js +398 -0
- package/server/lib/security/image-scanner.js +83 -0
- package/server/lib/security/image-scanner.test.js +106 -0
- package/server/lib/security/input-validator.js +352 -0
- package/server/lib/security/input-validator.test.js +330 -0
- package/server/lib/security/network-policy.js +174 -0
- package/server/lib/security/network-policy.test.js +164 -0
- package/server/lib/security/output-encoder.js +237 -0
- package/server/lib/security/output-encoder.test.js +276 -0
- package/server/lib/security/path-validator.js +359 -0
- package/server/lib/security/path-validator.test.js +293 -0
- package/server/lib/security/query-builder.js +421 -0
- package/server/lib/security/query-builder.test.js +318 -0
- package/server/lib/security/secret-detector.js +290 -0
- package/server/lib/security/secret-detector.test.js +354 -0
- package/server/lib/security/secrets-validator.js +137 -0
- package/server/lib/security/secrets-validator.test.js +120 -0
- package/server/lib/security-testing/dast-runner.js +154 -0
- package/server/lib/security-testing/dast-runner.test.js +62 -0
- package/server/lib/security-testing/dependency-scanner.js +172 -0
- package/server/lib/security-testing/dependency-scanner.test.js +64 -0
- package/server/lib/security-testing/pentest-runner.js +230 -0
- package/server/lib/security-testing/pentest-runner.test.js +60 -0
- package/server/lib/security-testing/sast-runner.js +136 -0
- package/server/lib/security-testing/sast-runner.test.js +62 -0
- package/server/lib/security-testing/secret-scanner.js +153 -0
- package/server/lib/security-testing/secret-scanner.test.js +66 -0
- package/server/lib/security-testing/security-gate.js +216 -0
- package/server/lib/security-testing/security-gate.test.js +115 -0
- package/server/lib/security-testing/security-reporter.js +303 -0
- package/server/lib/security-testing/security-reporter.test.js +114 -0
- package/server/lib/standards/audit-checker.js +546 -0
- package/server/lib/standards/audit-checker.test.js +415 -0
- package/server/lib/standards/cleanup-executor.js +452 -0
- package/server/lib/standards/cleanup-executor.test.js +293 -0
- package/server/lib/standards/refactor-stepper.js +425 -0
- package/server/lib/standards/refactor-stepper.test.js +298 -0
- package/server/lib/standards/standards-injector.js +167 -0
- package/server/lib/standards/standards-injector.test.js +232 -0
- package/server/lib/user-management.test.js +284 -0
- package/server/lib/vps/backup-manager.js +157 -0
- package/server/lib/vps/backup-manager.test.js +59 -0
- package/server/lib/vps/caddy-config.js +159 -0
- package/server/lib/vps/caddy-config.test.js +48 -0
- package/server/lib/vps/compose-orchestrator.js +219 -0
- package/server/lib/vps/compose-orchestrator.test.js +50 -0
- package/server/lib/vps/database-config.js +208 -0
- package/server/lib/vps/database-config.test.js +47 -0
- package/server/lib/vps/deploy-script.js +211 -0
- package/server/lib/vps/deploy-script.test.js +53 -0
- package/server/lib/vps/secrets-manager.js +148 -0
- package/server/lib/vps/secrets-manager.test.js +58 -0
- package/server/lib/vps/server-hardening.js +174 -0
- package/server/lib/vps/server-hardening.test.js +70 -0
- package/server/package-lock.json +19 -0
- package/server/package.json +1 -0
- package/server/templates/CLAUDE.md +37 -0
- 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
|
+
});
|