tlc-claude-code 1.2.29 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/dist/components/AuditPane.d.ts +30 -0
- package/dashboard/dist/components/AuditPane.js +127 -0
- package/dashboard/dist/components/AuditPane.test.d.ts +1 -0
- package/dashboard/dist/components/AuditPane.test.js +339 -0
- package/dashboard/dist/components/CompliancePane.d.ts +39 -0
- package/dashboard/dist/components/CompliancePane.js +96 -0
- package/dashboard/dist/components/CompliancePane.test.d.ts +1 -0
- package/dashboard/dist/components/CompliancePane.test.js +183 -0
- package/dashboard/dist/components/SSOPane.d.ts +36 -0
- package/dashboard/dist/components/SSOPane.js +71 -0
- package/dashboard/dist/components/SSOPane.test.d.ts +1 -0
- package/dashboard/dist/components/SSOPane.test.js +155 -0
- package/dashboard/dist/components/UsagePane.d.ts +13 -0
- package/dashboard/dist/components/UsagePane.js +51 -0
- package/dashboard/dist/components/UsagePane.test.d.ts +1 -0
- package/dashboard/dist/components/UsagePane.test.js +142 -0
- package/dashboard/dist/components/WorkspaceDocsPane.d.ts +19 -0
- package/dashboard/dist/components/WorkspaceDocsPane.js +130 -0
- package/dashboard/dist/components/WorkspaceDocsPane.test.d.ts +1 -0
- package/dashboard/dist/components/WorkspaceDocsPane.test.js +242 -0
- package/dashboard/dist/components/WorkspacePane.d.ts +18 -0
- package/dashboard/dist/components/WorkspacePane.js +17 -0
- package/dashboard/dist/components/WorkspacePane.test.d.ts +1 -0
- package/dashboard/dist/components/WorkspacePane.test.js +84 -0
- package/dashboard/dist/components/ZeroRetentionPane.d.ts +44 -0
- package/dashboard/dist/components/ZeroRetentionPane.js +83 -0
- package/dashboard/dist/components/ZeroRetentionPane.test.d.ts +1 -0
- package/dashboard/dist/components/ZeroRetentionPane.test.js +160 -0
- package/package.json +1 -1
- package/server/lib/access-control-doc.js +541 -0
- package/server/lib/access-control-doc.test.js +672 -0
- package/server/lib/adr-generator.js +423 -0
- package/server/lib/adr-generator.test.js +586 -0
- package/server/lib/agent-progress-monitor.js +223 -0
- package/server/lib/agent-progress-monitor.test.js +202 -0
- package/server/lib/architecture-command.js +450 -0
- package/server/lib/architecture-command.test.js +754 -0
- package/server/lib/ast-analyzer.js +324 -0
- package/server/lib/ast-analyzer.test.js +437 -0
- package/server/lib/audit-attribution.js +191 -0
- package/server/lib/audit-attribution.test.js +359 -0
- package/server/lib/audit-classifier.js +202 -0
- package/server/lib/audit-classifier.test.js +209 -0
- package/server/lib/audit-command.js +275 -0
- package/server/lib/audit-command.test.js +325 -0
- package/server/lib/audit-exporter.js +380 -0
- package/server/lib/audit-exporter.test.js +464 -0
- package/server/lib/audit-logger.js +236 -0
- package/server/lib/audit-logger.test.js +364 -0
- package/server/lib/audit-query.js +257 -0
- package/server/lib/audit-query.test.js +352 -0
- package/server/lib/audit-storage.js +269 -0
- package/server/lib/audit-storage.test.js +272 -0
- package/server/lib/auth-system.test.js +4 -1
- package/server/lib/boundary-detector.js +427 -0
- package/server/lib/boundary-detector.test.js +320 -0
- package/server/lib/budget-alerts.js +138 -0
- package/server/lib/budget-alerts.test.js +235 -0
- package/server/lib/bulk-repo-init.js +342 -0
- package/server/lib/bulk-repo-init.test.js +388 -0
- package/server/lib/candidates-tracker.js +210 -0
- package/server/lib/candidates-tracker.test.js +300 -0
- package/server/lib/checkpoint-manager.js +251 -0
- package/server/lib/checkpoint-manager.test.js +474 -0
- package/server/lib/circular-detector.js +337 -0
- package/server/lib/circular-detector.test.js +353 -0
- package/server/lib/cohesion-analyzer.js +310 -0
- package/server/lib/cohesion-analyzer.test.js +447 -0
- package/server/lib/compliance-checklist.js +866 -0
- package/server/lib/compliance-checklist.test.js +476 -0
- package/server/lib/compliance-command.js +616 -0
- package/server/lib/compliance-command.test.js +551 -0
- package/server/lib/compliance-reporter.js +692 -0
- package/server/lib/compliance-reporter.test.js +707 -0
- package/server/lib/contract-testing.js +625 -0
- package/server/lib/contract-testing.test.js +342 -0
- package/server/lib/conversion-planner.js +469 -0
- package/server/lib/conversion-planner.test.js +361 -0
- package/server/lib/convert-command.js +351 -0
- package/server/lib/convert-command.test.js +608 -0
- package/server/lib/coupling-calculator.js +189 -0
- package/server/lib/coupling-calculator.test.js +509 -0
- package/server/lib/data-flow-doc.js +665 -0
- package/server/lib/data-flow-doc.test.js +659 -0
- package/server/lib/dependency-graph.js +367 -0
- package/server/lib/dependency-graph.test.js +516 -0
- package/server/lib/duplication-detector.js +349 -0
- package/server/lib/duplication-detector.test.js +401 -0
- package/server/lib/ephemeral-storage.js +249 -0
- package/server/lib/ephemeral-storage.test.js +254 -0
- package/server/lib/evidence-collector.js +627 -0
- package/server/lib/evidence-collector.test.js +901 -0
- package/server/lib/example-service.js +616 -0
- package/server/lib/example-service.test.js +397 -0
- package/server/lib/flow-diagram-generator.js +474 -0
- package/server/lib/flow-diagram-generator.test.js +446 -0
- package/server/lib/idp-manager.js +626 -0
- package/server/lib/idp-manager.test.js +587 -0
- package/server/lib/impact-scorer.js +184 -0
- package/server/lib/impact-scorer.test.js +211 -0
- package/server/lib/memory-exclusion.js +326 -0
- package/server/lib/memory-exclusion.test.js +241 -0
- package/server/lib/mermaid-generator.js +358 -0
- package/server/lib/mermaid-generator.test.js +301 -0
- package/server/lib/messaging-patterns.js +750 -0
- package/server/lib/messaging-patterns.test.js +213 -0
- package/server/lib/mfa-handler.js +452 -0
- package/server/lib/mfa-handler.test.js +490 -0
- package/server/lib/microservice-template.js +386 -0
- package/server/lib/microservice-template.test.js +325 -0
- package/server/lib/new-project-microservice.js +450 -0
- package/server/lib/new-project-microservice.test.js +600 -0
- package/server/lib/oauth-flow.js +375 -0
- package/server/lib/oauth-flow.test.js +487 -0
- package/server/lib/oauth-registry.js +190 -0
- package/server/lib/oauth-registry.test.js +306 -0
- package/server/lib/readme-generator.js +490 -0
- package/server/lib/readme-generator.test.js +493 -0
- package/server/lib/refactor-command.js +326 -0
- package/server/lib/refactor-command.test.js +528 -0
- package/server/lib/refactor-executor.js +254 -0
- package/server/lib/refactor-executor.test.js +305 -0
- package/server/lib/refactor-observer.js +292 -0
- package/server/lib/refactor-observer.test.js +422 -0
- package/server/lib/refactor-progress.js +193 -0
- package/server/lib/refactor-progress.test.js +251 -0
- package/server/lib/refactor-reporter.js +237 -0
- package/server/lib/refactor-reporter.test.js +247 -0
- package/server/lib/repo-dependency-tracker.js +261 -0
- package/server/lib/repo-dependency-tracker.test.js +350 -0
- package/server/lib/retention-policy.js +281 -0
- package/server/lib/retention-policy.test.js +486 -0
- package/server/lib/role-mapper.js +236 -0
- package/server/lib/role-mapper.test.js +395 -0
- package/server/lib/saml-provider.js +765 -0
- package/server/lib/saml-provider.test.js +643 -0
- package/server/lib/security-policy-generator.js +682 -0
- package/server/lib/security-policy-generator.test.js +544 -0
- package/server/lib/semantic-analyzer.js +198 -0
- package/server/lib/semantic-analyzer.test.js +474 -0
- package/server/lib/sensitive-detector.js +112 -0
- package/server/lib/sensitive-detector.test.js +209 -0
- package/server/lib/service-interaction-diagram.js +700 -0
- package/server/lib/service-interaction-diagram.test.js +638 -0
- package/server/lib/service-scaffold.js +486 -0
- package/server/lib/service-scaffold.test.js +373 -0
- package/server/lib/service-summary.js +553 -0
- package/server/lib/service-summary.test.js +619 -0
- package/server/lib/session-purge.js +460 -0
- package/server/lib/session-purge.test.js +312 -0
- package/server/lib/shared-kernel.js +578 -0
- package/server/lib/shared-kernel.test.js +255 -0
- package/server/lib/sso-command.js +544 -0
- package/server/lib/sso-command.test.js +552 -0
- package/server/lib/sso-session.js +492 -0
- package/server/lib/sso-session.test.js +670 -0
- package/server/lib/traefik-config.js +282 -0
- package/server/lib/traefik-config.test.js +312 -0
- package/server/lib/usage-command.js +218 -0
- package/server/lib/usage-command.test.js +391 -0
- package/server/lib/usage-formatter.js +192 -0
- package/server/lib/usage-formatter.test.js +267 -0
- package/server/lib/usage-history.js +122 -0
- package/server/lib/usage-history.test.js +206 -0
- package/server/lib/workspace-command.js +249 -0
- package/server/lib/workspace-command.test.js +264 -0
- package/server/lib/workspace-config.js +270 -0
- package/server/lib/workspace-config.test.js +312 -0
- package/server/lib/workspace-docs-command.js +547 -0
- package/server/lib/workspace-docs-command.test.js +692 -0
- package/server/lib/workspace-memory.js +451 -0
- package/server/lib/workspace-memory.test.js +403 -0
- package/server/lib/workspace-scanner.js +452 -0
- package/server/lib/workspace-scanner.test.js +677 -0
- package/server/lib/workspace-test-runner.js +315 -0
- package/server/lib/workspace-test-runner.test.js +294 -0
- package/server/lib/zero-retention-command.js +439 -0
- package/server/lib/zero-retention-command.test.js +448 -0
- package/server/lib/zero-retention.js +322 -0
- package/server/lib/zero-retention.test.js +258 -0
- package/server/package-lock.json +14 -0
- package/server/package.json +1 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
classifyAction,
|
|
4
|
+
detectSensitive,
|
|
5
|
+
getSeverity,
|
|
6
|
+
} from './audit-classifier.js';
|
|
7
|
+
|
|
8
|
+
describe('audit-classifier', () => {
|
|
9
|
+
describe('classifyAction', () => {
|
|
10
|
+
it('returns "file:read" for Read tool', () => {
|
|
11
|
+
const action = { tool: 'Read', params: { file_path: '/src/index.js' } };
|
|
12
|
+
const result = classifyAction(action);
|
|
13
|
+
expect(result).toBe('file:read');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('returns "file:write" for Write tool', () => {
|
|
17
|
+
const action = { tool: 'Write', params: { file_path: '/src/new.js', content: 'code' } };
|
|
18
|
+
const result = classifyAction(action);
|
|
19
|
+
expect(result).toBe('file:write');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns "file:edit" for Edit tool', () => {
|
|
23
|
+
const action = { tool: 'Edit', params: { file_path: '/src/index.js', old_string: 'a', new_string: 'b' } };
|
|
24
|
+
const result = classifyAction(action);
|
|
25
|
+
expect(result).toBe('file:edit');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('returns "shell:execute" for Bash tool', () => {
|
|
29
|
+
const action = { tool: 'Bash', params: { command: 'ls -la /src' } };
|
|
30
|
+
const result = classifyAction(action);
|
|
31
|
+
expect(result).toBe('shell:execute');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns "shell:git" for git commands', () => {
|
|
35
|
+
const action = { tool: 'Bash', params: { command: 'git status' } };
|
|
36
|
+
const result = classifyAction(action);
|
|
37
|
+
expect(result).toBe('shell:git');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('returns "shell:git" for git commands with flags', () => {
|
|
41
|
+
const action = { tool: 'Bash', params: { command: 'git commit -m "message"' } };
|
|
42
|
+
const result = classifyAction(action);
|
|
43
|
+
expect(result).toBe('shell:git');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns "network:fetch" for WebFetch', () => {
|
|
47
|
+
const action = { tool: 'WebFetch', params: { url: 'https://example.com' } };
|
|
48
|
+
const result = classifyAction(action);
|
|
49
|
+
expect(result).toBe('network:fetch');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('returns "network:search" for WebSearch', () => {
|
|
53
|
+
const action = { tool: 'WebSearch', params: { query: 'test query' } };
|
|
54
|
+
const result = classifyAction(action);
|
|
55
|
+
expect(result).toBe('network:search');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('returns "file:glob" for Glob tool', () => {
|
|
59
|
+
const action = { tool: 'Glob', params: { pattern: '**/*.js' } };
|
|
60
|
+
const result = classifyAction(action);
|
|
61
|
+
expect(result).toBe('file:glob');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('returns "file:grep" for Grep tool', () => {
|
|
65
|
+
const action = { tool: 'Grep', params: { pattern: 'function' } };
|
|
66
|
+
const result = classifyAction(action);
|
|
67
|
+
expect(result).toBe('file:grep');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('returns "shell:npm" for npm commands', () => {
|
|
71
|
+
const action = { tool: 'Bash', params: { command: 'npm run test' } };
|
|
72
|
+
const result = classifyAction(action);
|
|
73
|
+
expect(result).toBe('shell:npm');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('returns "unknown" for unrecognized tools', () => {
|
|
77
|
+
const action = { tool: 'CustomTool', params: {} };
|
|
78
|
+
const result = classifyAction(action);
|
|
79
|
+
expect(result).toBe('unknown');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('detectSensitive', () => {
|
|
84
|
+
it('flags .env file access', () => {
|
|
85
|
+
const action = { tool: 'Read', params: { file_path: '/project/.env' } };
|
|
86
|
+
const result = detectSensitive(action);
|
|
87
|
+
expect(result.isSensitive).toBe(true);
|
|
88
|
+
expect(result.reason).toContain('.env');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('flags .env.local file access', () => {
|
|
92
|
+
const action = { tool: 'Write', params: { file_path: '/project/.env.local', content: 'SECRET=abc' } };
|
|
93
|
+
const result = detectSensitive(action);
|
|
94
|
+
expect(result.isSensitive).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('flags credential patterns in file paths', () => {
|
|
98
|
+
const action = { tool: 'Read', params: { file_path: '/project/credentials.json' } };
|
|
99
|
+
const result = detectSensitive(action);
|
|
100
|
+
expect(result.isSensitive).toBe(true);
|
|
101
|
+
expect(result.reason).toContain('credential');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('flags secrets directory access', () => {
|
|
105
|
+
const action = { tool: 'Read', params: { file_path: '/project/.secrets/api-key.txt' } };
|
|
106
|
+
const result = detectSensitive(action);
|
|
107
|
+
expect(result.isSensitive).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('flags private key files', () => {
|
|
111
|
+
const action = { tool: 'Read', params: { file_path: '/home/user/.ssh/id_rsa' } };
|
|
112
|
+
const result = detectSensitive(action);
|
|
113
|
+
expect(result.isSensitive).toBe(true);
|
|
114
|
+
expect(result.reason).toContain('private key');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('flags AWS credentials file', () => {
|
|
118
|
+
const action = { tool: 'Read', params: { file_path: '/home/user/.aws/credentials' } };
|
|
119
|
+
const result = detectSensitive(action);
|
|
120
|
+
expect(result.isSensitive).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('does not flag regular source files', () => {
|
|
124
|
+
const action = { tool: 'Read', params: { file_path: '/project/src/index.js' } };
|
|
125
|
+
const result = detectSensitive(action);
|
|
126
|
+
expect(result.isSensitive).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('flags password in command', () => {
|
|
130
|
+
const action = { tool: 'Bash', params: { command: 'echo "password=secret123"' } };
|
|
131
|
+
const result = detectSensitive(action);
|
|
132
|
+
expect(result.isSensitive).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('flags API key in command', () => {
|
|
136
|
+
const action = { tool: 'Bash', params: { command: 'curl -H "Authorization: Bearer sk-abc123"' } };
|
|
137
|
+
const result = detectSensitive(action);
|
|
138
|
+
expect(result.isSensitive).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('flags token patterns in write content', () => {
|
|
142
|
+
const action = { tool: 'Write', params: { file_path: '/config.js', content: 'const TOKEN = "ghp_abc123";' } };
|
|
143
|
+
const result = detectSensitive(action);
|
|
144
|
+
expect(result.isSensitive).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe('getSeverity', () => {
|
|
149
|
+
it('returns "critical" for sensitive operations', () => {
|
|
150
|
+
const action = { tool: 'Read', params: { file_path: '/project/.env' } };
|
|
151
|
+
const result = getSeverity(action);
|
|
152
|
+
expect(result).toBe('critical');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('returns "info" for read operations', () => {
|
|
156
|
+
const action = { tool: 'Read', params: { file_path: '/src/index.js' } };
|
|
157
|
+
const result = getSeverity(action);
|
|
158
|
+
expect(result).toBe('info');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('returns "warning" for write operations', () => {
|
|
162
|
+
const action = { tool: 'Write', params: { file_path: '/src/new.js', content: 'code' } };
|
|
163
|
+
const result = getSeverity(action);
|
|
164
|
+
expect(result).toBe('warning');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('returns "warning" for edit operations', () => {
|
|
168
|
+
const action = { tool: 'Edit', params: { file_path: '/src/index.js' } };
|
|
169
|
+
const result = getSeverity(action);
|
|
170
|
+
expect(result).toBe('warning');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('returns "warning" for shell execution', () => {
|
|
174
|
+
const action = { tool: 'Bash', params: { command: 'npm install' } };
|
|
175
|
+
const result = getSeverity(action);
|
|
176
|
+
expect(result).toBe('warning');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('returns "info" for git commands', () => {
|
|
180
|
+
const action = { tool: 'Bash', params: { command: 'git status' } };
|
|
181
|
+
const result = getSeverity(action);
|
|
182
|
+
expect(result).toBe('info');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('returns "info" for glob/grep operations', () => {
|
|
186
|
+
const action = { tool: 'Glob', params: { pattern: '**/*.js' } };
|
|
187
|
+
const result = getSeverity(action);
|
|
188
|
+
expect(result).toBe('info');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('returns "info" for network fetch', () => {
|
|
192
|
+
const action = { tool: 'WebFetch', params: { url: 'https://docs.example.com' } };
|
|
193
|
+
const result = getSeverity(action);
|
|
194
|
+
expect(result).toBe('info');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('returns "critical" for destructive git commands', () => {
|
|
198
|
+
const action = { tool: 'Bash', params: { command: 'git push --force' } };
|
|
199
|
+
const result = getSeverity(action);
|
|
200
|
+
expect(result).toBe('critical');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('returns "critical" for rm -rf commands', () => {
|
|
204
|
+
const action = { tool: 'Bash', params: { command: 'rm -rf /project/dist' } };
|
|
205
|
+
const result = getSeverity(action);
|
|
206
|
+
expect(result).toBe('critical');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Command - CLI command to view and export audit logs
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - View recent audit entries
|
|
6
|
+
* - Filter by user, action type, date
|
|
7
|
+
* - Export to JSON, CSV, Splunk, CEF formats
|
|
8
|
+
* - Verify log integrity (checksum validation)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { AuditStorage } from './audit-storage.js';
|
|
12
|
+
import { AuditQuery } from './audit-query.js';
|
|
13
|
+
import { AuditExporter } from './audit-exporter.js';
|
|
14
|
+
|
|
15
|
+
const VALID_EXPORT_FORMATS = ['json', 'csv', 'splunk', 'cef'];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse command line arguments
|
|
19
|
+
* @param {string[]} args - Command line arguments
|
|
20
|
+
* @returns {Object} Parsed options
|
|
21
|
+
*/
|
|
22
|
+
export function parseArgs(args) {
|
|
23
|
+
const result = {
|
|
24
|
+
user: null,
|
|
25
|
+
type: null,
|
|
26
|
+
since: null,
|
|
27
|
+
export: null,
|
|
28
|
+
verify: false,
|
|
29
|
+
limit: 20,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < args.length; i++) {
|
|
33
|
+
const arg = args[i];
|
|
34
|
+
|
|
35
|
+
if (arg === '--verify') {
|
|
36
|
+
result.verify = true;
|
|
37
|
+
} else if (arg === '--user') {
|
|
38
|
+
result.user = args[i + 1];
|
|
39
|
+
i++;
|
|
40
|
+
} else if (arg.startsWith('--user=')) {
|
|
41
|
+
result.user = arg.split('=')[1];
|
|
42
|
+
} else if (arg === '--type') {
|
|
43
|
+
result.type = args[i + 1];
|
|
44
|
+
i++;
|
|
45
|
+
} else if (arg.startsWith('--type=')) {
|
|
46
|
+
result.type = arg.split('=')[1];
|
|
47
|
+
} else if (arg === '--since') {
|
|
48
|
+
result.since = args[i + 1];
|
|
49
|
+
i++;
|
|
50
|
+
} else if (arg.startsWith('--since=')) {
|
|
51
|
+
result.since = arg.split('=')[1];
|
|
52
|
+
} else if (arg === '--export') {
|
|
53
|
+
result.export = args[i + 1];
|
|
54
|
+
i++;
|
|
55
|
+
} else if (arg.startsWith('--export=')) {
|
|
56
|
+
result.export = arg.split('=')[1];
|
|
57
|
+
} else if (arg === '--limit') {
|
|
58
|
+
result.limit = parseInt(args[i + 1], 10);
|
|
59
|
+
i++;
|
|
60
|
+
} else if (arg.startsWith('--limit=')) {
|
|
61
|
+
result.limit = parseInt(arg.split('=')[1], 10);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* AuditCommand class - handles tlc audit command
|
|
70
|
+
*/
|
|
71
|
+
export class AuditCommand {
|
|
72
|
+
/**
|
|
73
|
+
* Create an AuditCommand instance
|
|
74
|
+
* @param {Object} options - Configuration options
|
|
75
|
+
* @param {AuditStorage} options.storage - AuditStorage instance
|
|
76
|
+
* @param {AuditQuery} options.query - AuditQuery instance
|
|
77
|
+
* @param {AuditExporter} options.exporter - AuditExporter instance
|
|
78
|
+
* @param {string} options.baseDir - Base directory for audit storage
|
|
79
|
+
*/
|
|
80
|
+
constructor(options = {}) {
|
|
81
|
+
this.storage = options.storage || new AuditStorage(options.baseDir);
|
|
82
|
+
this.query = options.query || new AuditQuery(this.storage);
|
|
83
|
+
this.exporter = options.exporter || new AuditExporter(options.baseDir);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Execute the audit command
|
|
88
|
+
* @param {string[]} args - Command arguments
|
|
89
|
+
* @returns {Promise<Object>} Result { success, output, error? }
|
|
90
|
+
*/
|
|
91
|
+
async execute(args) {
|
|
92
|
+
const options = parseArgs(args);
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// Handle --verify flag
|
|
96
|
+
if (options.verify) {
|
|
97
|
+
return await this.handleVerify();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Handle --export flag
|
|
101
|
+
if (options.export) {
|
|
102
|
+
return await this.handleExport(options);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Default: query and display entries
|
|
106
|
+
return await this.handleQuery(options);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
output: '',
|
|
111
|
+
error: error.message,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Handle --verify flag
|
|
118
|
+
* @returns {Promise<Object>} Result
|
|
119
|
+
*/
|
|
120
|
+
async handleVerify() {
|
|
121
|
+
const result = await this.storage.verifyIntegrity();
|
|
122
|
+
const output = this.formatVerifyResult(result);
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
success: result.valid,
|
|
126
|
+
output,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Handle --export flag
|
|
132
|
+
* @param {Object} options - Parsed options
|
|
133
|
+
* @returns {Promise<Object>} Result
|
|
134
|
+
*/
|
|
135
|
+
async handleExport(options) {
|
|
136
|
+
const format = options.export.toLowerCase();
|
|
137
|
+
|
|
138
|
+
if (!VALID_EXPORT_FORMATS.includes(format)) {
|
|
139
|
+
return {
|
|
140
|
+
success: false,
|
|
141
|
+
output: '',
|
|
142
|
+
error: `Invalid export format: ${options.export}. Valid formats: ${VALID_EXPORT_FORMATS.join(', ')}`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Build export options
|
|
147
|
+
const exportOptions = {};
|
|
148
|
+
if (options.since) {
|
|
149
|
+
exportOptions.from = new Date(options.since);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let content;
|
|
153
|
+
switch (format) {
|
|
154
|
+
case 'json':
|
|
155
|
+
content = await this.exporter.exportJSON(exportOptions);
|
|
156
|
+
break;
|
|
157
|
+
case 'csv':
|
|
158
|
+
content = await this.exporter.exportCSV(exportOptions);
|
|
159
|
+
break;
|
|
160
|
+
case 'splunk':
|
|
161
|
+
content = await this.exporter.exportSplunk(exportOptions);
|
|
162
|
+
break;
|
|
163
|
+
case 'cef':
|
|
164
|
+
content = await this.exporter.exportCEF(exportOptions);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
success: true,
|
|
170
|
+
output: content,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Handle query (default behavior)
|
|
176
|
+
* @param {Object} options - Parsed options
|
|
177
|
+
* @returns {Promise<Object>} Result
|
|
178
|
+
*/
|
|
179
|
+
async handleQuery(options) {
|
|
180
|
+
// Build query options
|
|
181
|
+
const queryOptions = {
|
|
182
|
+
limit: options.limit,
|
|
183
|
+
sort: 'desc',
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
if (options.user) {
|
|
187
|
+
queryOptions.user = options.user;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (options.type) {
|
|
191
|
+
queryOptions.action = options.type;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (options.since) {
|
|
195
|
+
queryOptions.from = new Date(options.since);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const result = await this.query.query(queryOptions);
|
|
199
|
+
|
|
200
|
+
if (result.entries.length === 0) {
|
|
201
|
+
return {
|
|
202
|
+
success: true,
|
|
203
|
+
output: 'No audit entries found.',
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const output = this.formatQueryResult(result);
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
success: true,
|
|
211
|
+
output,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Format query result for display
|
|
217
|
+
* @param {Object} result - Query result
|
|
218
|
+
* @returns {string} Formatted output
|
|
219
|
+
*/
|
|
220
|
+
formatQueryResult(result) {
|
|
221
|
+
const lines = [];
|
|
222
|
+
|
|
223
|
+
lines.push(`Audit Log (${result.total} entries)`);
|
|
224
|
+
lines.push('='.repeat(60));
|
|
225
|
+
lines.push('');
|
|
226
|
+
|
|
227
|
+
for (const entry of result.entries) {
|
|
228
|
+
lines.push(this.formatEntry(entry));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (result.hasMore) {
|
|
232
|
+
lines.push('');
|
|
233
|
+
lines.push(`... and more. Use --limit to see more entries.`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return lines.join('\n');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Format a single entry for display
|
|
241
|
+
* @param {Object} entry - Audit entry
|
|
242
|
+
* @returns {string} Formatted entry
|
|
243
|
+
*/
|
|
244
|
+
formatEntry(entry) {
|
|
245
|
+
const timestamp = entry.timestamp ? entry.timestamp.substring(0, 19).replace('T', ' ') : 'unknown';
|
|
246
|
+
const tool = entry.tool || 'unknown';
|
|
247
|
+
const user = entry.attribution?.user || entry.user || '-';
|
|
248
|
+
const classification = entry.classification || '-';
|
|
249
|
+
const severity = entry.severity || 'info';
|
|
250
|
+
|
|
251
|
+
return `[${timestamp}] ${severity.toUpperCase().padEnd(8)} ${tool.padEnd(12)} ${classification.padEnd(20)} ${user}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Format verify result for display
|
|
256
|
+
* @param {Object} result - Verification result
|
|
257
|
+
* @returns {string} Formatted output
|
|
258
|
+
*/
|
|
259
|
+
formatVerifyResult(result) {
|
|
260
|
+
const lines = [];
|
|
261
|
+
|
|
262
|
+
if (result.valid) {
|
|
263
|
+
lines.push('Audit log integrity check: VALID');
|
|
264
|
+
lines.push(`Verified ${result.entryCount} entries`);
|
|
265
|
+
lines.push('All checksums and chain links are valid.');
|
|
266
|
+
} else {
|
|
267
|
+
lines.push('Audit log integrity check: INVALID');
|
|
268
|
+
lines.push(`Error at entry ${result.entryCount}: ${result.error}`);
|
|
269
|
+
lines.push('');
|
|
270
|
+
lines.push('WARNING: Possible tampering detected!');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return lines.join('\n');
|
|
274
|
+
}
|
|
275
|
+
}
|