@captainsafia/burrow 1.2.0 → 1.3.0-preview.319e6c8
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/api.d.ts +213 -0
- package/dist/api.js +251 -0
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
+
export interface TrustedPath {
|
|
4
|
+
path: string;
|
|
5
|
+
inode: string;
|
|
6
|
+
trustedAt: string;
|
|
7
|
+
}
|
|
3
8
|
export interface ResolvedSecret {
|
|
4
9
|
key: string;
|
|
5
10
|
value: string;
|
|
6
11
|
sourcePath: string;
|
|
7
12
|
}
|
|
8
13
|
export type ExportFormat = "shell" | "bash" | "fish" | "powershell" | "cmd" | "dotenv" | "json";
|
|
14
|
+
export interface TrustCheckResult {
|
|
15
|
+
trusted: boolean;
|
|
16
|
+
trustedPath?: string;
|
|
17
|
+
reason?: "not-trusted" | "inode-mismatch" | "path-not-found";
|
|
18
|
+
}
|
|
19
|
+
export interface LoadedSecret {
|
|
20
|
+
key: string;
|
|
21
|
+
value: string;
|
|
22
|
+
sourcePath: string;
|
|
23
|
+
}
|
|
24
|
+
export interface HookDiff {
|
|
25
|
+
/** Keys to unset from the environment */
|
|
26
|
+
toUnset: string[];
|
|
27
|
+
/** Secrets to set in the environment */
|
|
28
|
+
toSet: LoadedSecret[];
|
|
29
|
+
}
|
|
9
30
|
/**
|
|
10
31
|
* Configuration options for creating a BurrowClient instance.
|
|
11
32
|
*/
|
|
@@ -82,6 +103,97 @@ export interface RemoveOptions {
|
|
|
82
103
|
*/
|
|
83
104
|
path?: string;
|
|
84
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Options for the `trust` method.
|
|
108
|
+
*/
|
|
109
|
+
export interface TrustOptions {
|
|
110
|
+
/**
|
|
111
|
+
* Directory path to trust.
|
|
112
|
+
* Defaults to the current working directory.
|
|
113
|
+
*/
|
|
114
|
+
path?: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Options for the `untrust` method.
|
|
118
|
+
*/
|
|
119
|
+
export interface UntrustOptions {
|
|
120
|
+
/**
|
|
121
|
+
* Directory path to untrust.
|
|
122
|
+
* Defaults to the current working directory.
|
|
123
|
+
*/
|
|
124
|
+
path?: string;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Options for the `isTrusted` method.
|
|
128
|
+
*/
|
|
129
|
+
export interface IsTrustedOptions {
|
|
130
|
+
/**
|
|
131
|
+
* Directory path to check for trust.
|
|
132
|
+
* Defaults to the current working directory.
|
|
133
|
+
*/
|
|
134
|
+
path?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Result of the `trust` method.
|
|
138
|
+
*/
|
|
139
|
+
export interface TrustResult {
|
|
140
|
+
/**
|
|
141
|
+
* The canonicalized path that was trusted.
|
|
142
|
+
*/
|
|
143
|
+
path: string;
|
|
144
|
+
/**
|
|
145
|
+
* The filesystem inode/file ID for the trusted path.
|
|
146
|
+
*/
|
|
147
|
+
inode: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Options for the `hook` method.
|
|
151
|
+
*/
|
|
152
|
+
export interface HookOptions {
|
|
153
|
+
/**
|
|
154
|
+
* The shell to generate hook commands for.
|
|
155
|
+
*/
|
|
156
|
+
shell: "bash" | "zsh" | "fish";
|
|
157
|
+
/**
|
|
158
|
+
* Whether to use colored output.
|
|
159
|
+
* Defaults to respecting NO_COLOR environment variable.
|
|
160
|
+
*/
|
|
161
|
+
useColor?: boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Keys that were previously loaded by the hook.
|
|
164
|
+
* Used to compute which keys need to be unset.
|
|
165
|
+
*/
|
|
166
|
+
previousKeys?: string[];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Result of the `hook` method.
|
|
170
|
+
*/
|
|
171
|
+
export interface HookResult {
|
|
172
|
+
/**
|
|
173
|
+
* Shell commands to execute for environment updates.
|
|
174
|
+
*/
|
|
175
|
+
commands: string[];
|
|
176
|
+
/**
|
|
177
|
+
* Optional message to display to the user.
|
|
178
|
+
*/
|
|
179
|
+
message?: string;
|
|
180
|
+
/**
|
|
181
|
+
* The secrets that were loaded.
|
|
182
|
+
*/
|
|
183
|
+
secrets: LoadedSecret[];
|
|
184
|
+
/**
|
|
185
|
+
* The keys that were unloaded.
|
|
186
|
+
*/
|
|
187
|
+
unloadedKeys: string[];
|
|
188
|
+
/**
|
|
189
|
+
* Whether the directory is trusted.
|
|
190
|
+
*/
|
|
191
|
+
trusted: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Reason if directory is not trusted.
|
|
194
|
+
*/
|
|
195
|
+
notTrustedReason?: "not-trusted" | "inode-mismatch" | "path-not-found" | "autoload-disabled";
|
|
196
|
+
}
|
|
85
197
|
/**
|
|
86
198
|
* Options for the `export` method.
|
|
87
199
|
*/
|
|
@@ -135,6 +247,7 @@ export declare class BurrowClient {
|
|
|
135
247
|
private readonly storage;
|
|
136
248
|
private readonly resolver;
|
|
137
249
|
private readonly pathOptions;
|
|
250
|
+
private readonly trustManager;
|
|
138
251
|
/**
|
|
139
252
|
* Creates a new BurrowClient instance.
|
|
140
253
|
*
|
|
@@ -307,6 +420,106 @@ export declare class BurrowClient {
|
|
|
307
420
|
* ```
|
|
308
421
|
*/
|
|
309
422
|
resolve(cwd?: string): Promise<Map<string, ResolvedSecret>>;
|
|
423
|
+
/**
|
|
424
|
+
* Trusts a directory for auto-loading secrets.
|
|
425
|
+
*
|
|
426
|
+
* When a directory is trusted, navigating into it (or its subdirectories)
|
|
427
|
+
* will automatically load secrets into the shell environment via the hook.
|
|
428
|
+
*
|
|
429
|
+
* @param options - Trust options including target path
|
|
430
|
+
* @returns The trusted path info with canonicalized path and inode
|
|
431
|
+
*
|
|
432
|
+
* @example
|
|
433
|
+
* ```typescript
|
|
434
|
+
* // Trust current directory
|
|
435
|
+
* await client.trust();
|
|
436
|
+
*
|
|
437
|
+
* // Trust specific path
|
|
438
|
+
* const result = await client.trust({ path: '/projects/myapp' });
|
|
439
|
+
* console.log(`Trusted: ${result.path}`);
|
|
440
|
+
* ```
|
|
441
|
+
*/
|
|
442
|
+
trust(options?: TrustOptions): Promise<TrustResult>;
|
|
443
|
+
/**
|
|
444
|
+
* Removes trust from a directory.
|
|
445
|
+
*
|
|
446
|
+
* After untrusting, the directory (and its subdirectories) will no longer
|
|
447
|
+
* auto-load secrets. Secrets currently loaded remain until the next directory change.
|
|
448
|
+
*
|
|
449
|
+
* @param options - Untrust options including target path
|
|
450
|
+
* @returns true if the path was trusted and is now untrusted, false if it wasn't trusted
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```typescript
|
|
454
|
+
* const removed = await client.untrust({ path: '/projects/myapp' });
|
|
455
|
+
* if (removed) {
|
|
456
|
+
* console.log('Directory is no longer trusted');
|
|
457
|
+
* }
|
|
458
|
+
* ```
|
|
459
|
+
*/
|
|
460
|
+
untrust(options?: UntrustOptions): Promise<boolean>;
|
|
461
|
+
/**
|
|
462
|
+
* Checks if a directory is trusted for auto-loading.
|
|
463
|
+
*
|
|
464
|
+
* Trust can be inherited from ancestor directories. Also validates that
|
|
465
|
+
* the inode matches to detect directory replacements.
|
|
466
|
+
*
|
|
467
|
+
* @param options - Options including path to check
|
|
468
|
+
* @returns Trust check result with status and reason if not trusted
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```typescript
|
|
472
|
+
* const result = await client.isTrusted({ path: '/projects/myapp/src' });
|
|
473
|
+
* if (result.trusted) {
|
|
474
|
+
* console.log(`Trusted via: ${result.trustedPath}`);
|
|
475
|
+
* } else {
|
|
476
|
+
* console.log(`Not trusted: ${result.reason}`);
|
|
477
|
+
* }
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
isTrusted(options?: IsTrustedOptions): Promise<TrustCheckResult>;
|
|
481
|
+
/**
|
|
482
|
+
* Lists all trusted directories.
|
|
483
|
+
*
|
|
484
|
+
* @returns Array of all trusted path entries
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
* ```typescript
|
|
488
|
+
* const trusted = await client.listTrusted();
|
|
489
|
+
* for (const entry of trusted) {
|
|
490
|
+
* console.log(`${entry.path} (trusted at ${entry.trustedAt})`);
|
|
491
|
+
* }
|
|
492
|
+
* ```
|
|
493
|
+
*/
|
|
494
|
+
listTrusted(): Promise<TrustedPath[]>;
|
|
495
|
+
/**
|
|
496
|
+
* Processes a directory change for the shell hook.
|
|
497
|
+
*
|
|
498
|
+
* This is the main method called by shell hooks on directory change.
|
|
499
|
+
* It checks trust, resolves secrets, computes the diff from previous
|
|
500
|
+
* state, and returns the commands needed to update the environment.
|
|
501
|
+
*
|
|
502
|
+
* @param cwd - The new working directory
|
|
503
|
+
* @param options - Hook options including shell type and previous keys
|
|
504
|
+
* @returns Hook result with commands to execute and optional message
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```typescript
|
|
508
|
+
* const result = await client.hook('/projects/myapp', {
|
|
509
|
+
* shell: 'bash',
|
|
510
|
+
* previousKeys: ['OLD_KEY'] // Keys from last hook call
|
|
511
|
+
* });
|
|
512
|
+
* if (result.trusted) {
|
|
513
|
+
* for (const cmd of result.commands) {
|
|
514
|
+
* console.log(cmd); // Execute in shell
|
|
515
|
+
* }
|
|
516
|
+
* if (result.message) {
|
|
517
|
+
* console.error(result.message);
|
|
518
|
+
* }
|
|
519
|
+
* }
|
|
520
|
+
* ```
|
|
521
|
+
*/
|
|
522
|
+
hook(cwd: string, options: HookOptions): Promise<HookResult>;
|
|
310
523
|
/**
|
|
311
524
|
* Closes the database connection and releases resources.
|
|
312
525
|
* After calling this method, the client instance should not be used.
|
package/dist/api.js
CHANGED
|
@@ -80,6 +80,14 @@ class Storage {
|
|
|
80
80
|
)
|
|
81
81
|
`);
|
|
82
82
|
this.db.run("CREATE INDEX IF NOT EXISTS idx_secrets_path ON secrets (path)");
|
|
83
|
+
this.db.run(`
|
|
84
|
+
CREATE TABLE IF NOT EXISTS trusted_paths (
|
|
85
|
+
path TEXT PRIMARY KEY,
|
|
86
|
+
inode TEXT NOT NULL,
|
|
87
|
+
trusted_at TEXT NOT NULL
|
|
88
|
+
)
|
|
89
|
+
`);
|
|
90
|
+
this.db.run("CREATE INDEX IF NOT EXISTS idx_trusted_paths_inode ON trusted_paths (inode)");
|
|
83
91
|
const versionResult = this.db.query("PRAGMA user_version").get();
|
|
84
92
|
const currentVersion = versionResult?.user_version ?? 0;
|
|
85
93
|
if (currentVersion === 0) {
|
|
@@ -139,6 +147,61 @@ class Storage {
|
|
|
139
147
|
db.query("DELETE FROM secrets WHERE path = ? AND key = ?").run(canonicalPath, key);
|
|
140
148
|
return true;
|
|
141
149
|
}
|
|
150
|
+
async addTrustedPath(canonicalPath, inode) {
|
|
151
|
+
const db = await this.ensureDb();
|
|
152
|
+
const trustedAt = new Date().toISOString();
|
|
153
|
+
db.query(`
|
|
154
|
+
INSERT INTO trusted_paths (path, inode, trusted_at)
|
|
155
|
+
VALUES (?, ?, ?)
|
|
156
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
157
|
+
inode = excluded.inode,
|
|
158
|
+
trusted_at = excluded.trusted_at
|
|
159
|
+
`).run(canonicalPath, inode, trustedAt);
|
|
160
|
+
}
|
|
161
|
+
async removeTrustedPath(canonicalPath) {
|
|
162
|
+
const db = await this.ensureDb();
|
|
163
|
+
const existing = db.query("SELECT path FROM trusted_paths WHERE path = ?").get(canonicalPath);
|
|
164
|
+
if (!existing) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
db.query("DELETE FROM trusted_paths WHERE path = ?").run(canonicalPath);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
async getTrustedPath(canonicalPath) {
|
|
171
|
+
const db = await this.ensureDb();
|
|
172
|
+
const row = db.query("SELECT path, inode, trusted_at FROM trusted_paths WHERE path = ?").get(canonicalPath);
|
|
173
|
+
if (!row) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
path: row.path,
|
|
178
|
+
inode: row.inode,
|
|
179
|
+
trustedAt: row.trusted_at
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async getAllTrustedPaths() {
|
|
183
|
+
const db = await this.ensureDb();
|
|
184
|
+
const rows = db.query("SELECT path, inode, trusted_at FROM trusted_paths ORDER BY path").all();
|
|
185
|
+
return rows.map((row) => ({
|
|
186
|
+
path: row.path,
|
|
187
|
+
inode: row.inode,
|
|
188
|
+
trustedAt: row.trusted_at
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
async getTrustedAncestorPaths(canonicalPath) {
|
|
192
|
+
const db = await this.ensureDb();
|
|
193
|
+
let rows;
|
|
194
|
+
if (isWindows()) {
|
|
195
|
+
rows = db.query("SELECT path, inode, trusted_at FROM trusted_paths WHERE ? = path OR ? LIKE path || '\\' || '%' OR (length(path) = 3 AND path LIKE '_:\\' AND ? LIKE path || '%')").all(canonicalPath, canonicalPath, canonicalPath);
|
|
196
|
+
} else {
|
|
197
|
+
rows = db.query("SELECT path, inode, trusted_at FROM trusted_paths WHERE ? = path OR ? LIKE path || '/' || '%' OR path = '/'").all(canonicalPath, canonicalPath);
|
|
198
|
+
}
|
|
199
|
+
return rows.map((row) => ({
|
|
200
|
+
path: row.path,
|
|
201
|
+
inode: row.inode,
|
|
202
|
+
trustedAt: row.trusted_at
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
142
205
|
close() {
|
|
143
206
|
if (this.db) {
|
|
144
207
|
this.db.close();
|
|
@@ -355,11 +418,135 @@ function format(secrets, fmt, options = {}) {
|
|
|
355
418
|
throw new Error(`Unknown format: ${fmt}`);
|
|
356
419
|
}
|
|
357
420
|
}
|
|
421
|
+
// src/core/trust.ts
|
|
422
|
+
import { stat } from "node:fs/promises";
|
|
423
|
+
async function getInode(path) {
|
|
424
|
+
const stats = await stat(path);
|
|
425
|
+
return stats.ino.toString();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
class TrustManager {
|
|
429
|
+
storage;
|
|
430
|
+
pathOptions;
|
|
431
|
+
constructor(options) {
|
|
432
|
+
this.storage = options.storage;
|
|
433
|
+
this.pathOptions = {
|
|
434
|
+
followSymlinks: options.followSymlinks
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
async trust(targetPath) {
|
|
438
|
+
const canonicalPath = await canonicalize(targetPath, this.pathOptions);
|
|
439
|
+
const inode = await getInode(canonicalPath);
|
|
440
|
+
await this.storage.addTrustedPath(canonicalPath, inode);
|
|
441
|
+
return { path: canonicalPath, inode };
|
|
442
|
+
}
|
|
443
|
+
async untrust(targetPath) {
|
|
444
|
+
const canonicalPath = await canonicalize(targetPath, this.pathOptions);
|
|
445
|
+
return this.storage.removeTrustedPath(canonicalPath);
|
|
446
|
+
}
|
|
447
|
+
async isTrusted(targetPath) {
|
|
448
|
+
let canonicalPath;
|
|
449
|
+
try {
|
|
450
|
+
canonicalPath = await canonicalize(targetPath, this.pathOptions);
|
|
451
|
+
} catch {
|
|
452
|
+
return { trusted: false, reason: "path-not-found" };
|
|
453
|
+
}
|
|
454
|
+
const trustedAncestors = await this.storage.getTrustedAncestorPaths(canonicalPath);
|
|
455
|
+
if (trustedAncestors.length === 0) {
|
|
456
|
+
return { trusted: false, reason: "not-trusted" };
|
|
457
|
+
}
|
|
458
|
+
trustedAncestors.sort((a, b) => b.path.length - a.path.length);
|
|
459
|
+
for (const trusted of trustedAncestors) {
|
|
460
|
+
try {
|
|
461
|
+
const currentInode = await getInode(trusted.path);
|
|
462
|
+
if (currentInode === trusted.inode) {
|
|
463
|
+
return { trusted: true, trustedPath: trusted.path };
|
|
464
|
+
}
|
|
465
|
+
} catch {}
|
|
466
|
+
}
|
|
467
|
+
return { trusted: false, reason: "inode-mismatch" };
|
|
468
|
+
}
|
|
469
|
+
async list() {
|
|
470
|
+
return this.storage.getAllTrustedPaths();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
// src/core/hook.ts
|
|
474
|
+
function resolveToLoadedSecrets(secrets) {
|
|
475
|
+
const result = [];
|
|
476
|
+
for (const [, secret] of secrets) {
|
|
477
|
+
result.push({
|
|
478
|
+
key: secret.key,
|
|
479
|
+
value: secret.value,
|
|
480
|
+
sourcePath: secret.sourcePath
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
485
|
+
function computeHookDiff(previousKeys, newSecrets) {
|
|
486
|
+
const newKeys = new Set(newSecrets.map((s) => s.key));
|
|
487
|
+
const toUnset = [];
|
|
488
|
+
for (const key of previousKeys) {
|
|
489
|
+
if (!newKeys.has(key)) {
|
|
490
|
+
toUnset.push(key);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return {
|
|
494
|
+
toUnset,
|
|
495
|
+
toSet: newSecrets
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
function formatHookMessage(diff, useColor = true) {
|
|
499
|
+
const loaded = diff.toSet.length;
|
|
500
|
+
const unloaded = diff.toUnset.length;
|
|
501
|
+
if (loaded === 0 && unloaded === 0) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const dim = useColor ? "\x1B[2m" : "";
|
|
505
|
+
const reset = useColor ? "\x1B[0m" : "";
|
|
506
|
+
let message = `${dim}burrow: `;
|
|
507
|
+
if (unloaded > 0 && loaded > 0) {
|
|
508
|
+
message += `unloaded ${unloaded}, loaded ${loaded}`;
|
|
509
|
+
} else if (loaded > 0) {
|
|
510
|
+
message += `loaded ${loaded} secret${loaded === 1 ? "" : "s"}`;
|
|
511
|
+
} else {
|
|
512
|
+
message += `unloaded ${unloaded} secret${unloaded === 1 ? "" : "s"}`;
|
|
513
|
+
}
|
|
514
|
+
message += reset;
|
|
515
|
+
return message;
|
|
516
|
+
}
|
|
517
|
+
function generateShellCommands(diff, shell) {
|
|
518
|
+
const commands = [];
|
|
519
|
+
for (const key of diff.toUnset) {
|
|
520
|
+
if (shell === "fish") {
|
|
521
|
+
commands.push(`set -e ${key}`);
|
|
522
|
+
} else {
|
|
523
|
+
commands.push(`unset ${key}`);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
for (const secret of diff.toSet) {
|
|
527
|
+
const escapedValue = escapeShellValue2(secret.value, shell);
|
|
528
|
+
if (shell === "fish") {
|
|
529
|
+
commands.push(`set -gx ${secret.key} ${escapedValue}`);
|
|
530
|
+
} else {
|
|
531
|
+
commands.push(`export ${secret.key}=${escapedValue}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return commands;
|
|
535
|
+
}
|
|
536
|
+
function escapeShellValue2(value, shell) {
|
|
537
|
+
if (shell === "fish") {
|
|
538
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
539
|
+
} else {
|
|
540
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
541
|
+
return `$'${escaped}'`;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
358
544
|
// src/api.ts
|
|
359
545
|
class BurrowClient {
|
|
360
546
|
storage;
|
|
361
547
|
resolver;
|
|
362
548
|
pathOptions;
|
|
549
|
+
trustManager;
|
|
363
550
|
constructor(options = {}) {
|
|
364
551
|
this.storage = new Storage({
|
|
365
552
|
configDir: options.configDir,
|
|
@@ -372,6 +559,10 @@ class BurrowClient {
|
|
|
372
559
|
this.pathOptions = {
|
|
373
560
|
followSymlinks: options.followSymlinks
|
|
374
561
|
};
|
|
562
|
+
this.trustManager = new TrustManager({
|
|
563
|
+
storage: this.storage,
|
|
564
|
+
followSymlinks: options.followSymlinks
|
|
565
|
+
});
|
|
375
566
|
}
|
|
376
567
|
async set(key, value, options = {}) {
|
|
377
568
|
assertValidEnvKey(key);
|
|
@@ -407,6 +598,66 @@ class BurrowClient {
|
|
|
407
598
|
async resolve(cwd) {
|
|
408
599
|
return this.resolver.resolve(cwd);
|
|
409
600
|
}
|
|
601
|
+
async trust(options = {}) {
|
|
602
|
+
const targetPath = options.path ?? process.cwd();
|
|
603
|
+
return this.trustManager.trust(targetPath);
|
|
604
|
+
}
|
|
605
|
+
async untrust(options = {}) {
|
|
606
|
+
const targetPath = options.path ?? process.cwd();
|
|
607
|
+
return this.trustManager.untrust(targetPath);
|
|
608
|
+
}
|
|
609
|
+
async isTrusted(options = {}) {
|
|
610
|
+
const targetPath = options.path ?? process.cwd();
|
|
611
|
+
return this.trustManager.isTrusted(targetPath);
|
|
612
|
+
}
|
|
613
|
+
async listTrusted() {
|
|
614
|
+
return this.trustManager.list();
|
|
615
|
+
}
|
|
616
|
+
async hook(cwd, options) {
|
|
617
|
+
const previousKeys = new Set(options.previousKeys ?? []);
|
|
618
|
+
if (process.env["BURROW_AUTOLOAD"] === "0") {
|
|
619
|
+
const diff2 = computeHookDiff(previousKeys, []);
|
|
620
|
+
const commands2 = generateShellCommands(diff2, options.shell);
|
|
621
|
+
const useColor2 = options.useColor ?? !process.env["NO_COLOR"];
|
|
622
|
+
const message2 = diff2.toUnset.length > 0 ? formatHookMessage(diff2, useColor2) : undefined;
|
|
623
|
+
return {
|
|
624
|
+
commands: commands2,
|
|
625
|
+
message: message2,
|
|
626
|
+
secrets: [],
|
|
627
|
+
unloadedKeys: diff2.toUnset,
|
|
628
|
+
trusted: false,
|
|
629
|
+
notTrustedReason: "autoload-disabled"
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
const trustResult = await this.isTrusted({ path: cwd });
|
|
633
|
+
if (!trustResult.trusted) {
|
|
634
|
+
const diff2 = computeHookDiff(previousKeys, []);
|
|
635
|
+
const commands2 = generateShellCommands(diff2, options.shell);
|
|
636
|
+
const useColor2 = options.useColor ?? !process.env["NO_COLOR"];
|
|
637
|
+
const message2 = diff2.toUnset.length > 0 ? formatHookMessage(diff2, useColor2) : undefined;
|
|
638
|
+
return {
|
|
639
|
+
commands: commands2,
|
|
640
|
+
message: message2,
|
|
641
|
+
secrets: [],
|
|
642
|
+
unloadedKeys: diff2.toUnset,
|
|
643
|
+
trusted: false,
|
|
644
|
+
notTrustedReason: trustResult.reason
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
const resolvedSecrets = await this.resolve(cwd);
|
|
648
|
+
const secrets = resolveToLoadedSecrets(resolvedSecrets);
|
|
649
|
+
const diff = computeHookDiff(previousKeys, secrets);
|
|
650
|
+
const commands = generateShellCommands(diff, options.shell);
|
|
651
|
+
const useColor = options.useColor ?? !process.env["NO_COLOR"];
|
|
652
|
+
const message = formatHookMessage(diff, useColor);
|
|
653
|
+
return {
|
|
654
|
+
commands,
|
|
655
|
+
message,
|
|
656
|
+
secrets,
|
|
657
|
+
unloadedKeys: diff.toUnset,
|
|
658
|
+
trusted: true
|
|
659
|
+
};
|
|
660
|
+
}
|
|
410
661
|
close() {
|
|
411
662
|
this.storage.close();
|
|
412
663
|
}
|