lsh-framework 0.9.2 ā 0.10.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/dist/cli.js +3 -2
- package/dist/services/secrets/secrets.js +106 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -75,11 +75,12 @@ program
|
|
|
75
75
|
console.log(' sync Check sync status & get recommendations');
|
|
76
76
|
console.log(' push Upload .env to encrypted cloud storage');
|
|
77
77
|
console.log(' pull Download .env from cloud storage');
|
|
78
|
-
console.log(' list List
|
|
78
|
+
console.log(' list List secrets in current local .env file');
|
|
79
|
+
console.log(' env List all stored environments');
|
|
79
80
|
console.log(' show View secrets (masked)');
|
|
80
81
|
console.log(' key Generate encryption key');
|
|
81
82
|
console.log(' create Create new .env file');
|
|
82
|
-
console.log(' get <key> Get a specific secret value');
|
|
83
|
+
console.log(' get <key> Get a specific secret value (--all for all)');
|
|
83
84
|
console.log(' set <key> <value> Set a specific secret value');
|
|
84
85
|
console.log(' delete Delete .env file');
|
|
85
86
|
console.log(' status Get detailed secrets status');
|
|
@@ -43,10 +43,71 @@ export async function init_secrets(program) {
|
|
|
43
43
|
process.exit(1);
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
|
-
// List
|
|
46
|
+
// List current local secrets
|
|
47
47
|
program
|
|
48
|
-
.command('list
|
|
48
|
+
.command('list')
|
|
49
49
|
.alias('ls')
|
|
50
|
+
.description('List secrets in the current local .env file')
|
|
51
|
+
.option('-f, --file <path>', 'Path to .env file', '.env')
|
|
52
|
+
.option('--keys-only', 'Show only keys, not values')
|
|
53
|
+
.action(async (options) => {
|
|
54
|
+
try {
|
|
55
|
+
const envPath = path.resolve(options.file);
|
|
56
|
+
if (!fs.existsSync(envPath)) {
|
|
57
|
+
console.error(`ā File not found: ${envPath}`);
|
|
58
|
+
console.log('š” Tip: Pull from cloud with: lsh pull --env <environment>');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
const content = fs.readFileSync(envPath, 'utf8');
|
|
62
|
+
const lines = content.split('\n');
|
|
63
|
+
const secrets = [];
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
if (line.trim().startsWith('#') || !line.trim())
|
|
66
|
+
continue;
|
|
67
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
68
|
+
if (match) {
|
|
69
|
+
const key = match[1].trim();
|
|
70
|
+
let value = match[2].trim();
|
|
71
|
+
// Remove quotes if present
|
|
72
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
73
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
74
|
+
value = value.slice(1, -1);
|
|
75
|
+
}
|
|
76
|
+
secrets.push({ key, value });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (secrets.length === 0) {
|
|
80
|
+
console.log('No secrets found in .env file');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.log(`\nš Secrets in ${options.file}:\n`);
|
|
84
|
+
for (const { key, value } of secrets) {
|
|
85
|
+
if (options.keysOnly) {
|
|
86
|
+
console.log(` ${key}`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// Mask the value but show first/last 3 chars if long enough
|
|
90
|
+
let maskedValue = value;
|
|
91
|
+
if (value.length > 8) {
|
|
92
|
+
maskedValue = `${value.substring(0, 3)}${'*'.repeat(value.length - 6)}${value.substring(value.length - 3)}`;
|
|
93
|
+
}
|
|
94
|
+
else if (value.length > 0) {
|
|
95
|
+
maskedValue = '*'.repeat(value.length);
|
|
96
|
+
}
|
|
97
|
+
console.log(` ${key}=${maskedValue}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
console.log(`\n Total: ${secrets.length} secrets\n`);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
const err = error;
|
|
104
|
+
console.error('ā Failed to list secrets:', err.message);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// Manage environments (old 'list' functionality)
|
|
109
|
+
program
|
|
110
|
+
.command('env [environment]')
|
|
50
111
|
.description('List all stored environments or show secrets for specific environment')
|
|
51
112
|
.option('--all-files', 'List all tracked .env files across environments')
|
|
52
113
|
.action(async (environment, options) => {
|
|
@@ -220,9 +281,11 @@ API_KEY=
|
|
|
220
281
|
});
|
|
221
282
|
// Get a specific secret value
|
|
222
283
|
program
|
|
223
|
-
.command('get
|
|
224
|
-
.description('Get a specific secret value from .env file')
|
|
284
|
+
.command('get [key]')
|
|
285
|
+
.description('Get a specific secret value from .env file, or all secrets with --all')
|
|
225
286
|
.option('-f, --file <path>', 'Path to .env file', '.env')
|
|
287
|
+
.option('--all', 'Get all secrets from the file')
|
|
288
|
+
.option('--export', 'Output in export format for shell evaluation')
|
|
226
289
|
.action(async (key, options) => {
|
|
227
290
|
try {
|
|
228
291
|
const envPath = path.resolve(options.file);
|
|
@@ -232,6 +295,45 @@ API_KEY=
|
|
|
232
295
|
}
|
|
233
296
|
const content = fs.readFileSync(envPath, 'utf8');
|
|
234
297
|
const lines = content.split('\n');
|
|
298
|
+
// Handle --all flag
|
|
299
|
+
if (options.all) {
|
|
300
|
+
const secrets = [];
|
|
301
|
+
for (const line of lines) {
|
|
302
|
+
if (line.trim().startsWith('#') || !line.trim())
|
|
303
|
+
continue;
|
|
304
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
305
|
+
if (match) {
|
|
306
|
+
const key = match[1].trim();
|
|
307
|
+
let value = match[2].trim();
|
|
308
|
+
// Remove quotes if present
|
|
309
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
310
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
311
|
+
value = value.slice(1, -1);
|
|
312
|
+
}
|
|
313
|
+
secrets.push({ key, value });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (options.export) {
|
|
317
|
+
// Output in export format for shell evaluation
|
|
318
|
+
for (const { key, value } of secrets) {
|
|
319
|
+
// Escape single quotes in value and wrap in single quotes
|
|
320
|
+
const escapedValue = value.replace(/'/g, "'\\''");
|
|
321
|
+
console.log(`export ${key}='${escapedValue}'`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// Output in KEY=VALUE format
|
|
326
|
+
for (const { key, value } of secrets) {
|
|
327
|
+
console.log(`${key}=${value}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
// Handle single key lookup
|
|
333
|
+
if (!key) {
|
|
334
|
+
console.error('ā Please provide a key or use --all flag');
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
235
337
|
for (const line of lines) {
|
|
236
338
|
if (line.trim().startsWith('#') || !line.trim())
|
|
237
339
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsh-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Encrypted secrets manager with automatic rotation, team sync, and multi-environment support. Built on a powerful shell with daemon scheduling and CI/CD integration.",
|
|
5
5
|
"main": "dist/app.js",
|
|
6
6
|
"bin": {
|