lsh-framework 1.7.4 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -159,8 +159,8 @@ export class SecretsManager {
|
|
|
159
159
|
}
|
|
160
160
|
message += `\nThis is likely unintentional and could break your application.\n\n`;
|
|
161
161
|
message += `To proceed anyway, use the --force flag:\n`;
|
|
162
|
-
message += ` lsh
|
|
163
|
-
message += ` lsh
|
|
162
|
+
message += ` lsh push --force\n`;
|
|
163
|
+
message += ` lsh sync --force\n`;
|
|
164
164
|
return message;
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
@@ -505,7 +505,7 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
505
505
|
* Smart sync command - automatically set up and synchronize secrets
|
|
506
506
|
* This is the new enhanced sync that does everything automatically
|
|
507
507
|
*/
|
|
508
|
-
async smartSync(envFilePath = '.env', environment = 'dev', autoExecute = true, loadMode = false, force = false) {
|
|
508
|
+
async smartSync(envFilePath = '.env', environment = 'dev', autoExecute = true, loadMode = false, force = false, forceRekey = false) {
|
|
509
509
|
// In load mode, suppress all logger output to prevent zsh glob interpretation
|
|
510
510
|
// Save original level and restore at the end
|
|
511
511
|
const originalLogLevel = loadMode ? logger['config'].level : undefined;
|
|
@@ -551,11 +551,40 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
551
551
|
// Step 4: Determine action and execute if auto mode
|
|
552
552
|
let _action = 'in-sync';
|
|
553
553
|
if (status.cloudExists && status.keyMatches === false) {
|
|
554
|
+
if (forceRekey) {
|
|
555
|
+
// Force re-keying: push local secrets with current key
|
|
556
|
+
_action = 'push';
|
|
557
|
+
out('🔄 Force re-keying: Re-encrypting cloud secrets with current key...');
|
|
558
|
+
if (autoExecute) {
|
|
559
|
+
if (!status.localExists) {
|
|
560
|
+
out('❌ Cannot re-key: No local .env file found');
|
|
561
|
+
out(`💡 Pull with original key first, or create new .env`);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
out(' Pushing to cloud with new key...');
|
|
565
|
+
await this.push(envFilePath, environment, true); // Force push (use original environment, not effectiveEnv)
|
|
566
|
+
out();
|
|
567
|
+
out('✅ Re-keying complete! Cloud secrets now encrypted with current key.');
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
out('💡 Run: lsh push -f ${envFilePath} -e ${environment}');
|
|
571
|
+
}
|
|
572
|
+
out();
|
|
573
|
+
// Output export commands in load mode
|
|
574
|
+
if (loadMode && fs.existsSync(envFilePath)) {
|
|
575
|
+
console.log(this.generateExportCommands(envFilePath));
|
|
576
|
+
}
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
// No force-rekey: show error and options
|
|
554
580
|
_action = 'key-mismatch';
|
|
555
581
|
out('⚠️ Encryption key mismatch!');
|
|
556
582
|
out(' The local key does not match the cloud storage.');
|
|
557
|
-
out(
|
|
558
|
-
out(
|
|
583
|
+
out();
|
|
584
|
+
out(' Options:');
|
|
585
|
+
out(` 1. Use the original key (recommended if you have it)`);
|
|
586
|
+
out(` 2. Re-encrypt with current key: lsh push -f ${envFilePath} -e ${environment}`);
|
|
587
|
+
out(` 3. Re-key during sync: lsh sync --force-rekey -f ${envFilePath} -e ${environment}`);
|
|
559
588
|
out();
|
|
560
589
|
return;
|
|
561
590
|
}
|
|
@@ -571,7 +600,7 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
571
600
|
out('✅ Setup complete! Edit your .env and run sync again to update.');
|
|
572
601
|
}
|
|
573
602
|
else {
|
|
574
|
-
out('💡 Run: lsh
|
|
603
|
+
out('💡 Run: lsh create && lsh push');
|
|
575
604
|
}
|
|
576
605
|
out();
|
|
577
606
|
// Output export commands in load mode
|
|
@@ -589,7 +618,7 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
589
618
|
out('✅ Secrets pushed to cloud!');
|
|
590
619
|
}
|
|
591
620
|
else {
|
|
592
|
-
out(`💡 Run: lsh
|
|
621
|
+
out(`💡 Run: lsh push -f ${envFilePath} -e ${environment}`);
|
|
593
622
|
}
|
|
594
623
|
out();
|
|
595
624
|
// Output export commands in load mode
|
|
@@ -607,7 +636,7 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
607
636
|
out('✅ Secrets pulled from cloud!');
|
|
608
637
|
}
|
|
609
638
|
else {
|
|
610
|
-
out(`💡 Run: lsh
|
|
639
|
+
out(`💡 Run: lsh pull -f ${envFilePath} -e ${environment}`);
|
|
611
640
|
}
|
|
612
641
|
out();
|
|
613
642
|
// Output export commands in load mode
|
|
@@ -644,7 +673,7 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
644
673
|
out('✅ Secrets synced to cloud!');
|
|
645
674
|
}
|
|
646
675
|
else {
|
|
647
|
-
out(`💡 Run: lsh
|
|
676
|
+
out(`💡 Run: lsh push -f ${envFilePath} -e ${environment}`);
|
|
648
677
|
}
|
|
649
678
|
}
|
|
650
679
|
else {
|
|
@@ -658,7 +687,7 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
658
687
|
out('✅ Secrets synced from cloud!');
|
|
659
688
|
}
|
|
660
689
|
else {
|
|
661
|
-
out(`💡 Run: lsh
|
|
690
|
+
out(`💡 Run: lsh pull -f ${envFilePath} -e ${environment}`);
|
|
662
691
|
}
|
|
663
692
|
}
|
|
664
693
|
out();
|
|
@@ -723,22 +752,22 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
723
752
|
const suggestions = [];
|
|
724
753
|
if (!status.keySet) {
|
|
725
754
|
suggestions.push('⚠️ No encryption key set!');
|
|
726
|
-
suggestions.push(' Generate a key: lsh
|
|
755
|
+
suggestions.push(' Generate a key: lsh key');
|
|
727
756
|
suggestions.push(' Add it to .env: LSH_SECRETS_KEY=<your-key>');
|
|
728
757
|
suggestions.push(' Load it: export $(cat .env | xargs)');
|
|
729
758
|
}
|
|
730
759
|
if (status.cloudExists && status.keyMatches === false) {
|
|
731
760
|
suggestions.push('⚠️ Encryption key does not match cloud storage!');
|
|
732
761
|
suggestions.push(' Either use the original key, or push new secrets:');
|
|
733
|
-
suggestions.push(` lsh
|
|
762
|
+
suggestions.push(` lsh push -f ${envFilePath} -e ${environment}`);
|
|
734
763
|
}
|
|
735
764
|
if (!status.localExists && status.cloudExists && status.keyMatches) {
|
|
736
765
|
suggestions.push('💡 Cloud secrets available but no local file');
|
|
737
|
-
suggestions.push(` Pull from cloud: lsh
|
|
766
|
+
suggestions.push(` Pull from cloud: lsh pull -f ${envFilePath} -e ${environment}`);
|
|
738
767
|
}
|
|
739
768
|
if (status.localExists && !status.cloudExists) {
|
|
740
769
|
suggestions.push('💡 Local .env exists but not in cloud');
|
|
741
|
-
suggestions.push(` Push to cloud: lsh
|
|
770
|
+
suggestions.push(` Push to cloud: lsh push -f ${envFilePath} -e ${environment}`);
|
|
742
771
|
}
|
|
743
772
|
if (status.localExists && status.cloudExists && status.keyMatches) {
|
|
744
773
|
if (status.localModified && status.cloudModified) {
|
|
@@ -747,11 +776,11 @@ LSH_SECRETS_KEY=${this.encryptionKey}
|
|
|
747
776
|
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
|
|
748
777
|
if (localNewer && daysDiff > 0) {
|
|
749
778
|
suggestions.push('💡 Local file is newer than cloud');
|
|
750
|
-
suggestions.push(` Push to cloud: lsh
|
|
779
|
+
suggestions.push(` Push to cloud: lsh push -f ${envFilePath} -e ${environment}`);
|
|
751
780
|
}
|
|
752
781
|
else if (!localNewer && daysDiff > 0) {
|
|
753
782
|
suggestions.push('💡 Cloud is newer than local file');
|
|
754
|
-
suggestions.push(` Pull from cloud: lsh
|
|
783
|
+
suggestions.push(` Pull from cloud: lsh pull -f ${envFilePath} -e ${environment}`);
|
|
755
784
|
}
|
|
756
785
|
else {
|
|
757
786
|
suggestions.push('✅ Local and cloud are in sync!');
|
|
@@ -250,7 +250,7 @@ API_KEY=
|
|
|
250
250
|
console.log('');
|
|
251
251
|
console.log('Next steps:');
|
|
252
252
|
console.log(` 1. Edit the file: ${options.file}`);
|
|
253
|
-
console.log(` 2. Push to cloud: lsh
|
|
253
|
+
console.log(` 2. Push to cloud: lsh push -f ${options.file}`);
|
|
254
254
|
console.log('');
|
|
255
255
|
}
|
|
256
256
|
catch (error) {
|
|
@@ -269,6 +269,7 @@ API_KEY=
|
|
|
269
269
|
.option('--legacy', 'Use legacy sync mode (suggestions only)')
|
|
270
270
|
.option('--load', 'Output eval-able export commands for loading secrets')
|
|
271
271
|
.option('--force', 'Force sync even if destructive changes detected')
|
|
272
|
+
.option('--force-rekey', 'Re-encrypt cloud secrets with current local key (use when key mismatch)')
|
|
272
273
|
.action(async (options) => {
|
|
273
274
|
const manager = new SecretsManager();
|
|
274
275
|
try {
|
|
@@ -278,7 +279,7 @@ API_KEY=
|
|
|
278
279
|
}
|
|
279
280
|
else {
|
|
280
281
|
// Use new smart sync (auto-execute)
|
|
281
|
-
await manager.smartSync(options.file, options.env, !options.dryRun, options.load, options.force);
|
|
282
|
+
await manager.smartSync(options.file, options.env, !options.dryRun, options.load, options.force, options.forceRekey);
|
|
282
283
|
}
|
|
283
284
|
}
|
|
284
285
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsh-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Simple, cross-platform encrypted secrets manager with automatic sync, IPFS audit logs, and multi-environment support. Just run lsh sync and start managing your secrets.",
|
|
5
5
|
"main": "dist/app.js",
|
|
6
6
|
"bin": {
|