buildhive-agent 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +166 -0
  2. package/dist/__tests__/fakes/FakeDockerManager.d.ts +115 -0
  3. package/dist/__tests__/fakes/FakeDockerManager.d.ts.map +1 -0
  4. package/dist/__tests__/fakes/FakeDockerManager.js +203 -0
  5. package/dist/__tests__/fakes/FakeDockerManager.js.map +1 -0
  6. package/dist/acceptanceChecker.d.ts +26 -0
  7. package/dist/acceptanceChecker.d.ts.map +1 -0
  8. package/dist/acceptanceChecker.js +64 -0
  9. package/dist/acceptanceChecker.js.map +1 -0
  10. package/dist/advancedAgent.d.ts +161 -0
  11. package/dist/advancedAgent.d.ts.map +1 -0
  12. package/dist/advancedAgent.js +604 -0
  13. package/dist/advancedAgent.js.map +1 -0
  14. package/dist/agent.d.ts +101 -0
  15. package/dist/agent.d.ts.map +1 -0
  16. package/dist/agent.js +490 -0
  17. package/dist/agent.js.map +1 -0
  18. package/dist/api/jobStatusApi.d.ts +88 -0
  19. package/dist/api/jobStatusApi.d.ts.map +1 -0
  20. package/dist/api/jobStatusApi.js +240 -0
  21. package/dist/api/jobStatusApi.js.map +1 -0
  22. package/dist/autoUpdater.d.ts +135 -0
  23. package/dist/autoUpdater.d.ts.map +1 -0
  24. package/dist/autoUpdater.js +494 -0
  25. package/dist/autoUpdater.js.map +1 -0
  26. package/dist/cacheManager.d.ts +108 -0
  27. package/dist/cacheManager.d.ts.map +1 -0
  28. package/dist/cacheManager.js +300 -0
  29. package/dist/cacheManager.js.map +1 -0
  30. package/dist/cli.d.ts +11 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +749 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/config/index.d.ts +30 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/config/index.js +35 -0
  37. package/dist/config/index.js.map +1 -0
  38. package/dist/config/loader.d.ts +45 -0
  39. package/dist/config/loader.d.ts.map +1 -0
  40. package/dist/config/loader.js +269 -0
  41. package/dist/config/loader.js.map +1 -0
  42. package/dist/config/types.d.ts +193 -0
  43. package/dist/config/types.d.ts.map +1 -0
  44. package/dist/config/types.js +90 -0
  45. package/dist/config/types.js.map +1 -0
  46. package/dist/config/validation.d.ts +28 -0
  47. package/dist/config/validation.d.ts.map +1 -0
  48. package/dist/config/validation.js +397 -0
  49. package/dist/config/validation.js.map +1 -0
  50. package/dist/docker.d.ts +96 -0
  51. package/dist/docker.d.ts.map +1 -0
  52. package/dist/docker.js +411 -0
  53. package/dist/docker.js.map +1 -0
  54. package/dist/enhancedJobExecutor.d.ts +81 -0
  55. package/dist/enhancedJobExecutor.d.ts.map +1 -0
  56. package/dist/enhancedJobExecutor.js +223 -0
  57. package/dist/enhancedJobExecutor.js.map +1 -0
  58. package/dist/executors/executorFactory.d.ts +46 -0
  59. package/dist/executors/executorFactory.d.ts.map +1 -0
  60. package/dist/executors/executorFactory.js +80 -0
  61. package/dist/executors/executorFactory.js.map +1 -0
  62. package/dist/executors/index.d.ts +7 -0
  63. package/dist/executors/index.d.ts.map +1 -0
  64. package/dist/executors/index.js +6 -0
  65. package/dist/executors/index.js.map +1 -0
  66. package/dist/executors/nativeExecutor.d.ts +60 -0
  67. package/dist/executors/nativeExecutor.d.ts.map +1 -0
  68. package/dist/executors/nativeExecutor.js +311 -0
  69. package/dist/executors/nativeExecutor.js.map +1 -0
  70. package/dist/executors/types.d.ts +38 -0
  71. package/dist/executors/types.d.ts.map +1 -0
  72. package/dist/executors/types.js +9 -0
  73. package/dist/executors/types.js.map +1 -0
  74. package/dist/healthMonitor.d.ts +213 -0
  75. package/dist/healthMonitor.d.ts.map +1 -0
  76. package/dist/healthMonitor.js +547 -0
  77. package/dist/healthMonitor.js.map +1 -0
  78. package/dist/index.d.ts +16 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +16 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/jobExecutor.d.ts +117 -0
  83. package/dist/jobExecutor.d.ts.map +1 -0
  84. package/dist/jobExecutor.js +458 -0
  85. package/dist/jobExecutor.js.map +1 -0
  86. package/dist/lifecycleExecutor.d.ts +54 -0
  87. package/dist/lifecycleExecutor.d.ts.map +1 -0
  88. package/dist/lifecycleExecutor.js +230 -0
  89. package/dist/lifecycleExecutor.js.map +1 -0
  90. package/dist/main.d.ts +15 -0
  91. package/dist/main.d.ts.map +1 -0
  92. package/dist/main.js +77 -0
  93. package/dist/main.js.map +1 -0
  94. package/dist/metrics.d.ts +103 -0
  95. package/dist/metrics.d.ts.map +1 -0
  96. package/dist/metrics.js +360 -0
  97. package/dist/metrics.js.map +1 -0
  98. package/dist/recipes/builtinRecipes.d.ts +11 -0
  99. package/dist/recipes/builtinRecipes.d.ts.map +1 -0
  100. package/dist/recipes/builtinRecipes.js +688 -0
  101. package/dist/recipes/builtinRecipes.js.map +1 -0
  102. package/dist/recipes/index.d.ts +18 -0
  103. package/dist/recipes/index.d.ts.map +1 -0
  104. package/dist/recipes/index.js +17 -0
  105. package/dist/recipes/index.js.map +1 -0
  106. package/dist/recipes/recipeRegistry.d.ts +49 -0
  107. package/dist/recipes/recipeRegistry.d.ts.map +1 -0
  108. package/dist/recipes/recipeRegistry.js +264 -0
  109. package/dist/recipes/recipeRegistry.js.map +1 -0
  110. package/dist/recipes/types.d.ts +116 -0
  111. package/dist/recipes/types.d.ts.map +1 -0
  112. package/dist/recipes/types.js +10 -0
  113. package/dist/recipes/types.js.map +1 -0
  114. package/dist/recovery.d.ts +133 -0
  115. package/dist/recovery.d.ts.map +1 -0
  116. package/dist/recovery.js +299 -0
  117. package/dist/recovery.js.map +1 -0
  118. package/dist/registration/apiClient.d.ts +44 -0
  119. package/dist/registration/apiClient.d.ts.map +1 -0
  120. package/dist/registration/apiClient.js +149 -0
  121. package/dist/registration/apiClient.js.map +1 -0
  122. package/dist/registration/index.d.ts +41 -0
  123. package/dist/registration/index.d.ts.map +1 -0
  124. package/dist/registration/index.js +141 -0
  125. package/dist/registration/index.js.map +1 -0
  126. package/dist/registration/machineId.d.ts +30 -0
  127. package/dist/registration/machineId.d.ts.map +1 -0
  128. package/dist/registration/machineId.js +89 -0
  129. package/dist/registration/machineId.js.map +1 -0
  130. package/dist/registration/types.d.ts +32 -0
  131. package/dist/registration/types.d.ts.map +1 -0
  132. package/dist/registration/types.js +9 -0
  133. package/dist/registration/types.js.map +1 -0
  134. package/dist/resourceGovernor.d.ts +57 -0
  135. package/dist/resourceGovernor.d.ts.map +1 -0
  136. package/dist/resourceGovernor.js +125 -0
  137. package/dist/resourceGovernor.js.map +1 -0
  138. package/dist/security/secretManager.d.ts +107 -0
  139. package/dist/security/secretManager.d.ts.map +1 -0
  140. package/dist/security/secretManager.js +361 -0
  141. package/dist/security/secretManager.js.map +1 -0
  142. package/dist/security.d.ts +134 -0
  143. package/dist/security.d.ts.map +1 -0
  144. package/dist/security.js +470 -0
  145. package/dist/security.js.map +1 -0
  146. package/dist/storage/artifactUploader.d.ts +155 -0
  147. package/dist/storage/artifactUploader.d.ts.map +1 -0
  148. package/dist/storage/artifactUploader.js +554 -0
  149. package/dist/storage/artifactUploader.js.map +1 -0
  150. package/dist/types.d.ts +49 -0
  151. package/dist/types.d.ts.map +1 -0
  152. package/dist/types.js +7 -0
  153. package/dist/types.js.map +1 -0
  154. package/dist/utils/capabilities.d.ts +23 -0
  155. package/dist/utils/capabilities.d.ts.map +1 -0
  156. package/dist/utils/capabilities.js +200 -0
  157. package/dist/utils/capabilities.js.map +1 -0
  158. package/dist/utils/logger.d.ts +20 -0
  159. package/dist/utils/logger.d.ts.map +1 -0
  160. package/dist/utils/logger.js +188 -0
  161. package/dist/utils/logger.js.map +1 -0
  162. package/dist/utils/sdkScanner.d.ts +105 -0
  163. package/dist/utils/sdkScanner.d.ts.map +1 -0
  164. package/dist/utils/sdkScanner.js +459 -0
  165. package/dist/utils/sdkScanner.js.map +1 -0
  166. package/dist/websocketClient.d.ts +154 -0
  167. package/dist/websocketClient.d.ts.map +1 -0
  168. package/dist/websocketClient.js +422 -0
  169. package/dist/websocketClient.js.map +1 -0
  170. package/package.json +64 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Secret Manager
3
+ *
4
+ * Provides encrypted secret storage at rest using AES-256-GCM.
5
+ * Encryption key is derived from machine-specific data + optional passphrase
6
+ * via PBKDF2. Secrets are stored in ~/.buildhive/secrets.enc as a single
7
+ * encrypted blob containing a JSON envelope.
8
+ *
9
+ * Uses ONLY Node.js built-in modules (crypto, fs, path, os).
10
+ */
11
+ import type { AgentConfig } from '../config/types.js';
12
+ export declare class SecretManager {
13
+ private readonly configDir;
14
+ private readonly secretsPath;
15
+ private derivedKey;
16
+ private envelope;
17
+ constructor(configDir?: string);
18
+ /**
19
+ * Initialize the secret manager. If a secrets file already exists it is
20
+ * unlocked (decrypted). Otherwise a new empty vault is created.
21
+ *
22
+ * @param passphrase Optional passphrase. When omitted a machine-derived
23
+ * key is used (less secure but zero-friction for dev).
24
+ */
25
+ initialize(passphrase?: string): Promise<void>;
26
+ /**
27
+ * Store a secret value under the given key.
28
+ */
29
+ setSecret(key: string, value: string): Promise<void>;
30
+ /**
31
+ * Retrieve a secret value. Returns null if the key does not exist.
32
+ */
33
+ getSecret(key: string): Promise<string | null>;
34
+ /**
35
+ * Delete a secret. Returns true if the key existed.
36
+ */
37
+ deleteSecret(key: string): Promise<boolean>;
38
+ /**
39
+ * List all stored secret keys (values are never exposed).
40
+ */
41
+ listSecrets(): Promise<string[]>;
42
+ /**
43
+ * Check whether a secrets file already exists on disk.
44
+ */
45
+ isInitialized(): Promise<boolean>;
46
+ /**
47
+ * Rotate the encryption key by re-encrypting all secrets with a new
48
+ * passphrase. The old passphrase is required to unlock first.
49
+ */
50
+ rotateKey(oldPassphrase: string, newPassphrase: string): Promise<void>;
51
+ private ensureUnlocked;
52
+ /**
53
+ * Derive an encryption key from a passphrase (or machine-id fallback)
54
+ * using PBKDF2. When `existingSalt` is provided, it is reused (unlock
55
+ * path); otherwise a new random salt is generated (create / rotate path).
56
+ */
57
+ private deriveKey;
58
+ /**
59
+ * Returns a machine-specific string used as fallback key material when
60
+ * no passphrase is provided.
61
+ */
62
+ private getMachineMaterial;
63
+ /**
64
+ * Encrypt plaintext using AES-256-GCM.
65
+ */
66
+ private encrypt;
67
+ /**
68
+ * Decrypt ciphertext using AES-256-GCM.
69
+ */
70
+ private decrypt;
71
+ /**
72
+ * Serialize the current envelope to the encrypted file.
73
+ */
74
+ private flush;
75
+ /**
76
+ * Parse the binary secrets file into its component parts.
77
+ */
78
+ private parseFile;
79
+ }
80
+ /**
81
+ * Resolve any `secret:` prefixed values in an AgentConfig by looking them
82
+ * up in the SecretManager. Plain values are returned as-is for backward
83
+ * compatibility.
84
+ *
85
+ * Resolved fields:
86
+ * - config.apiKey
87
+ * - config.storageConfig.s3.accessKeyId
88
+ * - config.storageConfig.s3.secretAccessKey
89
+ */
90
+ export declare function resolveSecrets(config: AgentConfig, passphrase?: string): Promise<AgentConfig>;
91
+ /**
92
+ * Store a secret (for CLI use).
93
+ */
94
+ export declare function secretSet(key: string, value: string, passphrase?: string): Promise<void>;
95
+ /**
96
+ * Retrieve a secret (for CLI use).
97
+ */
98
+ export declare function secretGet(key: string, passphrase?: string): Promise<string | null>;
99
+ /**
100
+ * List all secret keys (for CLI use).
101
+ */
102
+ export declare function secretList(passphrase?: string): Promise<string[]>;
103
+ /**
104
+ * Delete a secret (for CLI use).
105
+ */
106
+ export declare function secretDelete(key: string, passphrase?: string): Promise<boolean>;
107
+ //# sourceMappingURL=secretManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretManager.d.ts","sourceRoot":"","sources":["../../src/security/secretManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA6CtD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,QAAQ,CAAgC;gBAEpC,SAAS,CAAC,EAAE,MAAM;IAS9B;;;;;;OAMG;IACG,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpD;;OAEG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D;;OAEG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKpD;;OAEG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWjD;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAKtC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IASvC;;;OAGG;IACG,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5E,OAAO,CAAC,cAAc;IAMtB;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAqBjB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;OAEG;IACH,OAAO,CAAC,OAAO;IAaf;;OAEG;IACH,OAAO,CAAC,OAAO;IAaf;;OAEG;YACW,KAAK;IAqBnB;;OAEG;IACH,OAAO,CAAC,SAAS;CAqClB;AAMD;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CA2DtB;AAMD;;GAEG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIvE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAIlB"}
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Secret Manager
3
+ *
4
+ * Provides encrypted secret storage at rest using AES-256-GCM.
5
+ * Encryption key is derived from machine-specific data + optional passphrase
6
+ * via PBKDF2. Secrets are stored in ~/.buildhive/secrets.enc as a single
7
+ * encrypted blob containing a JSON envelope.
8
+ *
9
+ * Uses ONLY Node.js built-in modules (crypto, fs, path, os).
10
+ */
11
+ import * as crypto from 'crypto';
12
+ import { promises as fs } from 'fs';
13
+ import * as path from 'path';
14
+ import * as os from 'os';
15
+ // ---------------------------------------------------------------------------
16
+ // Constants
17
+ // ---------------------------------------------------------------------------
18
+ const ALGORITHM = 'aes-256-gcm';
19
+ const KEY_LENGTH = 32; // 256 bits
20
+ const IV_LENGTH = 16; // 128 bits for GCM
21
+ const AUTH_TAG_LENGTH = 16; // 128 bits
22
+ const SALT_LENGTH = 32;
23
+ const PBKDF2_ITERATIONS = 600_000; // OWASP recommendation
24
+ const PBKDF2_DIGEST = 'sha512';
25
+ const SECRETS_FILE_NAME = 'secrets.enc';
26
+ const SECRETS_FILE_MODE = 0o600; // Owner read/write only
27
+ const SECRET_REF_PREFIX = 'secret:';
28
+ const ENVELOPE_VERSION = 1;
29
+ /**
30
+ * Binary file layout (all lengths in bytes):
31
+ * [4] magic bytes "BHSM"
32
+ * [1] format version
33
+ * [32] PBKDF2 salt
34
+ * [16] AES-GCM IV
35
+ * [16] AES-GCM auth tag
36
+ * [*] ciphertext (rest of file)
37
+ */
38
+ const MAGIC = Buffer.from('BHSM');
39
+ const FORMAT_VERSION = 1;
40
+ const HEADER_SIZE = MAGIC.length + 1 + SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH;
41
+ // ---------------------------------------------------------------------------
42
+ // SecretManager
43
+ // ---------------------------------------------------------------------------
44
+ export class SecretManager {
45
+ configDir;
46
+ secretsPath;
47
+ derivedKey = null;
48
+ envelope = null;
49
+ constructor(configDir) {
50
+ this.configDir = configDir ?? path.join(os.homedir(), '.buildhive');
51
+ this.secretsPath = path.join(this.configDir, SECRETS_FILE_NAME);
52
+ }
53
+ // -----------------------------------------------------------------------
54
+ // Public API
55
+ // -----------------------------------------------------------------------
56
+ /**
57
+ * Initialize the secret manager. If a secrets file already exists it is
58
+ * unlocked (decrypted). Otherwise a new empty vault is created.
59
+ *
60
+ * @param passphrase Optional passphrase. When omitted a machine-derived
61
+ * key is used (less secure but zero-friction for dev).
62
+ */
63
+ async initialize(passphrase) {
64
+ const exists = await this.isInitialized();
65
+ if (exists) {
66
+ // Unlock existing vault
67
+ const raw = await fs.readFile(this.secretsPath);
68
+ const { salt, iv, authTag, ciphertext } = this.parseFile(raw);
69
+ this.derivedKey = await this.deriveKey(passphrase, salt);
70
+ const plaintext = this.decrypt(ciphertext, iv, authTag);
71
+ this.envelope = JSON.parse(plaintext);
72
+ }
73
+ else {
74
+ // Create new empty vault
75
+ await fs.mkdir(this.configDir, { recursive: true });
76
+ this.derivedKey = await this.deriveKey(passphrase);
77
+ this.envelope = {
78
+ secrets: {},
79
+ version: ENVELOPE_VERSION,
80
+ updatedAt: new Date().toISOString(),
81
+ };
82
+ await this.flush();
83
+ }
84
+ }
85
+ /**
86
+ * Store a secret value under the given key.
87
+ */
88
+ async setSecret(key, value) {
89
+ this.ensureUnlocked();
90
+ this.envelope.secrets[key] = value;
91
+ this.envelope.updatedAt = new Date().toISOString();
92
+ await this.flush();
93
+ }
94
+ /**
95
+ * Retrieve a secret value. Returns null if the key does not exist.
96
+ */
97
+ async getSecret(key) {
98
+ this.ensureUnlocked();
99
+ return this.envelope.secrets[key] ?? null;
100
+ }
101
+ /**
102
+ * Delete a secret. Returns true if the key existed.
103
+ */
104
+ async deleteSecret(key) {
105
+ this.ensureUnlocked();
106
+ if (!(key in this.envelope.secrets)) {
107
+ return false;
108
+ }
109
+ delete this.envelope.secrets[key];
110
+ this.envelope.updatedAt = new Date().toISOString();
111
+ await this.flush();
112
+ return true;
113
+ }
114
+ /**
115
+ * List all stored secret keys (values are never exposed).
116
+ */
117
+ async listSecrets() {
118
+ this.ensureUnlocked();
119
+ return Object.keys(this.envelope.secrets);
120
+ }
121
+ /**
122
+ * Check whether a secrets file already exists on disk.
123
+ */
124
+ async isInitialized() {
125
+ try {
126
+ await fs.access(this.secretsPath);
127
+ return true;
128
+ }
129
+ catch {
130
+ return false;
131
+ }
132
+ }
133
+ /**
134
+ * Rotate the encryption key by re-encrypting all secrets with a new
135
+ * passphrase. The old passphrase is required to unlock first.
136
+ */
137
+ async rotateKey(oldPassphrase, newPassphrase) {
138
+ // Unlock with old key
139
+ const raw = await fs.readFile(this.secretsPath);
140
+ const { salt, iv, authTag, ciphertext } = this.parseFile(raw);
141
+ const oldKey = await this.deriveKey(oldPassphrase, salt);
142
+ const plaintext = this.decrypt(ciphertext, iv, authTag, oldKey);
143
+ this.envelope = JSON.parse(plaintext);
144
+ // Re-encrypt with new key
145
+ this.derivedKey = await this.deriveKey(newPassphrase);
146
+ this.envelope.updatedAt = new Date().toISOString();
147
+ await this.flush();
148
+ }
149
+ // -----------------------------------------------------------------------
150
+ // Internals
151
+ // -----------------------------------------------------------------------
152
+ ensureUnlocked() {
153
+ if (!this.derivedKey || !this.envelope) {
154
+ throw new Error('SecretManager is not initialized. Call initialize() first.');
155
+ }
156
+ }
157
+ /**
158
+ * Derive an encryption key from a passphrase (or machine-id fallback)
159
+ * using PBKDF2. When `existingSalt` is provided, it is reused (unlock
160
+ * path); otherwise a new random salt is generated (create / rotate path).
161
+ */
162
+ deriveKey(passphrase, existingSalt) {
163
+ const material = passphrase ?? this.getMachineMaterial();
164
+ const salt = existingSalt ?? crypto.randomBytes(SALT_LENGTH);
165
+ return new Promise((resolve, reject) => {
166
+ crypto.pbkdf2(material, salt, PBKDF2_ITERATIONS, KEY_LENGTH, PBKDF2_DIGEST, (err, key) => {
167
+ if (err)
168
+ return reject(err);
169
+ // Attach salt for later storage
170
+ key.__salt = salt;
171
+ resolve(key);
172
+ });
173
+ });
174
+ }
175
+ /**
176
+ * Returns a machine-specific string used as fallback key material when
177
+ * no passphrase is provided.
178
+ */
179
+ getMachineMaterial() {
180
+ const hostname = os.hostname();
181
+ const homedir = os.homedir();
182
+ const platform = os.platform();
183
+ const arch = os.arch();
184
+ return `buildhive:${hostname}:${homedir}:${platform}:${arch}`;
185
+ }
186
+ /**
187
+ * Encrypt plaintext using AES-256-GCM.
188
+ */
189
+ encrypt(plaintext) {
190
+ const iv = crypto.randomBytes(IV_LENGTH);
191
+ const cipher = crypto.createCipheriv(ALGORITHM, this.derivedKey, iv);
192
+ const encrypted = Buffer.concat([
193
+ cipher.update(plaintext, 'utf8'),
194
+ cipher.final(),
195
+ ]);
196
+ const authTag = cipher.getAuthTag();
197
+ return { iv, authTag, ciphertext: encrypted };
198
+ }
199
+ /**
200
+ * Decrypt ciphertext using AES-256-GCM.
201
+ */
202
+ decrypt(ciphertext, iv, authTag, key) {
203
+ const useKey = key ?? this.derivedKey;
204
+ const decipher = crypto.createDecipheriv(ALGORITHM, useKey, iv);
205
+ decipher.setAuthTag(authTag);
206
+ const decrypted = Buffer.concat([
207
+ decipher.update(ciphertext),
208
+ decipher.final(),
209
+ ]);
210
+ return decrypted.toString('utf8');
211
+ }
212
+ /**
213
+ * Serialize the current envelope to the encrypted file.
214
+ */
215
+ async flush() {
216
+ const json = JSON.stringify(this.envelope);
217
+ const { iv, authTag, ciphertext } = this.encrypt(json);
218
+ const salt = this.derivedKey.__salt;
219
+ // Build binary file: MAGIC | VERSION | SALT | IV | AUTH_TAG | CIPHERTEXT
220
+ const header = Buffer.alloc(MAGIC.length + 1 + SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH);
221
+ let offset = 0;
222
+ MAGIC.copy(header, offset);
223
+ offset += MAGIC.length;
224
+ header.writeUInt8(FORMAT_VERSION, offset);
225
+ offset += 1;
226
+ salt.copy(header, offset);
227
+ offset += SALT_LENGTH;
228
+ iv.copy(header, offset);
229
+ offset += IV_LENGTH;
230
+ authTag.copy(header, offset);
231
+ const file = Buffer.concat([header, ciphertext]);
232
+ await fs.mkdir(this.configDir, { recursive: true });
233
+ await fs.writeFile(this.secretsPath, file, { mode: SECRETS_FILE_MODE });
234
+ }
235
+ /**
236
+ * Parse the binary secrets file into its component parts.
237
+ */
238
+ parseFile(raw) {
239
+ if (raw.length < HEADER_SIZE) {
240
+ throw new Error('Secrets file is corrupted: too small');
241
+ }
242
+ let offset = 0;
243
+ const magic = raw.subarray(offset, offset + MAGIC.length);
244
+ offset += MAGIC.length;
245
+ if (!magic.equals(MAGIC)) {
246
+ throw new Error('Secrets file is corrupted: invalid magic bytes');
247
+ }
248
+ const version = raw.readUInt8(offset);
249
+ offset += 1;
250
+ if (version !== FORMAT_VERSION) {
251
+ throw new Error(`Unsupported secrets file version: ${version}`);
252
+ }
253
+ const salt = raw.subarray(offset, offset + SALT_LENGTH);
254
+ offset += SALT_LENGTH;
255
+ const iv = raw.subarray(offset, offset + IV_LENGTH);
256
+ offset += IV_LENGTH;
257
+ const authTag = raw.subarray(offset, offset + AUTH_TAG_LENGTH);
258
+ offset += AUTH_TAG_LENGTH;
259
+ const ciphertext = raw.subarray(offset);
260
+ return { salt, iv, authTag, ciphertext };
261
+ }
262
+ }
263
+ // ---------------------------------------------------------------------------
264
+ // Config integration helper
265
+ // ---------------------------------------------------------------------------
266
+ /**
267
+ * Resolve any `secret:` prefixed values in an AgentConfig by looking them
268
+ * up in the SecretManager. Plain values are returned as-is for backward
269
+ * compatibility.
270
+ *
271
+ * Resolved fields:
272
+ * - config.apiKey
273
+ * - config.storageConfig.s3.accessKeyId
274
+ * - config.storageConfig.s3.secretAccessKey
275
+ */
276
+ export async function resolveSecrets(config, passphrase) {
277
+ // Check whether any field actually needs resolution
278
+ const fieldsToResolve = [];
279
+ if (config.apiKey?.startsWith(SECRET_REF_PREFIX)) {
280
+ fieldsToResolve.push('apiKey');
281
+ }
282
+ if (config.storageConfig?.s3?.accessKeyId?.startsWith(SECRET_REF_PREFIX)) {
283
+ fieldsToResolve.push('s3.accessKeyId');
284
+ }
285
+ if (config.storageConfig?.s3?.secretAccessKey?.startsWith(SECRET_REF_PREFIX)) {
286
+ fieldsToResolve.push('s3.secretAccessKey');
287
+ }
288
+ if (fieldsToResolve.length === 0) {
289
+ return config;
290
+ }
291
+ const sm = new SecretManager();
292
+ await sm.initialize(passphrase);
293
+ // Build a shallow copy so we never mutate the original config
294
+ const resolved = { ...config };
295
+ if (config.apiKey?.startsWith(SECRET_REF_PREFIX)) {
296
+ const key = config.apiKey.slice(SECRET_REF_PREFIX.length);
297
+ const value = await sm.getSecret(key);
298
+ if (value === null) {
299
+ throw new Error(`Secret reference "${key}" not found in SecretManager`);
300
+ }
301
+ resolved.apiKey = value;
302
+ }
303
+ if (config.storageConfig?.s3) {
304
+ const s3 = { ...config.storageConfig.s3 };
305
+ const storage = { ...config.storageConfig, s3 };
306
+ if (s3.accessKeyId?.startsWith(SECRET_REF_PREFIX)) {
307
+ const key = s3.accessKeyId.slice(SECRET_REF_PREFIX.length);
308
+ const value = await sm.getSecret(key);
309
+ if (value === null) {
310
+ throw new Error(`Secret reference "${key}" not found in SecretManager`);
311
+ }
312
+ s3.accessKeyId = value;
313
+ }
314
+ if (s3.secretAccessKey?.startsWith(SECRET_REF_PREFIX)) {
315
+ const key = s3.secretAccessKey.slice(SECRET_REF_PREFIX.length);
316
+ const value = await sm.getSecret(key);
317
+ if (value === null) {
318
+ throw new Error(`Secret reference "${key}" not found in SecretManager`);
319
+ }
320
+ s3.secretAccessKey = value;
321
+ }
322
+ resolved.storageConfig = storage;
323
+ }
324
+ return resolved;
325
+ }
326
+ // ---------------------------------------------------------------------------
327
+ // CLI helper functions
328
+ // ---------------------------------------------------------------------------
329
+ /**
330
+ * Store a secret (for CLI use).
331
+ */
332
+ export async function secretSet(key, value, passphrase) {
333
+ const sm = new SecretManager();
334
+ await sm.initialize(passphrase);
335
+ await sm.setSecret(key, value);
336
+ }
337
+ /**
338
+ * Retrieve a secret (for CLI use).
339
+ */
340
+ export async function secretGet(key, passphrase) {
341
+ const sm = new SecretManager();
342
+ await sm.initialize(passphrase);
343
+ return sm.getSecret(key);
344
+ }
345
+ /**
346
+ * List all secret keys (for CLI use).
347
+ */
348
+ export async function secretList(passphrase) {
349
+ const sm = new SecretManager();
350
+ await sm.initialize(passphrase);
351
+ return sm.listSecrets();
352
+ }
353
+ /**
354
+ * Delete a secret (for CLI use).
355
+ */
356
+ export async function secretDelete(key, passphrase) {
357
+ const sm = new SecretManager();
358
+ await sm.initialize(passphrase);
359
+ return sm.deleteSecret(key);
360
+ }
361
+ //# sourceMappingURL=secretManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretManager.js","sourceRoot":"","sources":["../../src/security/secretManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Security Manager - Enhanced Docker security configuration and validation
3
+ *
4
+ * Provides comprehensive security measures for container execution including
5
+ * resource limits, network isolation, filesystem security, and monitoring.
6
+ *
7
+ * Requirements: 4.1, 4.2, 4.3, 4.4, 4.5
8
+ */
9
+ export interface SecurityConfig {
10
+ maxMemoryMB: number;
11
+ maxCpuCores: number;
12
+ maxDiskSpaceMB: number;
13
+ maxProcesses: number;
14
+ maxFileDescriptors: number;
15
+ networkMode: 'none' | 'bridge';
16
+ allowedOutboundPorts: number[];
17
+ blockPrivateNetworks: boolean;
18
+ readOnlyRoot: boolean;
19
+ allowedWritePaths: string[];
20
+ tempDirSizeMB: number;
21
+ dropAllCapabilities: boolean;
22
+ allowedCapabilities: string[];
23
+ noNewPrivileges: boolean;
24
+ seccompProfile?: string;
25
+ apparmorProfile?: string;
26
+ maxExecutionTimeSeconds: number;
27
+ killTimeoutSeconds: number;
28
+ enableResourceMonitoring: boolean;
29
+ enableSecurityAuditing: boolean;
30
+ logSecurityEvents: boolean;
31
+ }
32
+ export interface SecurityViolation {
33
+ type: 'resource' | 'network' | 'filesystem' | 'capability' | 'execution';
34
+ severity: 'low' | 'medium' | 'high' | 'critical';
35
+ message: string;
36
+ containerId: string;
37
+ timestamp: Date;
38
+ details?: any;
39
+ }
40
+ export interface ResourceUsage {
41
+ memoryUsageMB: number;
42
+ cpuUsagePercent: number;
43
+ diskUsageMB: number;
44
+ processCount: number;
45
+ networkBytesIn: number;
46
+ networkBytesOut: number;
47
+ }
48
+ export declare class SecurityManager {
49
+ private config;
50
+ private violations;
51
+ private resourceMonitors;
52
+ constructor(config: SecurityConfig);
53
+ /**
54
+ * Generate secure Docker arguments for container creation
55
+ */
56
+ generateSecureDockerArgs(containerId: string): string[];
57
+ /**
58
+ * Validate container configuration against security policies
59
+ */
60
+ validateContainerConfig(config: any): Promise<SecurityViolation[]>;
61
+ /**
62
+ * Start resource monitoring for a container
63
+ */
64
+ startResourceMonitoring(containerId: string): Promise<void>;
65
+ /**
66
+ * Stop resource monitoring for a container
67
+ */
68
+ stopResourceMonitoring(containerId: string): void;
69
+ /**
70
+ * Get current resource usage for a container
71
+ */
72
+ getResourceUsage(containerId: string): Promise<ResourceUsage>;
73
+ /**
74
+ * Check if resource usage exceeds limits
75
+ */
76
+ private checkResourceLimits;
77
+ /**
78
+ * Handle execution timeout
79
+ */
80
+ private handleExecutionTimeout;
81
+ /**
82
+ * Create secure temporary directory for container
83
+ */
84
+ createSecureTempDir(containerId: string): Promise<string>;
85
+ /**
86
+ * Clean up secure temporary directory
87
+ */
88
+ cleanupSecureTempDir(tempDir: string): Promise<void>;
89
+ /**
90
+ * Validate Docker image security
91
+ */
92
+ validateImageSecurity(image: string): Promise<SecurityViolation[]>;
93
+ /**
94
+ * Get security violations
95
+ */
96
+ getViolations(): SecurityViolation[];
97
+ /**
98
+ * Clear security violations
99
+ */
100
+ clearViolations(): void;
101
+ /**
102
+ * Record a security violation
103
+ */
104
+ private recordViolation;
105
+ /**
106
+ * Check if a volume mount is unsafe
107
+ */
108
+ private isUnsafeMount;
109
+ /**
110
+ * Check if image is from trusted registry
111
+ */
112
+ private isTrustedImage;
113
+ /**
114
+ * Parse memory limit string to MB
115
+ */
116
+ private parseMemoryLimit;
117
+ /**
118
+ * Parse resource stats output
119
+ */
120
+ private parseResourceStats;
121
+ /**
122
+ * Parse memory usage string
123
+ */
124
+ private parseMemoryUsage;
125
+ /**
126
+ * Execute a system command
127
+ */
128
+ private executeCommand;
129
+ /**
130
+ * Cleanup all monitoring
131
+ */
132
+ cleanup(): void;
133
+ }
134
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}