@dotenvx/dotenvx 1.60.0 → 1.60.2
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/CHANGELOG.md +13 -1
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/cli/actions/encrypt.js +8 -10
- package/src/cli/actions/rotate.js +11 -6
- package/src/cli/actions/set.js +12 -5
- package/src/lib/helpers/cryptography/provision.js +8 -4
- package/src/lib/helpers/cryptography/provisionSync.js +8 -4
- package/src/lib/main.d.ts +2 -1
- package/src/lib/main.js +12 -4
- package/src/lib/services/encrypt.js +2 -1
- package/src/lib/services/rotate.js +4 -2
- package/src/lib/services/sets.js +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.60.
|
|
5
|
+
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.60.2...main)
|
|
6
|
+
|
|
7
|
+
## [1.60.2](https://github.com/dotenvx/dotenvx/compare/v1.60.1...v1.60.2) (2026-04-07)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
* Communicate `local key` and `armored key` (for Ops stored keys) ([#778](https://github.com/dotenvx/dotenvx/pull/778))
|
|
12
|
+
|
|
13
|
+
## [1.60.1](https://github.com/dotenvx/dotenvx/compare/v1.60.0...v1.60.1) (2026-04-06)
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
* Added missing `+ key ⛨` for Ops stored keys ([#777](https://github.com/dotenvx/dotenvx/pull/777))
|
|
6
18
|
|
|
7
19
|
## [1.60.0](https://github.com/dotenvx/dotenvx/compare/v1.59.1...v1.60.0) (2026-04-04)
|
|
8
20
|
|
package/README.md
CHANGED
|
@@ -1572,7 +1572,7 @@ Encrypt the contents of a `.env` file to an encrypted `.env` file.
|
|
|
1572
1572
|
$ echo "HELLO=Dotenvx" > .env
|
|
1573
1573
|
|
|
1574
1574
|
$ dotenvx encrypt
|
|
1575
|
-
◈ encrypted (.env) + key (.env.keys)
|
|
1575
|
+
◈ encrypted (.env) + local key (.env.keys)
|
|
1576
1576
|
⮕ next run [dotenvx ext gitignore --pattern .env.keys] to gitignore .env.keys
|
|
1577
1577
|
⮕ next run [DOTENV_PRIVATE_KEY='122...0b8' dotenvx run -- yourcommand] to test decryption locally
|
|
1578
1578
|
```
|
|
@@ -1587,7 +1587,7 @@ $ echo "HELLO=Dotenvx" > .env
|
|
|
1587
1587
|
$ echo "HELLO=Production" > .env.production
|
|
1588
1588
|
|
|
1589
1589
|
$ dotenvx encrypt -f .env.production
|
|
1590
|
-
◈ encrypted (.env.production) + key (.env.keys)
|
|
1590
|
+
◈ encrypted (.env.production) + local key (.env.keys)
|
|
1591
1591
|
⮕ next run [dotenvx ext gitignore --pattern .env.keys] to gitignore .env.keys
|
|
1592
1592
|
⮕ next run [DOTENV_PRIVATE_KEY='bff...bc4' dotenvx run -- yourcommand] to test decryption locally
|
|
1593
1593
|
```
|
package/package.json
CHANGED
|
@@ -52,11 +52,15 @@ async function encrypt () {
|
|
|
52
52
|
|
|
53
53
|
if (spinner) spinner.stop()
|
|
54
54
|
if (changedFilepaths.length > 0) {
|
|
55
|
-
const
|
|
55
|
+
const localKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.localPrivateKeyAdded)
|
|
56
|
+
const remoteKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.remotePrivateKeyAdded)
|
|
56
57
|
let msg = `◈ encrypted (${changedFilepaths.join(',')})`
|
|
57
|
-
if (
|
|
58
|
-
const envKeysFilepath = localDisplayPath(
|
|
59
|
-
msg += ` + key (${envKeysFilepath})`
|
|
58
|
+
if (localKeyAddedEnv) {
|
|
59
|
+
const envKeysFilepath = localDisplayPath(localKeyAddedEnv.envKeysFilepath)
|
|
60
|
+
msg += ` + local key (${envKeysFilepath})`
|
|
61
|
+
}
|
|
62
|
+
if (remoteKeyAddedEnv) {
|
|
63
|
+
msg += ' + armored key ⛨'
|
|
60
64
|
}
|
|
61
65
|
logger.success(msg)
|
|
62
66
|
} else if (unchangedFilepaths.length > 0) {
|
|
@@ -64,12 +68,6 @@ async function encrypt () {
|
|
|
64
68
|
} else {
|
|
65
69
|
// do nothing - scenario when no .env files found
|
|
66
70
|
}
|
|
67
|
-
|
|
68
|
-
for (const processedEnv of processedEnvs) {
|
|
69
|
-
if (processedEnv.privateKeyAdded) {
|
|
70
|
-
// intentionally quiet: success line already communicates key creation
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
71
|
} catch (error) {
|
|
74
72
|
if (spinner) spinner.stop()
|
|
75
73
|
catchAndLog(error)
|
|
@@ -26,7 +26,7 @@ async function rotate () {
|
|
|
26
26
|
if (spinner) spinner.stop()
|
|
27
27
|
for (const processedEnv of processedEnvs) {
|
|
28
28
|
console.log(processedEnv.envSrc)
|
|
29
|
-
if (processedEnv.
|
|
29
|
+
if (processedEnv.localPrivateKeyAdded) {
|
|
30
30
|
console.log('')
|
|
31
31
|
console.log(processedEnv.envKeysSrc)
|
|
32
32
|
}
|
|
@@ -46,7 +46,7 @@ async function rotate () {
|
|
|
46
46
|
logger.warn(processedEnv.error.messageWithHelp)
|
|
47
47
|
} else if (processedEnv.changed) {
|
|
48
48
|
await fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
49
|
-
if (processedEnv.
|
|
49
|
+
if (processedEnv.localPrivateKeyAdded) {
|
|
50
50
|
await fsx.writeFileX(processedEnv.envKeysFilepath, processedEnv.envKeysSrc)
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -58,11 +58,16 @@ async function rotate () {
|
|
|
58
58
|
|
|
59
59
|
if (spinner) spinner.stop()
|
|
60
60
|
if (changedFilepaths.length > 0) {
|
|
61
|
-
const
|
|
61
|
+
const localKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.localPrivateKeyAdded)
|
|
62
|
+
const remoteKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.remotePrivateKeyAdded)
|
|
63
|
+
|
|
62
64
|
let msg = `⟳ rotated (${changedFilepaths.join(',')})`
|
|
63
|
-
if (
|
|
64
|
-
const envKeysFilepath = localDisplayPath(
|
|
65
|
-
msg += ` + key (${envKeysFilepath})`
|
|
65
|
+
if (localKeyAddedEnv) {
|
|
66
|
+
const envKeysFilepath = localDisplayPath(localKeyAddedEnv.envKeysFilepath)
|
|
67
|
+
msg += ` + local key (${envKeysFilepath})`
|
|
68
|
+
}
|
|
69
|
+
if (remoteKeyAddedEnv) {
|
|
70
|
+
msg += ' + armored key ⛨'
|
|
66
71
|
}
|
|
67
72
|
logger.success(msg)
|
|
68
73
|
} else if (unchangedFilepaths.length > 0) {
|
package/src/cli/actions/set.js
CHANGED
|
@@ -55,8 +55,15 @@ async function set (key, value) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
const
|
|
59
|
-
const
|
|
58
|
+
const localKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.localPrivateKeyAdded)
|
|
59
|
+
const remoteKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.remotePrivateKeyAdded)
|
|
60
|
+
let keyAddedSuffix = ''
|
|
61
|
+
if (localKeyAddedEnv) {
|
|
62
|
+
keyAddedSuffix = ` + local key (${localDisplayPath(localKeyAddedEnv.envKeysFilepath)})`
|
|
63
|
+
}
|
|
64
|
+
if (remoteKeyAddedEnv) {
|
|
65
|
+
keyAddedSuffix = ' + armored key ⛨'
|
|
66
|
+
}
|
|
60
67
|
|
|
61
68
|
if (spinner) spinner.stop()
|
|
62
69
|
if (changedFilepaths.length > 0) {
|
|
@@ -65,9 +72,9 @@ async function set (key, value) {
|
|
|
65
72
|
} else {
|
|
66
73
|
logger.success(`◇ set ${key} (${changedFilepaths.join(',')})`)
|
|
67
74
|
}
|
|
68
|
-
} else if (encrypt &&
|
|
69
|
-
const
|
|
70
|
-
logger.success(`◈ encrypted ${key} (${
|
|
75
|
+
} else if (encrypt && localKeyAddedEnv) { // TODO: this needs to take into account remoteKeyAddedEnv
|
|
76
|
+
const localKeyAddedEnvFilepath = localKeyAddedEnv.envFilepath || changedFilepaths[0] || '.env'
|
|
77
|
+
logger.success(`◈ encrypted ${key} (${localKeyAddedEnvFilepath})${keyAddedSuffix}`)
|
|
71
78
|
} else if (unchangedFilepaths.length > 0) {
|
|
72
79
|
logger.info(`○ no change (${unchangedFilepaths})`)
|
|
73
80
|
} else {
|
|
@@ -12,7 +12,8 @@ async function provision ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
|
12
12
|
let privateKey
|
|
13
13
|
let keysSrc
|
|
14
14
|
let envKeysFilepath
|
|
15
|
-
let
|
|
15
|
+
let localPrivateKeyAdded = false
|
|
16
|
+
let remotePrivateKeyAdded = false
|
|
16
17
|
|
|
17
18
|
if (noOps) {
|
|
18
19
|
const kp = localKeypair()
|
|
@@ -31,7 +32,9 @@ async function provision ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
|
31
32
|
const mutated = await mutateKeysSrc({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
|
32
33
|
keysSrc = mutated.keysSrc
|
|
33
34
|
envKeysFilepath = mutated.envKeysFilepath
|
|
34
|
-
|
|
35
|
+
localPrivateKeyAdded = true
|
|
36
|
+
} else {
|
|
37
|
+
remotePrivateKeyAdded = true
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
return {
|
|
@@ -39,8 +42,9 @@ async function provision ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
|
39
42
|
keysSrc,
|
|
40
43
|
publicKey,
|
|
41
44
|
privateKey,
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
envKeysFilepath,
|
|
46
|
+
localPrivateKeyAdded,
|
|
47
|
+
remotePrivateKeyAdded
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -12,7 +12,8 @@ function provisionSync ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
|
12
12
|
let privateKey
|
|
13
13
|
let keysSrc
|
|
14
14
|
let envKeysFilepath
|
|
15
|
-
let
|
|
15
|
+
let localPrivateKeyAdded = false
|
|
16
|
+
let remotePrivateKeyAdded = false
|
|
16
17
|
|
|
17
18
|
if (noOps) {
|
|
18
19
|
const kp = localKeypair()
|
|
@@ -31,7 +32,9 @@ function provisionSync ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
|
31
32
|
const mutated = mutateKeysSrcSync({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
|
32
33
|
keysSrc = mutated.keysSrc
|
|
33
34
|
envKeysFilepath = mutated.envKeysFilepath
|
|
34
|
-
|
|
35
|
+
localPrivateKeyAdded = true
|
|
36
|
+
} else {
|
|
37
|
+
remotePrivateKeyAdded = true
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
return {
|
|
@@ -39,8 +42,9 @@ function provisionSync ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
|
39
42
|
keysSrc,
|
|
40
43
|
publicKey,
|
|
41
44
|
privateKey,
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
envKeysFilepath,
|
|
46
|
+
localPrivateKeyAdded,
|
|
47
|
+
remotePrivateKeyAdded
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
|
package/src/lib/main.d.ts
CHANGED
|
@@ -235,7 +235,8 @@ export type SetProcessedEnv = {
|
|
|
235
235
|
encryptedValue?: string;
|
|
236
236
|
publicKey?: string;
|
|
237
237
|
privateKey?: string;
|
|
238
|
-
|
|
238
|
+
localPrivateKeyAdded?: boolean;
|
|
239
|
+
remotePrivateKeyAdded?: boolean;
|
|
239
240
|
privateKeyName?: string;
|
|
240
241
|
error?: Error;
|
|
241
242
|
};
|
package/src/lib/main.js
CHANGED
|
@@ -194,8 +194,16 @@ const set = function (key, value, options = {}) {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
const
|
|
197
|
+
let keyAddedSuffix = ''
|
|
198
|
+
const localKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.localPrivateKeyAdded)
|
|
199
|
+
const remoteKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.remotePrivateKeyAdded)
|
|
200
|
+
|
|
201
|
+
if (localKeyAddedEnv) {
|
|
202
|
+
keyAddedSuffix = ` + local key (${localDisplayPath(localKeyAddedEnv.envKeysFilepath)})`
|
|
203
|
+
}
|
|
204
|
+
if (remoteKeyAddedEnv) {
|
|
205
|
+
keyAddedSuffix = ' + armored key ⛨'
|
|
206
|
+
}
|
|
199
207
|
|
|
200
208
|
if (changedFilepaths.length > 0) {
|
|
201
209
|
if (encrypt) {
|
|
@@ -203,8 +211,8 @@ const set = function (key, value, options = {}) {
|
|
|
203
211
|
} else {
|
|
204
212
|
logger.success(`◇ set ${key} (${changedFilepaths.join(',')})`)
|
|
205
213
|
}
|
|
206
|
-
} else if (encrypt &&
|
|
207
|
-
const keyAddedEnvFilepath =
|
|
214
|
+
} else if (encrypt && localKeyAddedEnv) {
|
|
215
|
+
const keyAddedEnvFilepath = localKeyAddedEnv.envFilepath || changedFilepaths[0] || '.env'
|
|
208
216
|
logger.success(`◈ encrypted ${key} (${keyAddedEnvFilepath})${keyAddedSuffix}`)
|
|
209
217
|
} else if (unchangedFilepaths.length > 0) {
|
|
210
218
|
logger.info(`○ no change (${unchangedFilepaths})`)
|
|
@@ -105,7 +105,8 @@ class Encrypt {
|
|
|
105
105
|
envSrc = prov.envSrc
|
|
106
106
|
publicKey = prov.publicKey
|
|
107
107
|
privateKey = prov.privateKey
|
|
108
|
-
row.
|
|
108
|
+
row.localPrivateKeyAdded = prov.localPrivateKeyAdded
|
|
109
|
+
row.remotePrivateKeyAdded = prov.remotePrivateKeyAdded
|
|
109
110
|
row.envKeysFilepath = prov.envKeysFilepath
|
|
110
111
|
} else if (privateKeyValue) {
|
|
111
112
|
const prov = provisionWithPrivateKey({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, privateKeyValue, publicKeyValue, publicKeyName })
|
|
@@ -95,7 +95,8 @@ class Rotate {
|
|
|
95
95
|
newPublicKey = kp.publicKey
|
|
96
96
|
newPrivateKey = kp.privateKey
|
|
97
97
|
|
|
98
|
-
row.
|
|
98
|
+
row.localPrivateKeyAdded = false
|
|
99
|
+
row.remotePrivateKeyAdded = true
|
|
99
100
|
} else {
|
|
100
101
|
row.envKeysFilepath = this.envKeysFilepath || path.join(path.dirname(envFilepath), '.env.keys')
|
|
101
102
|
envKeysFilepath = path.resolve(row.envKeysFilepath)
|
|
@@ -107,7 +108,8 @@ class Rotate {
|
|
|
107
108
|
newPublicKey = kp.publicKey
|
|
108
109
|
newPrivateKey = kp.privateKey
|
|
109
110
|
|
|
110
|
-
row.
|
|
111
|
+
row.localPrivateKeyAdded = true
|
|
112
|
+
row.remotePrivateKeyAdded = false
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
// .env
|
package/src/lib/services/sets.js
CHANGED
|
@@ -135,8 +135,9 @@ class Sets {
|
|
|
135
135
|
envSrc = prov.envSrc
|
|
136
136
|
publicKey = prov.publicKey
|
|
137
137
|
privateKey = prov.privateKey
|
|
138
|
-
row.privateKeyAdded = prov.privateKeyAdded
|
|
139
138
|
row.envKeysFilepath = prov.envKeysFilepath
|
|
139
|
+
row.localPrivateKeyAdded = prov.localPrivateKeyAdded
|
|
140
|
+
row.remotePrivateKeyAdded = prov.remotePrivateKeyAdded
|
|
140
141
|
} else if (privateKeyValue) {
|
|
141
142
|
const prov = provisionWithPrivateKey({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, privateKeyValue, publicKeyValue, publicKeyName })
|
|
142
143
|
publicKey = prov.publicKey
|
|
@@ -240,8 +241,9 @@ class Sets {
|
|
|
240
241
|
envSrc = prov.envSrc
|
|
241
242
|
publicKey = prov.publicKey
|
|
242
243
|
privateKey = prov.privateKey
|
|
243
|
-
row.privateKeyAdded = prov.privateKeyAdded
|
|
244
244
|
row.envKeysFilepath = prov.envKeysFilepath
|
|
245
|
+
row.localPrivateKeyAdded = prov.localPrivateKeyAdded
|
|
246
|
+
row.remotePrivateKeyAdded = prov.remotePrivateKeyAdded
|
|
245
247
|
} else if (privateKeyValue) {
|
|
246
248
|
const prov = provisionWithPrivateKey({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, privateKeyValue, publicKeyValue, publicKeyName })
|
|
247
249
|
publicKey = prov.publicKey
|