@sonde/agent 0.0.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.
Files changed (149) hide show
  1. package/dist/cli/packs.d.ts +23 -0
  2. package/dist/cli/packs.d.ts.map +1 -0
  3. package/dist/cli/packs.js +172 -0
  4. package/dist/cli/packs.js.map +1 -0
  5. package/dist/cli/packs.test.d.ts +2 -0
  6. package/dist/cli/packs.test.d.ts.map +1 -0
  7. package/dist/cli/packs.test.js +171 -0
  8. package/dist/cli/packs.test.js.map +1 -0
  9. package/dist/config.d.ts +18 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +38 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/index.d.ts +13 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +191 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/runtime/attestation.d.ts +9 -0
  18. package/dist/runtime/attestation.d.ts.map +1 -0
  19. package/dist/runtime/attestation.js +32 -0
  20. package/dist/runtime/attestation.js.map +1 -0
  21. package/dist/runtime/attestation.test.d.ts +2 -0
  22. package/dist/runtime/attestation.test.d.ts.map +1 -0
  23. package/dist/runtime/attestation.test.js +59 -0
  24. package/dist/runtime/attestation.test.js.map +1 -0
  25. package/dist/runtime/audit.d.ts +19 -0
  26. package/dist/runtime/audit.d.ts.map +1 -0
  27. package/dist/runtime/audit.js +52 -0
  28. package/dist/runtime/audit.js.map +1 -0
  29. package/dist/runtime/audit.test.d.ts +2 -0
  30. package/dist/runtime/audit.test.d.ts.map +1 -0
  31. package/dist/runtime/audit.test.js +53 -0
  32. package/dist/runtime/audit.test.js.map +1 -0
  33. package/dist/runtime/connection.d.ts +55 -0
  34. package/dist/runtime/connection.d.ts.map +1 -0
  35. package/dist/runtime/connection.js +325 -0
  36. package/dist/runtime/connection.js.map +1 -0
  37. package/dist/runtime/connection.test.d.ts +2 -0
  38. package/dist/runtime/connection.test.d.ts.map +1 -0
  39. package/dist/runtime/connection.test.js +221 -0
  40. package/dist/runtime/connection.test.js.map +1 -0
  41. package/dist/runtime/executor.d.ts +21 -0
  42. package/dist/runtime/executor.d.ts.map +1 -0
  43. package/dist/runtime/executor.js +89 -0
  44. package/dist/runtime/executor.js.map +1 -0
  45. package/dist/runtime/executor.test.d.ts +2 -0
  46. package/dist/runtime/executor.test.d.ts.map +1 -0
  47. package/dist/runtime/executor.test.js +88 -0
  48. package/dist/runtime/executor.test.js.map +1 -0
  49. package/dist/runtime/privilege.d.ts +9 -0
  50. package/dist/runtime/privilege.d.ts.map +1 -0
  51. package/dist/runtime/privilege.js +35 -0
  52. package/dist/runtime/privilege.js.map +1 -0
  53. package/dist/runtime/privilege.test.d.ts +2 -0
  54. package/dist/runtime/privilege.test.d.ts.map +1 -0
  55. package/dist/runtime/privilege.test.js +22 -0
  56. package/dist/runtime/privilege.test.js.map +1 -0
  57. package/dist/runtime/scrubber.d.ts +17 -0
  58. package/dist/runtime/scrubber.d.ts.map +1 -0
  59. package/dist/runtime/scrubber.js +84 -0
  60. package/dist/runtime/scrubber.js.map +1 -0
  61. package/dist/runtime/scrubber.test.d.ts +2 -0
  62. package/dist/runtime/scrubber.test.d.ts.map +1 -0
  63. package/dist/runtime/scrubber.test.js +72 -0
  64. package/dist/runtime/scrubber.test.js.map +1 -0
  65. package/dist/system/scanner.d.ts +32 -0
  66. package/dist/system/scanner.d.ts.map +1 -0
  67. package/dist/system/scanner.js +90 -0
  68. package/dist/system/scanner.js.map +1 -0
  69. package/dist/system/scanner.test.d.ts +2 -0
  70. package/dist/system/scanner.test.d.ts.map +1 -0
  71. package/dist/system/scanner.test.js +121 -0
  72. package/dist/system/scanner.test.js.map +1 -0
  73. package/dist/tui/installer/InstallerApp.d.ts +11 -0
  74. package/dist/tui/installer/InstallerApp.d.ts.map +1 -0
  75. package/dist/tui/installer/InstallerApp.js +32 -0
  76. package/dist/tui/installer/InstallerApp.js.map +1 -0
  77. package/dist/tui/installer/StepComplete.d.ts +9 -0
  78. package/dist/tui/installer/StepComplete.d.ts.map +1 -0
  79. package/dist/tui/installer/StepComplete.js +46 -0
  80. package/dist/tui/installer/StepComplete.js.map +1 -0
  81. package/dist/tui/installer/StepHub.d.ts +8 -0
  82. package/dist/tui/installer/StepHub.d.ts.map +1 -0
  83. package/dist/tui/installer/StepHub.js +65 -0
  84. package/dist/tui/installer/StepHub.js.map +1 -0
  85. package/dist/tui/installer/StepPacks.d.ts +9 -0
  86. package/dist/tui/installer/StepPacks.d.ts.map +1 -0
  87. package/dist/tui/installer/StepPacks.js +35 -0
  88. package/dist/tui/installer/StepPacks.js.map +1 -0
  89. package/dist/tui/installer/StepPermissions.d.ts +9 -0
  90. package/dist/tui/installer/StepPermissions.d.ts.map +1 -0
  91. package/dist/tui/installer/StepPermissions.js +39 -0
  92. package/dist/tui/installer/StepPermissions.js.map +1 -0
  93. package/dist/tui/installer/StepScan.d.ts +7 -0
  94. package/dist/tui/installer/StepScan.d.ts.map +1 -0
  95. package/dist/tui/installer/StepScan.js +38 -0
  96. package/dist/tui/installer/StepScan.js.map +1 -0
  97. package/dist/tui/manager/ActivityLog.d.ts +7 -0
  98. package/dist/tui/manager/ActivityLog.d.ts.map +1 -0
  99. package/dist/tui/manager/ActivityLog.js +25 -0
  100. package/dist/tui/manager/ActivityLog.js.map +1 -0
  101. package/dist/tui/manager/AuditView.d.ts +7 -0
  102. package/dist/tui/manager/AuditView.d.ts.map +1 -0
  103. package/dist/tui/manager/AuditView.js +32 -0
  104. package/dist/tui/manager/AuditView.js.map +1 -0
  105. package/dist/tui/manager/ManagerApp.d.ts +20 -0
  106. package/dist/tui/manager/ManagerApp.d.ts.map +1 -0
  107. package/dist/tui/manager/ManagerApp.js +79 -0
  108. package/dist/tui/manager/ManagerApp.js.map +1 -0
  109. package/dist/tui/manager/PackManager.d.ts +7 -0
  110. package/dist/tui/manager/PackManager.d.ts.map +1 -0
  111. package/dist/tui/manager/PackManager.js +22 -0
  112. package/dist/tui/manager/PackManager.js.map +1 -0
  113. package/dist/tui/manager/StatusView.d.ts +15 -0
  114. package/dist/tui/manager/StatusView.d.ts.map +1 -0
  115. package/dist/tui/manager/StatusView.js +10 -0
  116. package/dist/tui/manager/StatusView.js.map +1 -0
  117. package/package.json +45 -0
  118. package/scripts/install.sh +11 -0
  119. package/src/cli/packs.test.ts +213 -0
  120. package/src/cli/packs.ts +214 -0
  121. package/src/config.ts +62 -0
  122. package/src/index.ts +218 -0
  123. package/src/runtime/attestation.test.ts +69 -0
  124. package/src/runtime/attestation.ts +36 -0
  125. package/src/runtime/audit.test.ts +64 -0
  126. package/src/runtime/audit.ts +70 -0
  127. package/src/runtime/connection.test.ts +303 -0
  128. package/src/runtime/connection.ts +389 -0
  129. package/src/runtime/executor.test.ts +112 -0
  130. package/src/runtime/executor.ts +107 -0
  131. package/src/runtime/privilege.test.ts +25 -0
  132. package/src/runtime/privilege.ts +36 -0
  133. package/src/runtime/scrubber.test.ts +84 -0
  134. package/src/runtime/scrubber.ts +96 -0
  135. package/src/system/scanner.test.ts +154 -0
  136. package/src/system/scanner.ts +133 -0
  137. package/src/tui/installer/InstallerApp.tsx +86 -0
  138. package/src/tui/installer/StepComplete.tsx +94 -0
  139. package/src/tui/installer/StepHub.tsx +111 -0
  140. package/src/tui/installer/StepPacks.tsx +73 -0
  141. package/src/tui/installer/StepPermissions.tsx +104 -0
  142. package/src/tui/installer/StepScan.tsx +82 -0
  143. package/src/tui/manager/ActivityLog.tsx +57 -0
  144. package/src/tui/manager/AuditView.tsx +73 -0
  145. package/src/tui/manager/ManagerApp.tsx +157 -0
  146. package/src/tui/manager/PackManager.tsx +71 -0
  147. package/src/tui/manager/StatusView.tsx +103 -0
  148. package/tsconfig.json +13 -0
  149. package/vitest.config.ts +8 -0
@@ -0,0 +1,89 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { packRegistry } from '@sonde/packs';
4
+ import { buildPatterns, scrubData } from './scrubber.js';
5
+ const execFileAsync = promisify(execFile);
6
+ const AGENT_VERSION = '0.1.0';
7
+ /** Default exec function that shells out to real commands */
8
+ async function defaultExec(command, args) {
9
+ const { stdout } = await execFileAsync(command, args, {
10
+ timeout: 30_000,
11
+ maxBuffer: 1024 * 1024,
12
+ });
13
+ return stdout;
14
+ }
15
+ export class ProbeExecutor {
16
+ packs;
17
+ exec;
18
+ scrubPatterns;
19
+ constructor(packs, exec, scrubPatterns) {
20
+ this.packs = packs ?? packRegistry;
21
+ this.exec = exec ?? defaultExec;
22
+ this.scrubPatterns = scrubPatterns ?? buildPatterns();
23
+ }
24
+ /** Get list of loaded packs with status info */
25
+ getLoadedPacks() {
26
+ return [...this.packs.values()].map((pack) => ({
27
+ name: pack.manifest.name,
28
+ version: pack.manifest.version,
29
+ status: 'active',
30
+ }));
31
+ }
32
+ /** Get a pack by name */
33
+ getPackByName(name) {
34
+ return this.packs.get(name);
35
+ }
36
+ /** Execute a probe request and return a probe response */
37
+ async execute(request) {
38
+ const start = Date.now();
39
+ // Find the handler by full probe name (e.g. "system.disk.usage")
40
+ const probeName = request.probe;
41
+ const packName = probeName.split('.')[0];
42
+ if (!packName) {
43
+ return this.errorResponse(probeName, start, `Invalid probe name: ${probeName}`);
44
+ }
45
+ const pack = this.packs.get(packName);
46
+ if (!pack) {
47
+ return this.errorResponse(probeName, start, `Pack '${packName}' not loaded`);
48
+ }
49
+ const handler = pack.handlers[probeName];
50
+ if (!handler) {
51
+ return this.errorResponse(probeName, start, `Unknown probe: ${probeName}`);
52
+ }
53
+ try {
54
+ const rawData = await handler(request.params, this.exec);
55
+ const data = scrubData(rawData, this.scrubPatterns);
56
+ return {
57
+ probe: probeName,
58
+ status: 'success',
59
+ data,
60
+ durationMs: Date.now() - start,
61
+ metadata: {
62
+ agentVersion: AGENT_VERSION,
63
+ packName: pack.manifest.name,
64
+ packVersion: pack.manifest.version,
65
+ capabilityLevel: 'observe',
66
+ },
67
+ };
68
+ }
69
+ catch (error) {
70
+ const message = error instanceof Error ? error.message : 'Unknown error';
71
+ return this.errorResponse(probeName, start, message, pack);
72
+ }
73
+ }
74
+ errorResponse(probe, startMs, message, pack) {
75
+ return {
76
+ probe,
77
+ status: 'error',
78
+ data: { error: message },
79
+ durationMs: Date.now() - startMs,
80
+ metadata: {
81
+ agentVersion: AGENT_VERSION,
82
+ packName: pack?.manifest.name ?? 'unknown',
83
+ packVersion: pack?.manifest.version ?? '0.0.0',
84
+ capabilityLevel: 'observe',
85
+ },
86
+ };
87
+ }
88
+ }
89
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/runtime/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=executor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.test.d.ts","sourceRoot":"","sources":["../../src/runtime/executor.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { ProbeExecutor } from './executor.js';
3
+ function createMockPack(overrides) {
4
+ return {
5
+ manifest: {
6
+ name: 'test',
7
+ version: '1.0.0',
8
+ description: 'Test pack',
9
+ requires: { groups: [], files: [], commands: [] },
10
+ probes: [{ name: 'echo', description: 'Echo test', capability: 'observe', timeout: 5000 }],
11
+ },
12
+ handlers: {
13
+ 'test.echo': vi.fn().mockResolvedValue({ message: 'hello' }),
14
+ },
15
+ ...overrides,
16
+ };
17
+ }
18
+ function makeRequest(probe, params) {
19
+ return {
20
+ probe,
21
+ params,
22
+ timeout: 30_000,
23
+ requestedBy: 'test',
24
+ };
25
+ }
26
+ describe('ProbeExecutor', () => {
27
+ it('executes a probe and returns success response', async () => {
28
+ const pack = createMockPack();
29
+ const packs = new Map([['test', pack]]);
30
+ const executor = new ProbeExecutor(packs);
31
+ const result = await executor.execute(makeRequest('test.echo'));
32
+ expect(result.status).toBe('success');
33
+ expect(result.probe).toBe('test.echo');
34
+ expect(result.data).toEqual({ message: 'hello' });
35
+ expect(result.durationMs).toBeGreaterThanOrEqual(0);
36
+ expect(result.metadata.packName).toBe('test');
37
+ expect(result.metadata.packVersion).toBe('1.0.0');
38
+ });
39
+ it('passes params and exec to handler', async () => {
40
+ const handler = vi.fn().mockResolvedValue({ ok: true });
41
+ const mockExec = vi.fn();
42
+ const pack = createMockPack({ handlers: { 'test.echo': handler } });
43
+ const packs = new Map([['test', pack]]);
44
+ const executor = new ProbeExecutor(packs, mockExec);
45
+ await executor.execute(makeRequest('test.echo', { verbose: true }));
46
+ expect(handler).toHaveBeenCalledWith({ verbose: true }, mockExec);
47
+ });
48
+ it('returns error for unknown pack', async () => {
49
+ const executor = new ProbeExecutor(new Map());
50
+ const result = await executor.execute(makeRequest('missing.probe'));
51
+ expect(result.status).toBe('error');
52
+ expect(result.data).toEqual({ error: "Pack 'missing' not loaded" });
53
+ });
54
+ it('returns error for unknown probe within pack', async () => {
55
+ const pack = createMockPack();
56
+ const packs = new Map([['test', pack]]);
57
+ const executor = new ProbeExecutor(packs);
58
+ const result = await executor.execute(makeRequest('test.nonexistent'));
59
+ expect(result.status).toBe('error');
60
+ expect(result.data).toEqual({ error: 'Unknown probe: test.nonexistent' });
61
+ });
62
+ it('returns error when handler throws', async () => {
63
+ const pack = createMockPack({
64
+ handlers: {
65
+ 'test.echo': vi.fn().mockRejectedValue(new Error('Command failed')),
66
+ },
67
+ });
68
+ const packs = new Map([['test', pack]]);
69
+ const executor = new ProbeExecutor(packs);
70
+ const result = await executor.execute(makeRequest('test.echo'));
71
+ expect(result.status).toBe('error');
72
+ expect(result.data).toEqual({ error: 'Command failed' });
73
+ expect(result.metadata.packName).toBe('test');
74
+ });
75
+ it('returns error for invalid probe name', async () => {
76
+ const executor = new ProbeExecutor(new Map());
77
+ const result = await executor.execute(makeRequest(''));
78
+ expect(result.status).toBe('error');
79
+ });
80
+ it('reports loaded packs', () => {
81
+ const pack = createMockPack();
82
+ const packs = new Map([['test', pack]]);
83
+ const executor = new ProbeExecutor(packs);
84
+ const loaded = executor.getLoadedPacks();
85
+ expect(loaded).toEqual([{ name: 'test', version: '1.0.0', status: 'active' }]);
86
+ });
87
+ });
88
+ //# sourceMappingURL=executor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.test.js","sourceRoot":"","sources":["../../src/runtime/executor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /** Exit with error if running as root (uid 0) */
2
+ export declare function checkNotRoot(): void;
3
+ /** Check if the 'sonde' system user exists */
4
+ export declare function sondeUserExists(): boolean;
5
+ /** Return group list for the sonde user */
6
+ export declare function getSondeGroups(): string[];
7
+ /** Return the command to add the sonde user to a group */
8
+ export declare function suggestGroupAdd(group: string): string;
9
+ //# sourceMappingURL=privilege.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privilege.d.ts","sourceRoot":"","sources":["../../src/runtime/privilege.ts"],"names":[],"mappings":"AAEA,iDAAiD;AACjD,wBAAgB,YAAY,IAAI,IAAI,CAOnC;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,IAAI,OAAO,CAOzC;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAOzC;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD"}
@@ -0,0 +1,35 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ /** Exit with error if running as root (uid 0) */
3
+ export function checkNotRoot() {
4
+ if (process.getuid?.() === 0) {
5
+ console.error('Error: sonde agent must not run as root.');
6
+ console.error('Run as the dedicated "sonde" user or a non-root account.');
7
+ console.error('See: packages/agent/scripts/install.sh');
8
+ process.exit(1);
9
+ }
10
+ }
11
+ /** Check if the 'sonde' system user exists */
12
+ export function sondeUserExists() {
13
+ try {
14
+ execFileSync('id', ['-u', 'sonde'], { stdio: 'ignore' });
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ /** Return group list for the sonde user */
22
+ export function getSondeGroups() {
23
+ try {
24
+ const output = execFileSync('id', ['-Gn', 'sonde'], { encoding: 'utf-8' }).trim();
25
+ return output ? output.split(/\s+/) : [];
26
+ }
27
+ catch {
28
+ return [];
29
+ }
30
+ }
31
+ /** Return the command to add the sonde user to a group */
32
+ export function suggestGroupAdd(group) {
33
+ return `sudo usermod -aG ${group} sonde`;
34
+ }
35
+ //# sourceMappingURL=privilege.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privilege.js","sourceRoot":"","sources":["../../src/runtime/privilege.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,iDAAiD;AACjD,MAAM,UAAU,YAAY;IAC1B,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC1E,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAClF,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,oBAAoB,KAAK,QAAQ,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=privilege.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privilege.test.d.ts","sourceRoot":"","sources":["../../src/runtime/privilege.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { checkNotRoot, sondeUserExists, suggestGroupAdd } from './privilege.js';
3
+ describe('privilege', () => {
4
+ it('checkNotRoot does not throw for non-root', () => {
5
+ // Tests run as non-root, so this should not exit
6
+ expect(() => checkNotRoot()).not.toThrow();
7
+ });
8
+ it('sondeUserExists returns a boolean', () => {
9
+ const result = sondeUserExists();
10
+ expect(typeof result).toBe('boolean');
11
+ });
12
+ it('suggestGroupAdd returns correct command', () => {
13
+ expect(suggestGroupAdd('docker')).toBe('sudo usermod -aG docker sonde');
14
+ expect(suggestGroupAdd('systemd-journal')).toBe('sudo usermod -aG systemd-journal sonde');
15
+ });
16
+ it('suggestGroupAdd with different groups', () => {
17
+ const cmd = suggestGroupAdd('adm');
18
+ expect(cmd).toContain('adm');
19
+ expect(cmd).toContain('sonde');
20
+ });
21
+ });
22
+ //# sourceMappingURL=privilege.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privilege.test.js","sourceRoot":"","sources":["../../src/runtime/privilege.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEhF,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,iDAAiD;QACjD,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QACjC,MAAM,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACxE,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface ScrubPattern {
2
+ name: string;
3
+ pattern: RegExp;
4
+ replacement?: string;
5
+ }
6
+ export declare const DEFAULT_SCRUB_PATTERNS: ScrubPattern[];
7
+ /**
8
+ * Deep-walk data, applying scrub patterns to all string values.
9
+ * Also redacts values of object keys that match sensitive key names.
10
+ */
11
+ export declare function scrubData(data: unknown, patterns: ScrubPattern[]): unknown;
12
+ /**
13
+ * Build scrub patterns from defaults + optional custom regex strings.
14
+ * Invalid custom regexes are silently skipped.
15
+ */
16
+ export declare function buildPatterns(customRegexes?: string[]): ScrubPattern[];
17
+ //# sourceMappingURL=scrubber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrubber.d.ts","sourceRoot":"","sources":["../../src/runtime/scrubber.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAKD,eAAO,MAAM,sBAAsB,EAAE,YAAY,EAsBhD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,CAyB1E;AAYD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAiBtE"}
@@ -0,0 +1,84 @@
1
+ /** Key names that indicate sensitive values (case-insensitive match) */
2
+ const SENSITIVE_KEY_RE = /(?:SECRET|KEY|TOKEN|PASSWORD|CREDENTIAL|PRIVATE)/i;
3
+ export const DEFAULT_SCRUB_PATTERNS = [
4
+ {
5
+ name: 'env-var-secrets',
6
+ pattern: /\b(\w*(?:SECRET|KEY|TOKEN|PASSWORD|CREDENTIAL|PRIVATE)\w*)\s*[=:]\s*\S+/gi,
7
+ replacement: '$1=[REDACTED]',
8
+ },
9
+ {
10
+ name: 'connection-strings',
11
+ pattern: /((?:postgres|postgresql|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:]+:)[^@]+(@)/gi,
12
+ replacement: '$1[REDACTED]$2',
13
+ },
14
+ {
15
+ name: 'bearer-tokens',
16
+ pattern: /(Bearer\s+)\S+/gi,
17
+ replacement: '$1[REDACTED]',
18
+ },
19
+ {
20
+ name: 'generic-api-keys',
21
+ pattern: /(api[_-]?key|access[_-]?token|auth[_-]?token)\s*[=:]\s*["']?[\w\-./+=]{16,}["']?/gi,
22
+ replacement: '$1=[REDACTED]',
23
+ },
24
+ ];
25
+ /**
26
+ * Deep-walk data, applying scrub patterns to all string values.
27
+ * Also redacts values of object keys that match sensitive key names.
28
+ */
29
+ export function scrubData(data, patterns) {
30
+ if (data === null || data === undefined)
31
+ return data;
32
+ if (typeof data === 'boolean' || typeof data === 'number')
33
+ return data;
34
+ if (typeof data === 'string') {
35
+ return scrubString(data, patterns);
36
+ }
37
+ if (Array.isArray(data)) {
38
+ return data.map((item) => scrubData(item, patterns));
39
+ }
40
+ if (typeof data === 'object') {
41
+ const result = {};
42
+ for (const [key, value] of Object.entries(data)) {
43
+ if (SENSITIVE_KEY_RE.test(key) && typeof value === 'string') {
44
+ result[key] = '[REDACTED]';
45
+ }
46
+ else {
47
+ result[key] = scrubData(value, patterns);
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+ return data;
53
+ }
54
+ function scrubString(str, patterns) {
55
+ let result = str;
56
+ for (const p of patterns) {
57
+ // Reset lastIndex for global regexes
58
+ p.pattern.lastIndex = 0;
59
+ result = result.replace(p.pattern, p.replacement ?? '[REDACTED]');
60
+ }
61
+ return result;
62
+ }
63
+ /**
64
+ * Build scrub patterns from defaults + optional custom regex strings.
65
+ * Invalid custom regexes are silently skipped.
66
+ */
67
+ export function buildPatterns(customRegexes) {
68
+ const patterns = [...DEFAULT_SCRUB_PATTERNS];
69
+ if (customRegexes) {
70
+ for (const raw of customRegexes) {
71
+ try {
72
+ patterns.push({
73
+ name: `custom:${raw}`,
74
+ pattern: new RegExp(raw, 'gi'),
75
+ });
76
+ }
77
+ catch {
78
+ // Invalid regex — skip gracefully
79
+ }
80
+ }
81
+ }
82
+ return patterns;
83
+ }
84
+ //# sourceMappingURL=scrubber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrubber.js","sourceRoot":"","sources":["../../src/runtime/scrubber.ts"],"names":[],"mappings":"AAMA,wEAAwE;AACxE,MAAM,gBAAgB,GAAG,mDAAmD,CAAC;AAE7E,MAAM,CAAC,MAAM,sBAAsB,GAAmB;IACpD;QACE,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,2EAA2E;QACpF,WAAW,EAAE,eAAe;KAC7B;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EACL,yFAAyF;QAC3F,WAAW,EAAE,gBAAgB;KAC9B;IACD;QACE,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,kBAAkB;QAC3B,WAAW,EAAE,cAAc;KAC5B;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,oFAAoF;QAC7F,WAAW,EAAE,eAAe;KAC7B;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAa,EAAE,QAAwB;IAC/D,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrD,IAAI,OAAO,IAAI,KAAK,SAAS,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEvE,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC,EAAE,CAAC;YAC3E,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,GAAW,EAAE,QAAwB;IACxD,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,qCAAqC;QACrC,CAAC,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QACxB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,WAAW,IAAI,YAAY,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,aAAwB;IACpD,MAAM,QAAQ,GAAG,CAAC,GAAG,sBAAsB,CAAC,CAAC;IAE7C,IAAI,aAAa,EAAE,CAAC;QAClB,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,UAAU,GAAG,EAAE;oBACrB,OAAO,EAAE,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC;iBAC/B,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,kCAAkC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scrubber.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrubber.test.d.ts","sourceRoot":"","sources":["../../src/runtime/scrubber.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,72 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { DEFAULT_SCRUB_PATTERNS, buildPatterns, scrubData } from './scrubber.js';
3
+ const patterns = DEFAULT_SCRUB_PATTERNS;
4
+ describe('scrubData', () => {
5
+ it('redacts env var secrets like DB_PASSWORD=hunter2', () => {
6
+ const result = scrubData('DB_PASSWORD=hunter2', patterns);
7
+ expect(result).toBe('DB_PASSWORD=[REDACTED]');
8
+ });
9
+ it('redacts connection strings (keeps user and host, redacts password)', () => {
10
+ const input = 'postgresql://admin:s3cret@db.host:5432/mydb';
11
+ const result = scrubData(input, patterns);
12
+ expect(result).toBe('postgresql://admin:[REDACTED]@db.host:5432/mydb');
13
+ expect(result).not.toContain('s3cret');
14
+ });
15
+ it('redacts Bearer tokens', () => {
16
+ const input = 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.payload.sig';
17
+ const result = scrubData(input, patterns);
18
+ expect(result).toContain('Bearer [REDACTED]');
19
+ expect(result).not.toContain('eyJhbGciOiJIUzI1NiJ9');
20
+ });
21
+ it('redacts values of sensitive object keys', () => {
22
+ const input = { DB_PASSWORD: 'hunter2', host: 'localhost' };
23
+ const result = scrubData(input, patterns);
24
+ expect(result).toEqual({ DB_PASSWORD: '[REDACTED]', host: 'localhost' });
25
+ });
26
+ it('passes through numbers, booleans, and null unchanged', () => {
27
+ expect(scrubData(42, patterns)).toBe(42);
28
+ expect(scrubData(true, patterns)).toBe(true);
29
+ expect(scrubData(null, patterns)).toBe(null);
30
+ expect(scrubData(undefined, patterns)).toBe(undefined);
31
+ });
32
+ it('handles nested objects and arrays recursively', () => {
33
+ const input = {
34
+ config: {
35
+ secrets: [{ API_KEY: 'abc123xyz', name: 'prod' }, 'SECRET_TOKEN=my-token-value'],
36
+ },
37
+ };
38
+ const result = scrubData(input, patterns);
39
+ const config = result.config;
40
+ const secrets = config.secrets;
41
+ expect(secrets[0].API_KEY).toBe('[REDACTED]');
42
+ expect(secrets[0].name).toBe('prod');
43
+ expect(secrets[1]).toBe('SECRET_TOKEN=[REDACTED]');
44
+ });
45
+ it('redacts generic API key patterns', () => {
46
+ const input = 'api_key=abcdef1234567890xx';
47
+ const result = scrubData(input, patterns);
48
+ expect(result).toBe('api_key=[REDACTED]');
49
+ });
50
+ it('does not modify non-sensitive data', () => {
51
+ const input = { hostname: 'server-1', uptime: 12345, healthy: true };
52
+ const result = scrubData(input, patterns);
53
+ expect(result).toEqual(input);
54
+ });
55
+ });
56
+ describe('buildPatterns', () => {
57
+ it('includes default patterns when no custom regexes given', () => {
58
+ const result = buildPatterns();
59
+ expect(result.length).toBe(DEFAULT_SCRUB_PATTERNS.length);
60
+ });
61
+ it('adds valid custom regex patterns', () => {
62
+ const result = buildPatterns(['SSN:\\s*\\d{3}-\\d{2}-\\d{4}']);
63
+ expect(result.length).toBe(DEFAULT_SCRUB_PATTERNS.length + 1);
64
+ const scrubbed = scrubData('SSN: 123-45-6789', result);
65
+ expect(scrubbed).toBe('[REDACTED]');
66
+ });
67
+ it('skips invalid custom regexes gracefully', () => {
68
+ const result = buildPatterns(['[invalid-regex']);
69
+ expect(result.length).toBe(DEFAULT_SCRUB_PATTERNS.length);
70
+ });
71
+ });
72
+ //# sourceMappingURL=scrubber.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrubber.test.js","sourceRoot":"","sources":["../../src/runtime/scrubber.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { PackManifest } from '@sonde/shared';
2
+ export interface ScanResult {
3
+ packName: string;
4
+ detected: boolean;
5
+ matchedCommands: string[];
6
+ matchedFiles: string[];
7
+ matchedServices: string[];
8
+ }
9
+ /** Abstraction for testability */
10
+ export interface SystemChecker {
11
+ commandExists(cmd: string): boolean;
12
+ fileExists(path: string): boolean;
13
+ serviceExists(service: string): boolean;
14
+ }
15
+ /** Real system checker using PATH lookup and fs */
16
+ export declare function createSystemChecker(): SystemChecker;
17
+ /**
18
+ * Scans the system against pack detect rules.
19
+ * Returns a ScanResult per manifest with which checks matched.
20
+ */
21
+ export declare function scanForSoftware(manifests: PackManifest[], checker: SystemChecker): ScanResult[];
22
+ export interface PermissionCheck {
23
+ satisfied: boolean;
24
+ missingGroups: string[];
25
+ missingCommands: string[];
26
+ missingFiles: string[];
27
+ }
28
+ /**
29
+ * Checks if the current user has the required permissions for a pack.
30
+ */
31
+ export declare function checkPackPermissions(manifest: PackManifest, checker: SystemChecker, userGroups: string[]): PermissionCheck;
32
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/system/scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,kCAAkC;AAClC,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACzC;AAED,mDAAmD;AACnD,wBAAgB,mBAAmB,IAAI,aAAa,CAsBnD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,UAAU,EAAE,CAqB/F;AAoCD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,EAAE,GACnB,eAAe,CAajB"}
@@ -0,0 +1,90 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ /** Real system checker using PATH lookup and fs */
4
+ export function createSystemChecker() {
5
+ return {
6
+ commandExists(cmd) {
7
+ try {
8
+ execFileSync('which', [cmd], { stdio: 'ignore' });
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ },
15
+ fileExists(filePath) {
16
+ return fs.existsSync(filePath);
17
+ },
18
+ serviceExists(service) {
19
+ try {
20
+ execFileSync('systemctl', ['cat', service], { stdio: 'ignore' });
21
+ return true;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ },
27
+ };
28
+ }
29
+ /**
30
+ * Scans the system against pack detect rules.
31
+ * Returns a ScanResult per manifest with which checks matched.
32
+ */
33
+ export function scanForSoftware(manifests, checker) {
34
+ const results = [];
35
+ for (const manifest of manifests) {
36
+ const detect = manifest.detect;
37
+ if (!detect) {
38
+ results.push({
39
+ packName: manifest.name,
40
+ detected: false,
41
+ matchedCommands: [],
42
+ matchedFiles: [],
43
+ matchedServices: [],
44
+ });
45
+ continue;
46
+ }
47
+ const result = checkDetectRules(manifest.name, detect, checker);
48
+ results.push(result);
49
+ }
50
+ return results;
51
+ }
52
+ function checkDetectRules(packName, detect, checker) {
53
+ const matchedCommands = [];
54
+ const matchedFiles = [];
55
+ const matchedServices = [];
56
+ for (const cmd of detect.commands ?? []) {
57
+ if (checker.commandExists(cmd)) {
58
+ matchedCommands.push(cmd);
59
+ }
60
+ }
61
+ for (const file of detect.files ?? []) {
62
+ if (checker.fileExists(file)) {
63
+ matchedFiles.push(file);
64
+ }
65
+ }
66
+ for (const service of detect.services ?? []) {
67
+ if (checker.serviceExists(service)) {
68
+ matchedServices.push(service);
69
+ }
70
+ }
71
+ // Detected if at least one check passed
72
+ const detected = matchedCommands.length > 0 || matchedFiles.length > 0 || matchedServices.length > 0;
73
+ return { packName, detected, matchedCommands, matchedFiles, matchedServices };
74
+ }
75
+ /**
76
+ * Checks if the current user has the required permissions for a pack.
77
+ */
78
+ export function checkPackPermissions(manifest, checker, userGroups) {
79
+ const groupSet = new Set(userGroups);
80
+ const missingGroups = manifest.requires.groups.filter((g) => !groupSet.has(g));
81
+ const missingCommands = manifest.requires.commands.filter((c) => !checker.commandExists(c));
82
+ const missingFiles = manifest.requires.files.filter((f) => !checker.fileExists(f));
83
+ return {
84
+ satisfied: missingGroups.length === 0 && missingCommands.length === 0 && missingFiles.length === 0,
85
+ missingGroups,
86
+ missingCommands,
87
+ missingFiles,
88
+ };
89
+ }
90
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/system/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scanner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.test.d.ts","sourceRoot":"","sources":["../../src/system/scanner.test.ts"],"names":[],"mappings":""}