proofscan 0.7.2 → 0.7.3
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/dist/cli.js +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/secrets.d.ts +19 -0
- package/dist/commands/secrets.d.ts.map +1 -0
- package/dist/commands/secrets.js +387 -0
- package/dist/commands/secrets.js.map +1 -0
- package/dist/secrets/index.d.ts +2 -0
- package/dist/secrets/index.d.ts.map +1 -1
- package/dist/secrets/index.js +4 -0
- package/dist/secrets/index.js.map +1 -1
- package/dist/secrets/management.d.ts +112 -0
- package/dist/secrets/management.d.ts.map +1 -0
- package/dist/secrets/management.js +488 -0
- package/dist/secrets/management.js.map +1 -0
- package/dist/secrets/resolve.d.ts +51 -0
- package/dist/secrets/resolve.d.ts.map +1 -0
- package/dist/secrets/resolve.js +113 -0
- package/dist/secrets/resolve.js.map +1 -0
- package/dist/secrets/store.d.ts +4 -0
- package/dist/secrets/store.d.ts.map +1 -1
- package/dist/secrets/store.js +12 -0
- package/dist/secrets/store.js.map +1 -1
- package/dist/secrets/types.d.ts +1 -1
- package/dist/secrets/types.d.ts.map +1 -1
- package/dist/secrets/types.js +2 -2
- package/dist/secrets/types.js.map +1 -1
- package/dist/utils/clipboard.d.ts +4 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +6 -0
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/secret-input.d.ts +22 -0
- package/dist/utils/secret-input.d.ts.map +1 -0
- package/dist/utils/secret-input.js +84 -0
- package/dist/utils/secret-input.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets management utilities (Phase 3.6)
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for:
|
|
5
|
+
* - Listing secrets with bindings
|
|
6
|
+
* - Setting/updating secrets
|
|
7
|
+
* - Pruning orphan secrets
|
|
8
|
+
* - Export/import encrypted bundles
|
|
9
|
+
*
|
|
10
|
+
* Security: Never logs, prints, or writes plaintext secrets.
|
|
11
|
+
*/
|
|
12
|
+
import { type ProviderType } from './types.js';
|
|
13
|
+
/** Information about a secret and its binding */
|
|
14
|
+
export interface SecretBindingInfo {
|
|
15
|
+
/** Secret reference (dpapi:xxx, plain:xxx) */
|
|
16
|
+
secret_ref: string;
|
|
17
|
+
/** Secret ID */
|
|
18
|
+
secret_id: string;
|
|
19
|
+
/** Connector ID (if bound) */
|
|
20
|
+
connector_id?: string;
|
|
21
|
+
/** Environment key (if bound) */
|
|
22
|
+
env_key?: string;
|
|
23
|
+
/** Provider type */
|
|
24
|
+
provider: ProviderType;
|
|
25
|
+
/** Creation timestamp */
|
|
26
|
+
created_at: string;
|
|
27
|
+
/** Last used timestamp (if tracked) */
|
|
28
|
+
last_used_at?: string;
|
|
29
|
+
/** Status: OK (bound), ORPHAN (not bound), MISSING (ref in config but not in store) */
|
|
30
|
+
status: 'OK' | 'ORPHAN' | 'MISSING';
|
|
31
|
+
}
|
|
32
|
+
/** Options for setting a secret */
|
|
33
|
+
export interface SetSecretOptions {
|
|
34
|
+
configPath: string;
|
|
35
|
+
connectorId: string;
|
|
36
|
+
envKey: string;
|
|
37
|
+
secretValue: string;
|
|
38
|
+
}
|
|
39
|
+
/** Result of setting a secret */
|
|
40
|
+
export interface SetSecretResult {
|
|
41
|
+
secretRef: string;
|
|
42
|
+
secretId: string;
|
|
43
|
+
updated: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** Options for pruning secrets */
|
|
46
|
+
export interface PruneOptions {
|
|
47
|
+
configDir: string;
|
|
48
|
+
configPath: string;
|
|
49
|
+
dryRun?: boolean;
|
|
50
|
+
olderThanDays?: number;
|
|
51
|
+
}
|
|
52
|
+
/** Result of pruning secrets */
|
|
53
|
+
export interface PruneResult {
|
|
54
|
+
orphanCount: number;
|
|
55
|
+
removedCount: number;
|
|
56
|
+
removedIds: string[];
|
|
57
|
+
}
|
|
58
|
+
/** Options for exporting secrets */
|
|
59
|
+
export interface ExportOptions {
|
|
60
|
+
configDir: string;
|
|
61
|
+
configPath: string;
|
|
62
|
+
outputPath: string;
|
|
63
|
+
passphrase: string;
|
|
64
|
+
}
|
|
65
|
+
/** Result of exporting secrets */
|
|
66
|
+
export interface ExportResult {
|
|
67
|
+
exportedCount: number;
|
|
68
|
+
}
|
|
69
|
+
/** Options for importing secrets */
|
|
70
|
+
export interface ImportOptions {
|
|
71
|
+
configDir: string;
|
|
72
|
+
configPath: string;
|
|
73
|
+
inputPath: string;
|
|
74
|
+
passphrase: string;
|
|
75
|
+
overwrite?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** Error detail for import failures */
|
|
78
|
+
export interface ImportError {
|
|
79
|
+
connector_id: string;
|
|
80
|
+
env_key: string;
|
|
81
|
+
error: string;
|
|
82
|
+
}
|
|
83
|
+
/** Result of importing secrets */
|
|
84
|
+
export interface ImportResult {
|
|
85
|
+
importedCount: number;
|
|
86
|
+
skippedCount: number;
|
|
87
|
+
errorCount: number;
|
|
88
|
+
/** Details about individual import failures */
|
|
89
|
+
errors?: ImportError[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* List all secrets with their binding information
|
|
93
|
+
*/
|
|
94
|
+
export declare function listSecretBindings(configDir: string, configPath: string): Promise<SecretBindingInfo[]>;
|
|
95
|
+
/**
|
|
96
|
+
* Set a secret value for a connector environment variable
|
|
97
|
+
* Uses file locking to prevent race conditions during concurrent access.
|
|
98
|
+
*/
|
|
99
|
+
export declare function setSecret(options: SetSecretOptions): Promise<SetSecretResult>;
|
|
100
|
+
/**
|
|
101
|
+
* Remove orphan secrets not referenced by config
|
|
102
|
+
*/
|
|
103
|
+
export declare function pruneOrphanSecrets(options: PruneOptions): Promise<PruneResult>;
|
|
104
|
+
/**
|
|
105
|
+
* Export secrets to encrypted bundle file
|
|
106
|
+
*/
|
|
107
|
+
export declare function exportSecrets(options: ExportOptions): Promise<ExportResult>;
|
|
108
|
+
/**
|
|
109
|
+
* Import secrets from encrypted bundle file
|
|
110
|
+
*/
|
|
111
|
+
export declare function importSecrets(options: ImportOptions): Promise<ImportResult>;
|
|
112
|
+
//# sourceMappingURL=management.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"management.d.ts","sourceRoot":"","sources":["../../src/secrets/management.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets management utilities (Phase 3.6)
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for:
|
|
5
|
+
* - Listing secrets with bindings
|
|
6
|
+
* - Setting/updating secrets
|
|
7
|
+
* - Pruning orphan secrets
|
|
8
|
+
* - Export/import encrypted bundles
|
|
9
|
+
*
|
|
10
|
+
* Security: Never logs, prints, or writes plaintext secrets.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, openSync, closeSync, renameSync } from 'fs';
|
|
13
|
+
import { dirname } from 'path';
|
|
14
|
+
import { randomBytes, createCipheriv, createDecipheriv, scryptSync, createHmac, timingSafeEqual } from 'crypto';
|
|
15
|
+
import { SqliteSecretStore } from './store.js';
|
|
16
|
+
import { parseSecretRef, makeSecretRef } from './types.js';
|
|
17
|
+
// ============================================================
|
|
18
|
+
// Crypto utilities
|
|
19
|
+
// ============================================================
|
|
20
|
+
const SCRYPT_N = 2 ** 14; // CPU/memory cost (16384 - compatible with low-memory environments)
|
|
21
|
+
const SCRYPT_R = 8;
|
|
22
|
+
const SCRYPT_P = 1;
|
|
23
|
+
const KEY_LEN = 32; // 256 bits
|
|
24
|
+
function deriveKey(passphrase, salt) {
|
|
25
|
+
return scryptSync(passphrase, salt, KEY_LEN, {
|
|
26
|
+
N: SCRYPT_N,
|
|
27
|
+
r: SCRYPT_R,
|
|
28
|
+
p: SCRYPT_P,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function encryptPayload(plaintext, key) {
|
|
32
|
+
const iv = randomBytes(12); // 96 bits for GCM
|
|
33
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
34
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
35
|
+
const authTag = cipher.getAuthTag();
|
|
36
|
+
return { iv, authTag, ciphertext };
|
|
37
|
+
}
|
|
38
|
+
function decryptPayload(ciphertext, key, iv, authTag) {
|
|
39
|
+
const decipher = createDecipheriv('aes-256-gcm', key, iv);
|
|
40
|
+
decipher.setAuthTag(authTag);
|
|
41
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
42
|
+
}
|
|
43
|
+
// ============================================================
|
|
44
|
+
// File locking utilities
|
|
45
|
+
// ============================================================
|
|
46
|
+
const LOCK_TIMEOUT_MS = 10000; // 10 seconds
|
|
47
|
+
const LOCK_RETRY_INTERVAL_MS = 100;
|
|
48
|
+
/**
|
|
49
|
+
* Acquire exclusive lock on config file
|
|
50
|
+
* Uses a .lock file mechanism for cross-process safety
|
|
51
|
+
*/
|
|
52
|
+
async function acquireConfigLock(configPath) {
|
|
53
|
+
const lockPath = `${configPath}.lock`;
|
|
54
|
+
const startTime = Date.now();
|
|
55
|
+
while (Date.now() - startTime < LOCK_TIMEOUT_MS) {
|
|
56
|
+
try {
|
|
57
|
+
// O_CREAT | O_EXCL - fails if file already exists (atomic check-and-create)
|
|
58
|
+
const fd = openSync(lockPath, 'wx');
|
|
59
|
+
closeSync(fd);
|
|
60
|
+
return lockPath;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (err.code === 'EEXIST') {
|
|
64
|
+
// Lock exists, wait and retry
|
|
65
|
+
await new Promise(resolve => setTimeout(resolve, LOCK_RETRY_INTERVAL_MS));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Failed to acquire lock on ${configPath} (timeout after ${LOCK_TIMEOUT_MS}ms)`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Release config file lock
|
|
76
|
+
*/
|
|
77
|
+
function releaseConfigLock(lockPath) {
|
|
78
|
+
try {
|
|
79
|
+
unlinkSync(lockPath);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Ignore errors (lock may have been removed by timeout)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Read and write config file atomically with file locking
|
|
87
|
+
*/
|
|
88
|
+
async function withConfigLock(configPath, operation) {
|
|
89
|
+
const lockPath = await acquireConfigLock(configPath);
|
|
90
|
+
const tempPath = `${configPath}.tmp`;
|
|
91
|
+
try {
|
|
92
|
+
// Read current config
|
|
93
|
+
if (!existsSync(configPath)) {
|
|
94
|
+
throw new Error(`Config file not found: ${configPath}`);
|
|
95
|
+
}
|
|
96
|
+
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
97
|
+
// Execute operation
|
|
98
|
+
const { config: updatedConfig, result } = await operation(config);
|
|
99
|
+
// Write atomically: write to temp file first, then rename to original
|
|
100
|
+
writeFileSync(tempPath, JSON.stringify(updatedConfig, null, 2));
|
|
101
|
+
renameSync(tempPath, configPath);
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
// Clean up temp file if it exists
|
|
106
|
+
try {
|
|
107
|
+
if (existsSync(tempPath)) {
|
|
108
|
+
unlinkSync(tempPath);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Ignore cleanup errors
|
|
113
|
+
}
|
|
114
|
+
releaseConfigLock(lockPath);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// ============================================================
|
|
118
|
+
// Helper functions
|
|
119
|
+
// ============================================================
|
|
120
|
+
/** Extract all secret refs from config */
|
|
121
|
+
function collectConfigSecretRefs(config) {
|
|
122
|
+
const refs = new Map();
|
|
123
|
+
for (const connector of config.connectors || []) {
|
|
124
|
+
const env = connector.transport?.env;
|
|
125
|
+
if (!env)
|
|
126
|
+
continue;
|
|
127
|
+
for (const [key, value] of Object.entries(env)) {
|
|
128
|
+
const parsed = parseSecretRef(value);
|
|
129
|
+
if (parsed) {
|
|
130
|
+
refs.set(parsed.id, { connectorId: connector.id, envKey: key });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return refs;
|
|
135
|
+
}
|
|
136
|
+
// ============================================================
|
|
137
|
+
// Management functions
|
|
138
|
+
// ============================================================
|
|
139
|
+
/**
|
|
140
|
+
* List all secrets with their binding information
|
|
141
|
+
*/
|
|
142
|
+
export async function listSecretBindings(configDir, configPath) {
|
|
143
|
+
const results = [];
|
|
144
|
+
const store = new SqliteSecretStore(configDir);
|
|
145
|
+
try {
|
|
146
|
+
// Get all secret IDs from store
|
|
147
|
+
const secretIds = await store.list();
|
|
148
|
+
// Load config to find bindings
|
|
149
|
+
let config = { version: 1, connectors: [] };
|
|
150
|
+
if (existsSync(configPath)) {
|
|
151
|
+
config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
152
|
+
}
|
|
153
|
+
const configRefs = collectConfigSecretRefs(config);
|
|
154
|
+
// Build binding info for each secret
|
|
155
|
+
for (const id of secretIds) {
|
|
156
|
+
const binding = configRefs.get(id);
|
|
157
|
+
const createdAt = await store.getCreatedAt(id);
|
|
158
|
+
// Determine provider from meta or try to get from store
|
|
159
|
+
let provider = 'plain';
|
|
160
|
+
// We need to get the record to know the provider
|
|
161
|
+
// For now, use the store's provider type
|
|
162
|
+
provider = store.getProviderType();
|
|
163
|
+
results.push({
|
|
164
|
+
secret_ref: makeSecretRef(provider, id),
|
|
165
|
+
secret_id: id,
|
|
166
|
+
connector_id: binding?.connectorId,
|
|
167
|
+
env_key: binding?.envKey,
|
|
168
|
+
provider,
|
|
169
|
+
created_at: createdAt?.toISOString() ?? new Date().toISOString(),
|
|
170
|
+
status: binding ? 'OK' : 'ORPHAN',
|
|
171
|
+
});
|
|
172
|
+
// Remove from configRefs to track what we've seen
|
|
173
|
+
configRefs.delete(id);
|
|
174
|
+
}
|
|
175
|
+
// Any remaining configRefs are MISSING (in config but not in store)
|
|
176
|
+
for (const [id, binding] of configRefs) {
|
|
177
|
+
results.push({
|
|
178
|
+
secret_ref: `unknown:${id}`,
|
|
179
|
+
secret_id: id,
|
|
180
|
+
connector_id: binding.connectorId,
|
|
181
|
+
env_key: binding.envKey,
|
|
182
|
+
provider: 'plain',
|
|
183
|
+
created_at: '',
|
|
184
|
+
status: 'MISSING',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return results;
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
store.close();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Set a secret value for a connector environment variable
|
|
195
|
+
* Uses file locking to prevent race conditions during concurrent access.
|
|
196
|
+
*/
|
|
197
|
+
export async function setSecret(options) {
|
|
198
|
+
const { configPath, connectorId, envKey, secretValue } = options;
|
|
199
|
+
const configDir = dirname(configPath);
|
|
200
|
+
// Store the secret first (outside the lock to minimize lock time)
|
|
201
|
+
const store = new SqliteSecretStore(configDir);
|
|
202
|
+
let storeResult;
|
|
203
|
+
try {
|
|
204
|
+
storeResult = await store.store(secretValue, {
|
|
205
|
+
connectorId,
|
|
206
|
+
keyName: envKey,
|
|
207
|
+
source: `${connectorId}.transport.env.${envKey}`,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
store.close();
|
|
212
|
+
}
|
|
213
|
+
// Update config with file locking
|
|
214
|
+
return withConfigLock(configPath, async (config) => {
|
|
215
|
+
// Find connector
|
|
216
|
+
const connector = config.connectors?.find(c => c.id === connectorId);
|
|
217
|
+
if (!connector) {
|
|
218
|
+
throw new Error(`Connector not found: ${connectorId}`);
|
|
219
|
+
}
|
|
220
|
+
// Ensure transport.env exists
|
|
221
|
+
if (!connector.transport) {
|
|
222
|
+
connector.transport = { type: 'stdio', command: '' };
|
|
223
|
+
}
|
|
224
|
+
const transport = connector.transport;
|
|
225
|
+
if (!transport.env) {
|
|
226
|
+
transport.env = {};
|
|
227
|
+
}
|
|
228
|
+
// Check if there's an existing secret
|
|
229
|
+
const existingValue = transport.env[envKey];
|
|
230
|
+
let updated = false;
|
|
231
|
+
if (existingValue) {
|
|
232
|
+
const parsed = parseSecretRef(existingValue);
|
|
233
|
+
if (parsed) {
|
|
234
|
+
updated = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Update config with new reference
|
|
238
|
+
transport.env[envKey] = storeResult.reference;
|
|
239
|
+
return {
|
|
240
|
+
config,
|
|
241
|
+
result: {
|
|
242
|
+
secretRef: storeResult.reference,
|
|
243
|
+
secretId: storeResult.id,
|
|
244
|
+
updated,
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Remove orphan secrets not referenced by config
|
|
251
|
+
*/
|
|
252
|
+
export async function pruneOrphanSecrets(options) {
|
|
253
|
+
const { configDir, configPath, dryRun = false, olderThanDays } = options;
|
|
254
|
+
const store = new SqliteSecretStore(configDir);
|
|
255
|
+
try {
|
|
256
|
+
const secretIds = await store.list();
|
|
257
|
+
// Load config to find active bindings
|
|
258
|
+
let config = { version: 1, connectors: [] };
|
|
259
|
+
if (existsSync(configPath)) {
|
|
260
|
+
config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
261
|
+
}
|
|
262
|
+
const configRefs = collectConfigSecretRefs(config);
|
|
263
|
+
// Find orphans
|
|
264
|
+
const orphanIds = [];
|
|
265
|
+
const now = Date.now();
|
|
266
|
+
const ageThreshold = olderThanDays ? olderThanDays * 24 * 60 * 60 * 1000 : 0;
|
|
267
|
+
for (const id of secretIds) {
|
|
268
|
+
if (!configRefs.has(id)) {
|
|
269
|
+
// Check age if specified
|
|
270
|
+
if (ageThreshold > 0) {
|
|
271
|
+
const createdAt = await store.getCreatedAt(id);
|
|
272
|
+
if (createdAt) {
|
|
273
|
+
const age = now - createdAt.getTime();
|
|
274
|
+
if (age < ageThreshold) {
|
|
275
|
+
// Secret is too new, skip it
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
orphanIds.push(id);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Remove orphans if not dry run
|
|
284
|
+
let removedCount = 0;
|
|
285
|
+
if (!dryRun) {
|
|
286
|
+
for (const id of orphanIds) {
|
|
287
|
+
const deleted = await store.delete(id);
|
|
288
|
+
if (deleted) {
|
|
289
|
+
removedCount++;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
orphanCount: orphanIds.length,
|
|
295
|
+
removedCount,
|
|
296
|
+
removedIds: orphanIds,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
finally {
|
|
300
|
+
store.close();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Export secrets to encrypted bundle file
|
|
305
|
+
*/
|
|
306
|
+
export async function exportSecrets(options) {
|
|
307
|
+
const { configDir, configPath, outputPath, passphrase } = options;
|
|
308
|
+
const store = new SqliteSecretStore(configDir);
|
|
309
|
+
try {
|
|
310
|
+
const secretIds = await store.list();
|
|
311
|
+
// Load config to get bindings
|
|
312
|
+
let config = { version: 1, connectors: [] };
|
|
313
|
+
if (existsSync(configPath)) {
|
|
314
|
+
config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
315
|
+
}
|
|
316
|
+
const configRefs = collectConfigSecretRefs(config);
|
|
317
|
+
// Build entries
|
|
318
|
+
const entries = [];
|
|
319
|
+
for (const id of secretIds) {
|
|
320
|
+
const binding = configRefs.get(id);
|
|
321
|
+
if (!binding)
|
|
322
|
+
continue; // Skip orphans
|
|
323
|
+
// Retrieve plaintext (in-memory only)
|
|
324
|
+
const plaintext = await store.retrieve(id);
|
|
325
|
+
if (!plaintext)
|
|
326
|
+
continue;
|
|
327
|
+
entries.push({
|
|
328
|
+
connector_id: binding.connectorId,
|
|
329
|
+
env_key: binding.envKey,
|
|
330
|
+
secret_bytes_b64: Buffer.from(plaintext, 'utf-8').toString('base64'),
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
// Encrypt bundle
|
|
334
|
+
const payloadJson = JSON.stringify({ entries });
|
|
335
|
+
const payloadBytes = Buffer.from(payloadJson, 'utf-8');
|
|
336
|
+
const salt = randomBytes(16);
|
|
337
|
+
const key = deriveKey(passphrase, salt);
|
|
338
|
+
const { iv, authTag, ciphertext } = encryptPayload(payloadBytes, key);
|
|
339
|
+
// Prepare bundle metadata
|
|
340
|
+
const kdfInfo = {
|
|
341
|
+
name: 'scrypt',
|
|
342
|
+
salt: salt.toString('base64'),
|
|
343
|
+
N: SCRYPT_N,
|
|
344
|
+
r: SCRYPT_R,
|
|
345
|
+
p: SCRYPT_P,
|
|
346
|
+
keyLen: KEY_LEN,
|
|
347
|
+
};
|
|
348
|
+
const cipherInfo = {
|
|
349
|
+
name: 'aes-256-gcm',
|
|
350
|
+
iv: iv.toString('base64'),
|
|
351
|
+
authTag: authTag.toString('base64'),
|
|
352
|
+
};
|
|
353
|
+
// Compute HMAC over metadata to detect tampering of KDF/cipher parameters
|
|
354
|
+
const metadataForHmac = JSON.stringify({ version: 1, kdf: kdfInfo, cipher: cipherInfo });
|
|
355
|
+
const metadataHmac = createHmac('sha256', key).update(metadataForHmac).digest('base64');
|
|
356
|
+
const bundle = {
|
|
357
|
+
version: 1,
|
|
358
|
+
kdf: kdfInfo,
|
|
359
|
+
cipher: cipherInfo,
|
|
360
|
+
payload: ciphertext.toString('base64'),
|
|
361
|
+
metadataHmac,
|
|
362
|
+
};
|
|
363
|
+
// Write bundle to file
|
|
364
|
+
writeFileSync(outputPath, JSON.stringify(bundle, null, 2));
|
|
365
|
+
return {
|
|
366
|
+
exportedCount: entries.length,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
finally {
|
|
370
|
+
store.close();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Import secrets from encrypted bundle file
|
|
375
|
+
*/
|
|
376
|
+
export async function importSecrets(options) {
|
|
377
|
+
const { configDir, configPath, inputPath, passphrase, overwrite = false } = options;
|
|
378
|
+
// Read and parse bundle
|
|
379
|
+
const bundleJson = readFileSync(inputPath, 'utf-8');
|
|
380
|
+
const bundle = JSON.parse(bundleJson);
|
|
381
|
+
if (bundle.version !== 1) {
|
|
382
|
+
throw new Error(`Unsupported export bundle version: ${bundle.version}`);
|
|
383
|
+
}
|
|
384
|
+
// Derive key
|
|
385
|
+
const salt = Buffer.from(bundle.kdf.salt, 'base64');
|
|
386
|
+
const key = deriveKey(passphrase, salt);
|
|
387
|
+
// Verify HMAC before trusting metadata (prevents KDF parameter tampering)
|
|
388
|
+
// Uses timing-safe comparison to prevent timing attacks
|
|
389
|
+
const metadataForHmac = JSON.stringify({ version: bundle.version, kdf: bundle.kdf, cipher: bundle.cipher });
|
|
390
|
+
const expectedHmacBuf = createHmac('sha256', key).update(metadataForHmac).digest();
|
|
391
|
+
const actualHmacBuf = Buffer.from(bundle.metadataHmac, 'base64');
|
|
392
|
+
if (expectedHmacBuf.length !== actualHmacBuf.length || !timingSafeEqual(expectedHmacBuf, actualHmacBuf)) {
|
|
393
|
+
throw new Error('Bundle integrity check failed. The file may have been tampered with or the passphrase is incorrect.');
|
|
394
|
+
}
|
|
395
|
+
// Decrypt payload
|
|
396
|
+
const iv = Buffer.from(bundle.cipher.iv, 'base64');
|
|
397
|
+
const authTag = Buffer.from(bundle.cipher.authTag, 'base64');
|
|
398
|
+
const ciphertext = Buffer.from(bundle.payload, 'base64');
|
|
399
|
+
let payloadBytes;
|
|
400
|
+
try {
|
|
401
|
+
payloadBytes = decryptPayload(ciphertext, key, iv, authTag);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
throw new Error('Decryption failed. Wrong passphrase?');
|
|
405
|
+
}
|
|
406
|
+
const payload = JSON.parse(payloadBytes.toString('utf-8'));
|
|
407
|
+
// Store secrets first (outside the config lock to minimize lock time)
|
|
408
|
+
const store = new SqliteSecretStore(configDir);
|
|
409
|
+
const storedSecrets = [];
|
|
410
|
+
const errors = [];
|
|
411
|
+
try {
|
|
412
|
+
for (const entry of payload.entries) {
|
|
413
|
+
try {
|
|
414
|
+
// Decode plaintext (in-memory only)
|
|
415
|
+
const plaintext = Buffer.from(entry.secret_bytes_b64, 'base64').toString('utf-8');
|
|
416
|
+
// Store secret
|
|
417
|
+
const result = await store.store(plaintext, {
|
|
418
|
+
connectorId: entry.connector_id,
|
|
419
|
+
keyName: entry.env_key,
|
|
420
|
+
source: `${entry.connector_id}.transport.env.${entry.env_key}`,
|
|
421
|
+
});
|
|
422
|
+
storedSecrets.push({ entry, reference: result.reference });
|
|
423
|
+
}
|
|
424
|
+
catch (err) {
|
|
425
|
+
errors.push({
|
|
426
|
+
connector_id: entry.connector_id,
|
|
427
|
+
env_key: entry.env_key,
|
|
428
|
+
error: err instanceof Error ? err.message : String(err),
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
finally {
|
|
434
|
+
store.close();
|
|
435
|
+
}
|
|
436
|
+
// If no secrets were stored, return early without touching config
|
|
437
|
+
if (storedSecrets.length === 0) {
|
|
438
|
+
return {
|
|
439
|
+
importedCount: 0,
|
|
440
|
+
skippedCount: payload.entries.length - errors.length,
|
|
441
|
+
errorCount: errors.length,
|
|
442
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
// Update config with file locking to prevent race conditions
|
|
446
|
+
return withConfigLock(configPath, async (config) => {
|
|
447
|
+
let importedCount = 0;
|
|
448
|
+
let skippedCount = 0;
|
|
449
|
+
for (const { entry, reference } of storedSecrets) {
|
|
450
|
+
// Find connector
|
|
451
|
+
const connector = config.connectors?.find(c => c.id === entry.connector_id);
|
|
452
|
+
if (!connector) {
|
|
453
|
+
// Connector doesn't exist in config, skip
|
|
454
|
+
skippedCount++;
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
// Check if already has a secret ref
|
|
458
|
+
const transport = connector.transport;
|
|
459
|
+
const existingValue = transport?.env?.[entry.env_key];
|
|
460
|
+
if (existingValue && parseSecretRef(existingValue)) {
|
|
461
|
+
if (!overwrite) {
|
|
462
|
+
skippedCount++;
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// Update config
|
|
467
|
+
if (!transport) {
|
|
468
|
+
connector.transport = { type: 'stdio', command: '' };
|
|
469
|
+
}
|
|
470
|
+
const t = connector.transport;
|
|
471
|
+
if (!t.env) {
|
|
472
|
+
t.env = {};
|
|
473
|
+
}
|
|
474
|
+
t.env[entry.env_key] = reference;
|
|
475
|
+
importedCount++;
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
config,
|
|
479
|
+
result: {
|
|
480
|
+
importedCount,
|
|
481
|
+
skippedCount: skippedCount + (payload.entries.length - storedSecrets.length - errors.length),
|
|
482
|
+
errorCount: errors.length,
|
|
483
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
484
|
+
},
|
|
485
|
+
};
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
//# sourceMappingURL=management.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"management.js","sourceRoot":"","sources":["../../src/secrets/management.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC1G,OAAO,EAAE,OAAO,EAAQ,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAChH,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAqB,MAAM,YAAY,CAAC;AA2H9E,+DAA+D;AAC/D,mBAAmB;AACnB,+DAA+D;AAE/D,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,oEAAoE;AAC9F,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,MAAM,OAAO,GAAG,EAAE,CAAC,CAAC,WAAW;AAE/B,SAAS,SAAS,CAAC,UAAkB,EAAE,IAAY;IACjD,OAAO,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE;QAC3C,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,QAAQ;KACZ,CAAC,CAAC;AACL,CAAC;AAED,SAAS,cAAc,CAAC,SAAiB,EAAE,GAAW;IACpD,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB;IAC9C,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IACpC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,cAAc,CAAC,UAAkB,EAAE,GAAW,EAAE,EAAU,EAAE,OAAe;IAClF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,+DAA+D;AAC/D,yBAAyB;AACzB,+DAA+D;AAE/D,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,aAAa;AAC5C,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAEnC;;;GAGG;AACH,KAAK,UAAU,iBAAiB,CAAC,UAAkB;IACjD,MAAM,QAAQ,GAAG,GAAG,UAAU,OAAO,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,eAAe,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,4EAA4E;YAC5E,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACpC,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,8BAA8B;gBAC9B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC;YAC5E,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,6BAA6B,UAAU,mBAAmB,eAAe,KAAK,CAAC,CAAC;AAClG,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,IAAI,CAAC;QACH,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,cAAc,CAC3B,UAAkB,EAClB,SAAqE;IAErE,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,GAAG,UAAU,MAAM,CAAC;IACrC,IAAI,CAAC;QACH,sBAAsB;QACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,MAAM,GAAW,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QAErE,oBAAoB;QACpB,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QAElE,sEAAsE;QACtE,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAChE,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAEjC,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,kCAAkC;QAClC,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACzB,UAAU,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;QACD,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,mBAAmB;AACnB,+DAA+D;AAE/D,0CAA0C;AAC1C,SAAS,uBAAuB,CAAC,MAAc;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAmD,CAAC;IAExE,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QAChD,MAAM,GAAG,GAAI,SAAS,CAAC,SAA4B,EAAE,GAAG,CAAC;QACzD,IAAI,CAAC,GAAG;YAAE,SAAS;QAEnB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YACrC,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+DAA+D;AAC/D,uBAAuB;AACvB,+DAA+D;AAE/D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAiB,EACjB,UAAkB;IAElB,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,gCAAgC;QAChC,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAErC,+BAA+B;QAC/B,IAAI,MAAM,GAAW,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QACpD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAEnD,qCAAqC;QACrC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YAE/C,wDAAwD;YACxD,IAAI,QAAQ,GAAiB,OAAO,CAAC;YACrC,iDAAiD;YACjD,yCAAyC;YACzC,QAAQ,GAAG,KAAK,CAAC,eAAe,EAAE,CAAC;YAEnC,OAAO,CAAC,IAAI,CAAC;gBACX,UAAU,EAAE,aAAa,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACvC,SAAS,EAAE,EAAE;gBACb,YAAY,EAAE,OAAO,EAAE,WAAW;gBAClC,OAAO,EAAE,OAAO,EAAE,MAAM;gBACxB,QAAQ;gBACR,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAChE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ;aAClC,CAAC,CAAC;YAEH,kDAAkD;YAClD,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;QAED,oEAAoE;QACpE,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,UAAU,EAAE,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC;gBACX,UAAU,EAAE,WAAW,EAAE,EAAE;gBAC3B,SAAS,EAAE,EAAE;gBACb,YAAY,EAAE,OAAO,CAAC,WAAW;gBACjC,OAAO,EAAE,OAAO,CAAC,MAAM;gBACvB,QAAQ,EAAE,OAAO;gBACjB,UAAU,EAAE,EAAE;gBACd,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB;IACvD,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACjE,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAEtC,kEAAkE;IAClE,MAAM,KAAK,GAAG,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,WAA8C,CAAC;IACnD,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE;YAC3C,WAAW;YACX,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,GAAG,WAAW,kBAAkB,MAAM,EAAE;SACjD,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAED,kCAAkC;IAClC,OAAO,cAAc,CAAkB,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAClE,iBAAiB;QACjB,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,WAAW,CAAC,CAAC;QACrE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,wBAAwB,WAAW,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,8BAA8B;QAC9B,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;YACxB,SAAuB,CAAC,SAAS,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAoB,CAAC;QACxF,CAAC;QACD,MAAM,SAAS,GAAG,SAAS,CAAC,SAA2B,CAAC;QACxD,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;YACnB,SAAS,CAAC,GAAG,GAAG,EAAE,CAAC;QACrB,CAAC;QAED,sCAAsC;QACtC,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;YAC7C,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;QACH,CAAC;QAED,mCAAmC;QACnC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC;QAE9C,OAAO;YACL,MAAM;YACN,MAAM,EAAE;gBACN,SAAS,EAAE,WAAW,CAAC,SAAS;gBAChC,QAAQ,EAAE,WAAW,CAAC,EAAE;gBACxB,OAAO;aACR;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAqB;IAC5D,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAEzE,MAAM,KAAK,GAAG,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAErC,sCAAsC;QACtC,IAAI,MAAM,GAAW,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QACpD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAEnD,eAAe;QACf,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7E,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACxB,yBAAyB;gBACzB,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;oBACrB,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;oBAC/C,IAAI,SAAS,EAAE,CAAC;wBACd,MAAM,GAAG,GAAG,GAAG,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;wBACtC,IAAI,GAAG,GAAG,YAAY,EAAE,CAAC;4BACvB,6BAA6B;4BAC7B,SAAS;wBACX,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;gBAC3B,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACvC,IAAI,OAAO,EAAE,CAAC;oBACZ,YAAY,EAAE,CAAC;gBACjB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,WAAW,EAAE,SAAS,CAAC,MAAM;YAC7B,YAAY;YACZ,UAAU,EAAE,SAAS;SACtB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAElE,MAAM,KAAK,GAAG,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAErC,8BAA8B;QAC9B,IAAI,MAAM,GAAW,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QACpD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAEnD,gBAAgB;QAChB,MAAM,OAAO,GAAkB,EAAE,CAAC;QAClC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnC,IAAI,CAAC,OAAO;gBAAE,SAAS,CAAC,eAAe;YAEvC,sCAAsC;YACtC,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,SAAS;gBAAE,SAAS;YAEzB,OAAO,CAAC,IAAI,CAAC;gBACX,YAAY,EAAE,OAAO,CAAC,WAAW;gBACjC,OAAO,EAAE,OAAO,CAAC,MAAM;gBACvB,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;aACrE,CAAC,CAAC;QACL,CAAC;QAED,iBAAiB;QACjB,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QAChD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACxC,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QAEtE,0BAA0B;QAC1B,MAAM,OAAO,GAAG;YACd,IAAI,EAAE,QAAiB;YACvB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC7B,CAAC,EAAE,QAAQ;YACX,CAAC,EAAE,QAAQ;YACX,CAAC,EAAE,QAAQ;YACX,MAAM,EAAE,OAAO;SAChB,CAAC;QACF,MAAM,UAAU,GAAG;YACjB,IAAI,EAAE,aAAsB;YAC5B,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;SACpC,CAAC;QAEF,0EAA0E;QAC1E,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QACzF,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAExF,MAAM,MAAM,GAAiB;YAC3B,OAAO,EAAE,CAAC;YACV,GAAG,EAAE,OAAO;YACZ,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACtC,YAAY;SACb,CAAC;QAEF,uBAAuB;QACvB,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE3D,OAAO;YACL,aAAa,EAAE,OAAO,CAAC,MAAM;SAC9B,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAEpF,wBAAwB;IACxB,MAAM,UAAU,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,MAAM,GAAiB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAEpD,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,sCAAsC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,aAAa;IACb,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAExC,0EAA0E;IAC1E,wDAAwD;IACxD,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5G,MAAM,eAAe,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,EAAE,CAAC;IACnF,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IACjE,IAAI,eAAe,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,eAAe,EAAE,aAAa,CAAC,EAAE,CAAC;QACxG,MAAM,IAAI,KAAK,CAAC,qGAAqG,CAAC,CAAC;IACzH,CAAC;IAED,kBAAkB;IAClB,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAEzD,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACH,YAAY,GAAG,cAAc,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA+B,CAAC;IAEzF,sEAAsE;IACtE,MAAM,KAAK,GAAG,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAgD,EAAE,CAAC;IACtE,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,IAAI,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,oCAAoC;gBACpC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAElF,eAAe;gBACf,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE;oBAC1C,WAAW,EAAE,KAAK,CAAC,YAAY;oBAC/B,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,kBAAkB,KAAK,CAAC,OAAO,EAAE;iBAC/D,CAAC,CAAC;gBAEH,aAAa,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC;oBACV,YAAY,EAAE,KAAK,CAAC,YAAY;oBAChC,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACxD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAED,kEAAkE;IAClE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,aAAa,EAAE,CAAC;YAChB,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM;YACpD,UAAU,EAAE,MAAM,CAAC,MAAM;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SAC/C,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,OAAO,cAAc,CAAe,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAC/D,IAAI,aAAa,GAAG,CAAC,CAAC;QACtB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,aAAa,EAAE,CAAC;YACjD,iBAAiB;YACjB,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,YAAY,CAAC,CAAC;YAC5E,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,0CAA0C;gBAC1C,YAAY,EAAE,CAAC;gBACf,SAAS;YACX,CAAC;YAED,oCAAoC;YACpC,MAAM,SAAS,GAAG,SAAS,CAAC,SAA2B,CAAC;YACxD,MAAM,aAAa,GAAG,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACtD,IAAI,aAAa,IAAI,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC;gBACnD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,YAAY,EAAE,CAAC;oBACf,SAAS;gBACX,CAAC;YACH,CAAC;YAED,gBAAgB;YAChB,IAAI,CAAC,SAAS,EAAE,CAAC;gBACd,SAAuB,CAAC,SAAS,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAoB,CAAC;YACxF,CAAC;YACD,MAAM,CAAC,GAAG,SAAS,CAAC,SAA2B,CAAC;YAChD,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;gBACX,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC;YACb,CAAC;YACD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;YAEjC,aAAa,EAAE,CAAC;QAClB,CAAC;QAED,OAAO;YACL,MAAM;YACN,MAAM,EAAE;gBACN,aAAa;gBACb,YAAY,EAAE,YAAY,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;gBAC5F,UAAU,EAAE,MAAM,CAAC,MAAM;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;aAC/C;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret reference resolution (Phase 3.6)
|
|
3
|
+
*
|
|
4
|
+
* Resolves secret references (dpapi:<id>, keychain:<id>, plain:<id>) in env vars
|
|
5
|
+
* to their plaintext values at runtime.
|
|
6
|
+
*
|
|
7
|
+
* Security:
|
|
8
|
+
* - Plaintext is only held in memory during process spawn
|
|
9
|
+
* - Never written to disk, logs, or config files
|
|
10
|
+
* - Original env with refs is not modified
|
|
11
|
+
*/
|
|
12
|
+
/** Result of resolving env secrets */
|
|
13
|
+
export interface ResolveEnvSecretsResult {
|
|
14
|
+
/** Resolved env (with plaintext values) - SENSITIVE, in-memory only */
|
|
15
|
+
envResolved: Record<string, string>;
|
|
16
|
+
/** Secret refs that were successfully resolved */
|
|
17
|
+
resolvedRefs: string[];
|
|
18
|
+
/** Errors encountered during resolution */
|
|
19
|
+
errors: ResolveError[];
|
|
20
|
+
/** Whether resolution was fully successful */
|
|
21
|
+
success: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Error during secret resolution */
|
|
24
|
+
export interface ResolveError {
|
|
25
|
+
/** Environment key */
|
|
26
|
+
key: string;
|
|
27
|
+
/** Secret reference that failed */
|
|
28
|
+
ref: string;
|
|
29
|
+
/** Error message */
|
|
30
|
+
message: string;
|
|
31
|
+
/** Suggested fix command */
|
|
32
|
+
suggestion?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve secret references in env vars to plaintext values
|
|
36
|
+
*
|
|
37
|
+
* This function should be called just before spawning a child process.
|
|
38
|
+
* The returned envResolved should be passed to spawn() and then
|
|
39
|
+
* immediately discarded (not stored or logged).
|
|
40
|
+
*
|
|
41
|
+
* @param env - Environment variables potentially containing secret refs
|
|
42
|
+
* @param connectorId - Connector ID for error messages and suggestions
|
|
43
|
+
* @param configDir - Config directory (default: ~/.proofscan)
|
|
44
|
+
* @returns Resolved env and any errors
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveEnvSecrets(env: Record<string, string> | undefined, connectorId: string, configDir?: string): Promise<ResolveEnvSecretsResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Format resolution errors for user display
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatResolveErrors(errors: ResolveError[], connectorId: string): string[];
|
|
51
|
+
//# sourceMappingURL=resolve.d.ts.map
|