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.
- package/README.md +166 -0
- package/dist/__tests__/fakes/FakeDockerManager.d.ts +115 -0
- package/dist/__tests__/fakes/FakeDockerManager.d.ts.map +1 -0
- package/dist/__tests__/fakes/FakeDockerManager.js +203 -0
- package/dist/__tests__/fakes/FakeDockerManager.js.map +1 -0
- package/dist/acceptanceChecker.d.ts +26 -0
- package/dist/acceptanceChecker.d.ts.map +1 -0
- package/dist/acceptanceChecker.js +64 -0
- package/dist/acceptanceChecker.js.map +1 -0
- package/dist/advancedAgent.d.ts +161 -0
- package/dist/advancedAgent.d.ts.map +1 -0
- package/dist/advancedAgent.js +604 -0
- package/dist/advancedAgent.js.map +1 -0
- package/dist/agent.d.ts +101 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +490 -0
- package/dist/agent.js.map +1 -0
- package/dist/api/jobStatusApi.d.ts +88 -0
- package/dist/api/jobStatusApi.d.ts.map +1 -0
- package/dist/api/jobStatusApi.js +240 -0
- package/dist/api/jobStatusApi.js.map +1 -0
- package/dist/autoUpdater.d.ts +135 -0
- package/dist/autoUpdater.d.ts.map +1 -0
- package/dist/autoUpdater.js +494 -0
- package/dist/autoUpdater.js.map +1 -0
- package/dist/cacheManager.d.ts +108 -0
- package/dist/cacheManager.d.ts.map +1 -0
- package/dist/cacheManager.js +300 -0
- package/dist/cacheManager.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +749 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +30 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +35 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +45 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +269 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +193 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +90 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validation.d.ts +28 -0
- package/dist/config/validation.d.ts.map +1 -0
- package/dist/config/validation.js +397 -0
- package/dist/config/validation.js.map +1 -0
- package/dist/docker.d.ts +96 -0
- package/dist/docker.d.ts.map +1 -0
- package/dist/docker.js +411 -0
- package/dist/docker.js.map +1 -0
- package/dist/enhancedJobExecutor.d.ts +81 -0
- package/dist/enhancedJobExecutor.d.ts.map +1 -0
- package/dist/enhancedJobExecutor.js +223 -0
- package/dist/enhancedJobExecutor.js.map +1 -0
- package/dist/executors/executorFactory.d.ts +46 -0
- package/dist/executors/executorFactory.d.ts.map +1 -0
- package/dist/executors/executorFactory.js +80 -0
- package/dist/executors/executorFactory.js.map +1 -0
- package/dist/executors/index.d.ts +7 -0
- package/dist/executors/index.d.ts.map +1 -0
- package/dist/executors/index.js +6 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/nativeExecutor.d.ts +60 -0
- package/dist/executors/nativeExecutor.d.ts.map +1 -0
- package/dist/executors/nativeExecutor.js +311 -0
- package/dist/executors/nativeExecutor.js.map +1 -0
- package/dist/executors/types.d.ts +38 -0
- package/dist/executors/types.d.ts.map +1 -0
- package/dist/executors/types.js +9 -0
- package/dist/executors/types.js.map +1 -0
- package/dist/healthMonitor.d.ts +213 -0
- package/dist/healthMonitor.d.ts.map +1 -0
- package/dist/healthMonitor.js +547 -0
- package/dist/healthMonitor.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/jobExecutor.d.ts +117 -0
- package/dist/jobExecutor.d.ts.map +1 -0
- package/dist/jobExecutor.js +458 -0
- package/dist/jobExecutor.js.map +1 -0
- package/dist/lifecycleExecutor.d.ts +54 -0
- package/dist/lifecycleExecutor.d.ts.map +1 -0
- package/dist/lifecycleExecutor.js +230 -0
- package/dist/lifecycleExecutor.js.map +1 -0
- package/dist/main.d.ts +15 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +77 -0
- package/dist/main.js.map +1 -0
- package/dist/metrics.d.ts +103 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +360 -0
- package/dist/metrics.js.map +1 -0
- package/dist/recipes/builtinRecipes.d.ts +11 -0
- package/dist/recipes/builtinRecipes.d.ts.map +1 -0
- package/dist/recipes/builtinRecipes.js +688 -0
- package/dist/recipes/builtinRecipes.js.map +1 -0
- package/dist/recipes/index.d.ts +18 -0
- package/dist/recipes/index.d.ts.map +1 -0
- package/dist/recipes/index.js +17 -0
- package/dist/recipes/index.js.map +1 -0
- package/dist/recipes/recipeRegistry.d.ts +49 -0
- package/dist/recipes/recipeRegistry.d.ts.map +1 -0
- package/dist/recipes/recipeRegistry.js +264 -0
- package/dist/recipes/recipeRegistry.js.map +1 -0
- package/dist/recipes/types.d.ts +116 -0
- package/dist/recipes/types.d.ts.map +1 -0
- package/dist/recipes/types.js +10 -0
- package/dist/recipes/types.js.map +1 -0
- package/dist/recovery.d.ts +133 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +299 -0
- package/dist/recovery.js.map +1 -0
- package/dist/registration/apiClient.d.ts +44 -0
- package/dist/registration/apiClient.d.ts.map +1 -0
- package/dist/registration/apiClient.js +149 -0
- package/dist/registration/apiClient.js.map +1 -0
- package/dist/registration/index.d.ts +41 -0
- package/dist/registration/index.d.ts.map +1 -0
- package/dist/registration/index.js +141 -0
- package/dist/registration/index.js.map +1 -0
- package/dist/registration/machineId.d.ts +30 -0
- package/dist/registration/machineId.d.ts.map +1 -0
- package/dist/registration/machineId.js +89 -0
- package/dist/registration/machineId.js.map +1 -0
- package/dist/registration/types.d.ts +32 -0
- package/dist/registration/types.d.ts.map +1 -0
- package/dist/registration/types.js +9 -0
- package/dist/registration/types.js.map +1 -0
- package/dist/resourceGovernor.d.ts +57 -0
- package/dist/resourceGovernor.d.ts.map +1 -0
- package/dist/resourceGovernor.js +125 -0
- package/dist/resourceGovernor.js.map +1 -0
- package/dist/security/secretManager.d.ts +107 -0
- package/dist/security/secretManager.d.ts.map +1 -0
- package/dist/security/secretManager.js +361 -0
- package/dist/security/secretManager.js.map +1 -0
- package/dist/security.d.ts +134 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +470 -0
- package/dist/security.js.map +1 -0
- package/dist/storage/artifactUploader.d.ts +155 -0
- package/dist/storage/artifactUploader.d.ts.map +1 -0
- package/dist/storage/artifactUploader.js +554 -0
- package/dist/storage/artifactUploader.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/capabilities.d.ts +23 -0
- package/dist/utils/capabilities.d.ts.map +1 -0
- package/dist/utils/capabilities.js +200 -0
- package/dist/utils/capabilities.js.map +1 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +188 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/sdkScanner.d.ts +105 -0
- package/dist/utils/sdkScanner.d.ts.map +1 -0
- package/dist/utils/sdkScanner.js +459 -0
- package/dist/utils/sdkScanner.js.map +1 -0
- package/dist/websocketClient.d.ts +154 -0
- package/dist/websocketClient.d.ts.map +1 -0
- package/dist/websocketClient.js +422 -0
- package/dist/websocketClient.js.map +1 -0
- 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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"}
|