crewly 1.5.22 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/roles/orchestrator/prompt.md +182 -25
- package/config/skills/agent/core/cancel-followup/SKILL.md +38 -0
- package/config/skills/agent/core/cancel-followup/execute.sh +111 -0
- package/config/skills/agent/core/cancel-followup/execute.test.sh +42 -0
- package/config/skills/agent/core/list-my-followups/SKILL.md +36 -0
- package/config/skills/agent/core/list-my-followups/execute.sh +93 -0
- package/config/skills/agent/core/list-my-followups/execute.test.sh +41 -0
- package/config/skills/agent/core/schedule-followup/SKILL.md +53 -0
- package/config/skills/agent/core/schedule-followup/execute.sh +195 -0
- package/config/skills/agent/core/schedule-followup/execute.test.sh +48 -0
- package/config/skills/agent/core/watch-for-event/SKILL.md +60 -0
- package/config/skills/agent/core/watch-for-event/execute.sh +177 -0
- package/config/skills/agent/core/watch-for-event/execute.test.sh +43 -0
- package/config/skills/orchestrator/credential-manager/SKILL.md +218 -0
- package/config/skills/orchestrator/credential-manager/execute.sh +166 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts +80 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.js +365 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.d.ts +26 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.js +40 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +23 -14
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/scripts/backfill-mission-priority.d.ts +3 -1
- package/dist/backend/backend/src/scripts/backfill-mission-priority.d.ts.map +1 -1
- package/dist/backend/backend/src/scripts/backfill-mission-priority.js +16 -4
- package/dist/backend/backend/src/scripts/backfill-mission-priority.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
- package/dist/backend/backend/src/services/credential/credential-store.service.d.ts +161 -0
- package/dist/backend/backend/src/services/credential/credential-store.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/credential/credential-store.service.js +298 -0
- package/dist/backend/backend/src/services/credential/credential-store.service.js.map +1 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +117 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +293 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -0
- package/dist/backend/backend/src/services/project/task.service.d.ts +18 -2
- package/dist/backend/backend/src/services/project/task.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/task.service.js +69 -53
- package/dist/backend/backend/src/services/project/task.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/contract-matcher.d.ts +20 -0
- package/dist/backend/backend/src/services/v3/contract-matcher.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/contract-matcher.js +33 -0
- package/dist/backend/backend/src/services/v3/contract-matcher.js.map +1 -0
- package/dist/backend/backend/src/services/v3/escalation.service.d.ts +20 -1
- package/dist/backend/backend/src/services/v3/escalation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation.service.js +97 -28
- package/dist/backend/backend/src/services/v3/escalation.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.d.ts +6 -4
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.js +18 -28
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.js +14 -9
- package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts +34 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js +115 -5
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js.map +1 -1
- package/dist/backend/backend/src/types/credential.types.d.ts +185 -0
- package/dist/backend/backend/src/types/credential.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/credential.types.js +76 -0
- package/dist/backend/backend/src/types/credential.types.js.map +1 -0
- package/dist/backend/backend/src/utils/encryption.utils.d.ts +57 -0
- package/dist/backend/backend/src/utils/encryption.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/encryption.utils.js +162 -0
- package/dist/backend/backend/src/utils/encryption.utils.js.map +1 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.d.ts +161 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.js +298 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.js.map +1 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +117 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +293 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -0
- package/dist/cli/backend/src/services/settings/settings.service.d.ts +168 -0
- package/dist/cli/backend/src/services/settings/settings.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/settings/settings.service.js +312 -0
- package/dist/cli/backend/src/services/settings/settings.service.js.map +1 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts +159 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.js +626 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.js.map +1 -0
- package/dist/cli/backend/src/services/skill/skill.service.d.ts +273 -0
- package/dist/cli/backend/src/services/skill/skill.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/skill/skill.service.js +655 -0
- package/dist/cli/backend/src/services/skill/skill.service.js.map +1 -0
- package/dist/cli/backend/src/types/credential.types.d.ts +185 -0
- package/dist/cli/backend/src/types/credential.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/credential.types.js +76 -0
- package/dist/cli/backend/src/types/credential.types.js.map +1 -0
- package/dist/cli/backend/src/utils/encryption.utils.d.ts +57 -0
- package/dist/cli/backend/src/utils/encryption.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/encryption.utils.js +162 -0
- package/dist/cli/backend/src/utils/encryption.utils.js.map +1 -0
- package/dist/cli/backend/src/utils/skill-md-parser.d.ts +38 -0
- package/dist/cli/backend/src/utils/skill-md-parser.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/skill-md-parser.js +47 -0
- package/dist/cli/backend/src/utils/skill-md-parser.js.map +1 -0
- package/frontend/dist/assets/{index-dc92ab64.css → index-6aaa0630.css} +1 -1
- package/frontend/dist/assets/{index-76d76633.js → index-9e6d97d1.js} +334 -328
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/config/experts/empathetic-resolver/expert.json +0 -11
- package/config/experts/empathetic-resolver.md +0 -32
- package/config/experts/pragmatic-architect/expert.json +0 -11
- package/config/experts/pragmatic-architect.md +0 -32
- package/config/experts/viral-alchemist/expert.json +0 -11
- package/config/experts/viral-alchemist.md +0 -32
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential Encryption Utilities
|
|
3
|
+
*
|
|
4
|
+
* AES-256-GCM encryption with scrypt-derived keys for credential payloads.
|
|
5
|
+
* Uses a per-install master.key file (mode 0600) as the base key material.
|
|
6
|
+
*
|
|
7
|
+
* File format:
|
|
8
|
+
* [1 byte: version=1] [12 bytes: IV] [16 bytes: auth tag] [N bytes: ciphertext]
|
|
9
|
+
*
|
|
10
|
+
* Threat model:
|
|
11
|
+
* - Primary defense: file exfiltration via backup / cloud sync / screen capture
|
|
12
|
+
* - NOT a defense against a compromised local user account or malicious code
|
|
13
|
+
* running as the user (both can read master.key and derive the same key)
|
|
14
|
+
*
|
|
15
|
+
* @module utils/encryption.utils
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Clear the derived-key cache. Primarily for tests — production code should
|
|
19
|
+
* not need this as master.key is assumed stable for the process lifetime.
|
|
20
|
+
*/
|
|
21
|
+
export declare function _resetDerivedKeyCache(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Ensure a master.key file exists at the given path. If absent, generate
|
|
24
|
+
* a cryptographically random 32-byte key and write it with mode 0600.
|
|
25
|
+
*
|
|
26
|
+
* Idempotent: if the file already exists, does nothing.
|
|
27
|
+
*
|
|
28
|
+
* @param masterKeyPath - Absolute path to the master.key file
|
|
29
|
+
*/
|
|
30
|
+
export declare function ensureMasterKey(masterKeyPath: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Encrypt a UTF-8 string using AES-256-GCM.
|
|
33
|
+
*
|
|
34
|
+
* @param plaintext - The string to encrypt (caller typically JSON-serializes first)
|
|
35
|
+
* @param masterKeyPath - Absolute path to the master.key file
|
|
36
|
+
* @returns Buffer in the format `[version][iv][tag][ciphertext]`
|
|
37
|
+
*/
|
|
38
|
+
export declare function encrypt(plaintext: string, masterKeyPath: string): Promise<Buffer>;
|
|
39
|
+
/**
|
|
40
|
+
* Decrypt a buffer produced by `encrypt()`.
|
|
41
|
+
*
|
|
42
|
+
* @param encrypted - Buffer in the `[version][iv][tag][ciphertext]` format
|
|
43
|
+
* @param masterKeyPath - Absolute path to the master.key file
|
|
44
|
+
* @returns The decrypted UTF-8 string
|
|
45
|
+
* @throws Error if the buffer is malformed, the version is unsupported,
|
|
46
|
+
* or the auth tag does not match (tampering or wrong key)
|
|
47
|
+
*/
|
|
48
|
+
export declare function decrypt(encrypted: Buffer, masterKeyPath: string): Promise<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Default credentials directory: `~/.crewly/credentials/`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function defaultCredentialsDir(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Default master.key path: `~/.crewly/credentials/master.key`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function defaultMasterKeyPath(): string;
|
|
57
|
+
//# sourceMappingURL=encryption.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.utils.d.ts","sourceRoot":"","sources":["../../../../../backend/src/utils/encryption.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAmEH;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU1E;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential Encryption Utilities
|
|
3
|
+
*
|
|
4
|
+
* AES-256-GCM encryption with scrypt-derived keys for credential payloads.
|
|
5
|
+
* Uses a per-install master.key file (mode 0600) as the base key material.
|
|
6
|
+
*
|
|
7
|
+
* File format:
|
|
8
|
+
* [1 byte: version=1] [12 bytes: IV] [16 bytes: auth tag] [N bytes: ciphertext]
|
|
9
|
+
*
|
|
10
|
+
* Threat model:
|
|
11
|
+
* - Primary defense: file exfiltration via backup / cloud sync / screen capture
|
|
12
|
+
* - NOT a defense against a compromised local user account or malicious code
|
|
13
|
+
* running as the user (both can read master.key and derive the same key)
|
|
14
|
+
*
|
|
15
|
+
* @module utils/encryption.utils
|
|
16
|
+
*/
|
|
17
|
+
import { promises as fs } from 'fs';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import os from 'os';
|
|
20
|
+
import crypto from 'crypto';
|
|
21
|
+
/** File-format version byte — bump if layout changes. */
|
|
22
|
+
const FORMAT_VERSION = 1;
|
|
23
|
+
/** AES-256-GCM uses 12-byte (96-bit) IVs per NIST recommendation. */
|
|
24
|
+
const IV_LENGTH = 12;
|
|
25
|
+
/** AES-GCM produces 16-byte (128-bit) auth tags. */
|
|
26
|
+
const AUTH_TAG_LENGTH = 16;
|
|
27
|
+
/** AES-256 key size. */
|
|
28
|
+
const KEY_LENGTH = 32;
|
|
29
|
+
/** scrypt N (iteration count). 2^15 = 32768. */
|
|
30
|
+
const SCRYPT_N = 32768;
|
|
31
|
+
const SCRYPT_R = 8;
|
|
32
|
+
const SCRYPT_P = 1;
|
|
33
|
+
/**
|
|
34
|
+
* scrypt memory cap. Default in Node is 32MB which is right at the edge for
|
|
35
|
+
* our parameters; give explicit headroom so derivation never fails.
|
|
36
|
+
*/
|
|
37
|
+
const SCRYPT_MAX_MEM = 128 * 1024 * 1024;
|
|
38
|
+
/** Fixed salt — changing invalidates all previously encrypted credentials. */
|
|
39
|
+
const SCRYPT_SALT = Buffer.from('crewly-credentials-v1', 'utf8');
|
|
40
|
+
/**
|
|
41
|
+
* Module-level cache of derived keys, keyed by master.key path. scrypt is
|
|
42
|
+
* intentionally expensive (~100ms per call), so we run it once per master
|
|
43
|
+
* key path per process. Concurrent callers share the in-flight promise.
|
|
44
|
+
*/
|
|
45
|
+
const derivedKeyCache = new Map();
|
|
46
|
+
/**
|
|
47
|
+
* Derive the AES key from the master.key file contents via scrypt. Results
|
|
48
|
+
* are cached by master-key path for the lifetime of the process.
|
|
49
|
+
*
|
|
50
|
+
* @param masterKeyPath - Absolute path to the master.key file
|
|
51
|
+
* @returns A 32-byte derived key
|
|
52
|
+
*/
|
|
53
|
+
async function deriveKey(masterKeyPath) {
|
|
54
|
+
const cached = derivedKeyCache.get(masterKeyPath);
|
|
55
|
+
if (cached)
|
|
56
|
+
return cached;
|
|
57
|
+
const promise = deriveKeyUncached(masterKeyPath).catch((err) => {
|
|
58
|
+
// On failure, remove the rejected promise so the next call retries.
|
|
59
|
+
derivedKeyCache.delete(masterKeyPath);
|
|
60
|
+
throw err;
|
|
61
|
+
});
|
|
62
|
+
derivedKeyCache.set(masterKeyPath, promise);
|
|
63
|
+
return promise;
|
|
64
|
+
}
|
|
65
|
+
async function deriveKeyUncached(masterKeyPath) {
|
|
66
|
+
const masterKey = await fs.readFile(masterKeyPath);
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
crypto.scrypt(masterKey, SCRYPT_SALT, KEY_LENGTH, { N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P, maxmem: SCRYPT_MAX_MEM }, (err, derivedKey) => (err ? reject(err) : resolve(derivedKey)));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Clear the derived-key cache. Primarily for tests — production code should
|
|
73
|
+
* not need this as master.key is assumed stable for the process lifetime.
|
|
74
|
+
*/
|
|
75
|
+
export function _resetDerivedKeyCache() {
|
|
76
|
+
derivedKeyCache.clear();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Ensure a master.key file exists at the given path. If absent, generate
|
|
80
|
+
* a cryptographically random 32-byte key and write it with mode 0600.
|
|
81
|
+
*
|
|
82
|
+
* Idempotent: if the file already exists, does nothing.
|
|
83
|
+
*
|
|
84
|
+
* @param masterKeyPath - Absolute path to the master.key file
|
|
85
|
+
*/
|
|
86
|
+
export async function ensureMasterKey(masterKeyPath) {
|
|
87
|
+
try {
|
|
88
|
+
await fs.access(masterKeyPath);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// File doesn't exist — create it.
|
|
93
|
+
}
|
|
94
|
+
await fs.mkdir(path.dirname(masterKeyPath), { recursive: true });
|
|
95
|
+
const key = crypto.randomBytes(32);
|
|
96
|
+
await fs.writeFile(masterKeyPath, key, { mode: 0o600 });
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Encrypt a UTF-8 string using AES-256-GCM.
|
|
100
|
+
*
|
|
101
|
+
* @param plaintext - The string to encrypt (caller typically JSON-serializes first)
|
|
102
|
+
* @param masterKeyPath - Absolute path to the master.key file
|
|
103
|
+
* @returns Buffer in the format `[version][iv][tag][ciphertext]`
|
|
104
|
+
*/
|
|
105
|
+
export async function encrypt(plaintext, masterKeyPath) {
|
|
106
|
+
const key = await deriveKey(masterKeyPath);
|
|
107
|
+
const iv = crypto.randomBytes(IV_LENGTH);
|
|
108
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
|
|
109
|
+
const ciphertext = Buffer.concat([
|
|
110
|
+
cipher.update(plaintext, 'utf8'),
|
|
111
|
+
cipher.final(),
|
|
112
|
+
]);
|
|
113
|
+
const authTag = cipher.getAuthTag();
|
|
114
|
+
return Buffer.concat([
|
|
115
|
+
Buffer.from([FORMAT_VERSION]),
|
|
116
|
+
iv,
|
|
117
|
+
authTag,
|
|
118
|
+
ciphertext,
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Decrypt a buffer produced by `encrypt()`.
|
|
123
|
+
*
|
|
124
|
+
* @param encrypted - Buffer in the `[version][iv][tag][ciphertext]` format
|
|
125
|
+
* @param masterKeyPath - Absolute path to the master.key file
|
|
126
|
+
* @returns The decrypted UTF-8 string
|
|
127
|
+
* @throws Error if the buffer is malformed, the version is unsupported,
|
|
128
|
+
* or the auth tag does not match (tampering or wrong key)
|
|
129
|
+
*/
|
|
130
|
+
export async function decrypt(encrypted, masterKeyPath) {
|
|
131
|
+
if (encrypted.length < 1 + IV_LENGTH + AUTH_TAG_LENGTH + 1) {
|
|
132
|
+
throw new Error('Encrypted buffer is too short to be valid');
|
|
133
|
+
}
|
|
134
|
+
const version = encrypted[0];
|
|
135
|
+
if (version !== FORMAT_VERSION) {
|
|
136
|
+
throw new Error(`Unsupported encryption format version: ${version}`);
|
|
137
|
+
}
|
|
138
|
+
const iv = encrypted.subarray(1, 1 + IV_LENGTH);
|
|
139
|
+
const authTag = encrypted.subarray(1 + IV_LENGTH, 1 + IV_LENGTH + AUTH_TAG_LENGTH);
|
|
140
|
+
const ciphertext = encrypted.subarray(1 + IV_LENGTH + AUTH_TAG_LENGTH);
|
|
141
|
+
const key = await deriveKey(masterKeyPath);
|
|
142
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
|
|
143
|
+
decipher.setAuthTag(authTag);
|
|
144
|
+
const plaintext = Buffer.concat([
|
|
145
|
+
decipher.update(ciphertext),
|
|
146
|
+
decipher.final(),
|
|
147
|
+
]);
|
|
148
|
+
return plaintext.toString('utf8');
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Default credentials directory: `~/.crewly/credentials/`.
|
|
152
|
+
*/
|
|
153
|
+
export function defaultCredentialsDir() {
|
|
154
|
+
return path.join(os.homedir(), '.crewly', 'credentials');
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Default master.key path: `~/.crewly/credentials/master.key`.
|
|
158
|
+
*/
|
|
159
|
+
export function defaultMasterKeyPath() {
|
|
160
|
+
return path.join(defaultCredentialsDir(), 'master.key');
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=encryption.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.utils.js","sourceRoot":"","sources":["../../../../../backend/src/utils/encryption.utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential Store Service
|
|
3
|
+
*
|
|
4
|
+
* Manages the workspace-level credential registry and per-credential
|
|
5
|
+
* encrypted payload files under `~/.crewly/credentials/`.
|
|
6
|
+
*
|
|
7
|
+
* The store is split into two surfaces:
|
|
8
|
+
*
|
|
9
|
+
* - **Metadata API** (`listCredentials`, `getCredential`, `findCredentialsByProvider`):
|
|
10
|
+
* returns `CredentialRegistryEntry` objects containing only non-secret
|
|
11
|
+
* information (id, name, provider, scopes, email, timestamps). Safe to
|
|
12
|
+
* expose to agent / LLM context and over MCP.
|
|
13
|
+
*
|
|
14
|
+
* - **Payload API** (`getPayload`, `setPayload`): decrypts the per-credential
|
|
15
|
+
* `.enc` file to return the actual token value(s). **Intended only for
|
|
16
|
+
* credential helpers and the skill executor** (which injects values into
|
|
17
|
+
* skill subprocess env vars). Callers must never return payload contents
|
|
18
|
+
* to agent/LLM context.
|
|
19
|
+
*
|
|
20
|
+
* Encrypted file format and threat model: see `utils/encryption.utils.ts`.
|
|
21
|
+
*
|
|
22
|
+
* @module services/credential/credential-store.service
|
|
23
|
+
*/
|
|
24
|
+
import { CredentialRegistryEntry, CredentialPayload, GoogleOAuthPayload, CredentialType, CredentialHelperName, CredentialStatus } from '../../types/credential.types.js';
|
|
25
|
+
/**
|
|
26
|
+
* Arguments for adding an API key credential.
|
|
27
|
+
*/
|
|
28
|
+
export interface AddApiKeyInput {
|
|
29
|
+
/** User-provided display name (must be unique recommended, not enforced). */
|
|
30
|
+
name: string;
|
|
31
|
+
/** Provider identifier (e.g., "gemini", "openai"). */
|
|
32
|
+
provider: string;
|
|
33
|
+
/** The actual API key value — never logged or returned to agent. */
|
|
34
|
+
value: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Arguments for adding an OAuth credential (usually produced by a helper's
|
|
38
|
+
* capture flow).
|
|
39
|
+
*/
|
|
40
|
+
export interface AddOAuthInput {
|
|
41
|
+
/** User-provided display name. */
|
|
42
|
+
name: string;
|
|
43
|
+
/** Provider identifier (e.g., "google"). */
|
|
44
|
+
provider: string;
|
|
45
|
+
/** Which helper manages refresh for this credential. */
|
|
46
|
+
helper: CredentialHelperName;
|
|
47
|
+
/** Full OAuth token payload captured from the helper's login flow. */
|
|
48
|
+
payload: GoogleOAuthPayload;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Updatable metadata fields on a credential. Other fields are managed
|
|
52
|
+
* internally (id, type, provider, encFile, createdAt).
|
|
53
|
+
*/
|
|
54
|
+
export interface UpdateCredentialMetadata {
|
|
55
|
+
name?: string;
|
|
56
|
+
status?: CredentialStatus;
|
|
57
|
+
lastUsedAt?: string;
|
|
58
|
+
expiresAt?: number;
|
|
59
|
+
scopes?: string[];
|
|
60
|
+
accountEmail?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Options for constructing a `CredentialStoreService`. Intended mainly for
|
|
64
|
+
* tests — production uses the default paths under `~/.crewly/credentials/`.
|
|
65
|
+
*/
|
|
66
|
+
export interface CredentialStoreOptions {
|
|
67
|
+
/** Override the credentials directory (default: `~/.crewly/credentials`). */
|
|
68
|
+
dir?: string;
|
|
69
|
+
/** Override the master.key file path (default: `<dir>/master.key`). */
|
|
70
|
+
masterKeyPath?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* File-based credential store.
|
|
74
|
+
*/
|
|
75
|
+
export declare class CredentialStoreService {
|
|
76
|
+
private readonly dir;
|
|
77
|
+
private readonly registryPath;
|
|
78
|
+
private readonly masterKeyPath;
|
|
79
|
+
private initialized;
|
|
80
|
+
constructor(options?: CredentialStoreOptions);
|
|
81
|
+
/**
|
|
82
|
+
* Ensure the credentials directory and master.key exist. Called
|
|
83
|
+
* automatically by every public method — safe to invoke explicitly
|
|
84
|
+
* for eager initialization.
|
|
85
|
+
*/
|
|
86
|
+
init(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* List all credentials' metadata. Does not include secret values.
|
|
89
|
+
*/
|
|
90
|
+
listCredentials(): Promise<CredentialRegistryEntry[]>;
|
|
91
|
+
/**
|
|
92
|
+
* Get a single credential's metadata by id.
|
|
93
|
+
*
|
|
94
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
95
|
+
*/
|
|
96
|
+
getCredential(id: string): Promise<CredentialRegistryEntry>;
|
|
97
|
+
/**
|
|
98
|
+
* Find all credentials for a given provider, optionally filtered by type.
|
|
99
|
+
*/
|
|
100
|
+
findCredentialsByProvider(provider: string, type?: CredentialType): Promise<CredentialRegistryEntry[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Add a new API key credential. The value is encrypted on disk and
|
|
103
|
+
* never exposed back through the metadata API.
|
|
104
|
+
*/
|
|
105
|
+
addApiKey(input: AddApiKeyInput): Promise<CredentialRegistryEntry>;
|
|
106
|
+
/**
|
|
107
|
+
* Add a new OAuth credential. Typically called by a helper's capture
|
|
108
|
+
* flow after completing an OAuth exchange.
|
|
109
|
+
*/
|
|
110
|
+
addOAuth(input: AddOAuthInput): Promise<CredentialRegistryEntry>;
|
|
111
|
+
/**
|
|
112
|
+
* Update a credential's metadata. Does not touch the encrypted payload.
|
|
113
|
+
* Use `setPayload` to rewrite the secret material (e.g., after refresh).
|
|
114
|
+
*
|
|
115
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
116
|
+
*/
|
|
117
|
+
updateCredential(id: string, patch: UpdateCredentialMetadata): Promise<CredentialRegistryEntry>;
|
|
118
|
+
/**
|
|
119
|
+
* Delete a credential (removes registry entry and encrypted payload).
|
|
120
|
+
* The registry removal is authoritative — if the `.enc` file is missing
|
|
121
|
+
* for any reason, that is not an error.
|
|
122
|
+
*
|
|
123
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
124
|
+
*/
|
|
125
|
+
deleteCredential(id: string): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Decrypt and return the credential's payload. **Do not return the
|
|
128
|
+
* result to agent / LLM contexts** — intended only for helpers
|
|
129
|
+
* refreshing tokens and the skill executor injecting env vars.
|
|
130
|
+
*
|
|
131
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
132
|
+
*/
|
|
133
|
+
getPayload(id: string): Promise<CredentialPayload>;
|
|
134
|
+
/**
|
|
135
|
+
* Encrypt and write a new payload for an existing credential. Used by
|
|
136
|
+
* helpers after a successful token refresh.
|
|
137
|
+
*
|
|
138
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
139
|
+
*/
|
|
140
|
+
setPayload(id: string, payload: CredentialPayload): Promise<void>;
|
|
141
|
+
private readRegistry;
|
|
142
|
+
private writeRegistry;
|
|
143
|
+
private appendEntry;
|
|
144
|
+
private encFilePath;
|
|
145
|
+
private writePayload;
|
|
146
|
+
private newId;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get the process-wide CredentialStoreService singleton.
|
|
150
|
+
*/
|
|
151
|
+
export declare function getCredentialStoreService(): CredentialStoreService;
|
|
152
|
+
/**
|
|
153
|
+
* Reset the singleton — for tests only.
|
|
154
|
+
*/
|
|
155
|
+
export declare function resetCredentialStoreService(): void;
|
|
156
|
+
/**
|
|
157
|
+
* Replace the singleton with a specific instance — for tests only.
|
|
158
|
+
* Allows route/controller tests to point the store at a scratch directory.
|
|
159
|
+
*/
|
|
160
|
+
export declare function _setCredentialStoreForTesting(svc: CredentialStoreService): void;
|
|
161
|
+
//# sourceMappingURL=credential-store.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-store.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/credential/credential-store.service.ts"],"names":[],"mappings":"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"}
|