@dotenvx/dotenvx 2.1.0 → 2.1.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 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/v2.1.0...main)
5
+ [Unreleased](https://github.com/dotenvx/dotenvx/compare/v2.1.2...main)
6
+
7
+ ## [2.1.2](https://github.com/dotenvx/dotenvx/compare/v2.1.1...v2.1.2) (2026-07-02)
8
+
9
+ ### Changed
10
+
11
+ * Support restricted read permissions to `.env.keys` ([#676](https://github.com/dotenvx/dotenvx/issues/676), [#867](https://github.com/dotenvx/dotenvx/pull/867))
12
+
13
+ ## [2.1.1](https://github.com/dotenvx/dotenvx/compare/v2.1.0...v2.1.1) (2026-07-02)
14
+
15
+ ### Changed
16
+
17
+ * Support `DOTENV_CONFIG_QUIET=true` as synonym for `--quiet` flag ([#866](https://github.com/dotenvx/dotenvx/pull/866))
6
18
 
7
19
  ## [2.1.0](https://github.com/dotenvx/dotenvx/compare/v2.0.0...v2.1.0) (2026-07-02)
8
20
 
package/README.md CHANGED
@@ -672,6 +672,13 @@ $ dotenvx run -f .env.production --quiet -- node index.js
672
672
  Hello production
673
673
  ```
674
674
 
675
+ You can also set `DOTENV_CONFIG_QUIET=true`.
676
+
677
+ ```sh
678
+ $ DOTENV_CONFIG_QUIET=true dotenvx run -f .env.production -- node index.js
679
+ Hello production
680
+ ```
681
+
675
682
  </details>
676
683
  <details><summary>`--log-level` flag</summary><br>
677
684
 
@@ -723,6 +730,22 @@ $ dotenvx encrypt
723
730
 
724
731
  > A `DOTENV_PUBLIC_KEY` (encryption key) and a `DOTENV_PRIVATE_KEY` (decryption key) are generated using the same public-key cryptography as [Bitcoin](https://en.bitcoin.it/wiki/Secp256k1).
725
732
 
733
+ ### Protect `.env.keys` from agents
734
+
735
+ After encryption, `DOTENV_PUBLIC_KEY` lives in your encrypted `.env` file. This means agents and automation can keep running `dotenvx set` and `dotenvx encrypt` without reading `.env.keys`.
736
+
737
+ ```sh
738
+ $ chmod a-r .env.keys
739
+
740
+ $ dotenvx set HELLO World
741
+ ◈ encrypted HELLO (.env)
742
+
743
+ $ dotenvx encrypt
744
+ ◈ encrypted (.env)
745
+ ```
746
+
747
+ Keep `.env.keys` unreadable by agents, while still letting them safely update encrypted values.
748
+
726
749
  More examples
727
750
 
728
751
  <details><summary>`.env`</summary><br>
@@ -1231,6 +1254,13 @@ $ dotenvx run -f .env.production --quiet -- node index.js
1231
1254
  Hello production
1232
1255
  ```
1233
1256
 
1257
+ You can also set `DOTENV_CONFIG_QUIET=true`.
1258
+
1259
+ ```sh
1260
+ $ DOTENV_CONFIG_QUIET=true dotenvx run -f .env.production -- node index.js
1261
+ Hello production
1262
+ ```
1263
+
1234
1264
  </details>
1235
1265
  <details><summary>`run --log-level`</summary><br>
1236
1266
 
@@ -1572,6 +1602,8 @@ $ dotenvx set HELLO Dotenvx
1572
1602
  set HELLO with encryption (.env)
1573
1603
  ```
1574
1604
 
1605
+ Works with unreadable `.env.keys` when `.env` already contains `DOTENV_PUBLIC_KEY`.
1606
+
1575
1607
  </details>
1576
1608
  <details><summary>`set KEY value -f`</summary><br>
1577
1609
 
@@ -1646,6 +1678,20 @@ $ dotenvx set HELLO Dotenvx --plain
1646
1678
  set HELLO (.env)
1647
1679
  ```
1648
1680
 
1681
+ </details>
1682
+ <details><summary>`set KEY_PLAIN value`</summary><br>
1683
+
1684
+ Set a plaintext key/value inside an encrypted `.env` file by ending the key with `_PLAIN`.
1685
+
1686
+ ```sh
1687
+ $ touch .env
1688
+
1689
+ $ dotenvx set HELLO_PLAIN Dotenvx
1690
+ set HELLO_PLAIN (.env)
1691
+ ```
1692
+
1693
+ Keys ending in `_PLAIN` are not encrypted by `dotenvx set` or `dotenvx encrypt`.
1694
+
1649
1695
  </details>
1650
1696
  <details><summary>`encrypt`</summary><br>
1651
1697
 
@@ -1660,6 +1706,8 @@ $ dotenvx encrypt
1660
1706
  ⮕ next run [DOTENV_PRIVATE_KEY='122...0b8' dotenvx run -- yourcommand] to test decryption locally
1661
1707
  ```
1662
1708
 
1709
+ Works with unreadable `.env.keys` when `.env` already contains `DOTENV_PUBLIC_KEY`.
1710
+
1663
1711
  </details>
1664
1712
  <details><summary>`encrypt -f`</summary><br>
1665
1713
 
@@ -1755,6 +1803,20 @@ $ dotenvx encrypt -ek "HO*"
1755
1803
  ◈ encrypted (.env)
1756
1804
  ```
1757
1805
 
1806
+ </details>
1807
+ <details><summary>`encrypt KEY_PLAIN`</summary><br>
1808
+
1809
+ Skip encryption for keys ending in `_PLAIN`.
1810
+
1811
+ ```sh
1812
+ $ echo "HELLO=Dotenvx\nHELLO_PLAIN=visible" > .env
1813
+
1814
+ $ dotenvx encrypt
1815
+ ◈ encrypted (.env)
1816
+ ```
1817
+
1818
+ `HELLO` is encrypted. `HELLO_PLAIN` stays plaintext.
1819
+
1758
1820
  </details>
1759
1821
  <details><summary>`encrypt --stdout`</summary><br>
1760
1822
 
@@ -2398,6 +2460,14 @@ Error: [MISSING_ENV_FILE] missing .env.missing file (/path/to/.env.missing)
2398
2460
  Hello Dotenvx
2399
2461
  ```
2400
2462
 
2463
+ You can also set `DOTENV_CONFIG_QUIET=true`.
2464
+
2465
+ ```sh
2466
+ $ DOTENV_CONFIG_QUIET=true node index.js
2467
+ Error: [MISSING_ENV_FILE] missing .env.missing file (/path/to/.env.missing)
2468
+ Hello Dotenvx
2469
+ ```
2470
+
2401
2471
  </details>
2402
2472
  <details><summary>`config(strict: true)` - strict</summary><br>
2403
2473
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.1.0",
2
+ "version": "2.1.2",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "a secure dotenv–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -7,6 +7,7 @@ const catchAndLog = require('./../../lib/helpers/catchAndLog')
7
7
  const createSpinner = require('../../lib/helpers/createSpinner')
8
8
  const Session = require('../../db/session')
9
9
  const normalizeArmorAliases = require('./normalizeArmorAliases')
10
+ const normalizeDotenvConfigQuiet = require('../../lib/helpers/normalizeDotenvConfigQuiet')
10
11
 
11
12
  const conventions = require('./../../lib/helpers/conventions')
12
13
  const { determine } = require('./../../lib/helpers/envResolution')
@@ -45,7 +46,7 @@ function uniqueInjectedKeys (processedEnvs) {
45
46
  }
46
47
 
47
48
  async function run () {
48
- const options = normalizeArmorAliases(this.opts())
49
+ const options = normalizeDotenvConfigQuiet(normalizeArmorAliases(this.opts()))
49
50
 
50
51
  let commandArgs = this.args
51
52
  if (commandArgs.length < 1) {
@@ -12,6 +12,7 @@ const getCommanderVersion = require('./../lib/helpers/getCommanderVersion')
12
12
  const executeDynamic = require('./../lib/helpers/executeDynamic')
13
13
  const removeDynamicHelpSection = require('./../lib/helpers/removeDynamicHelpSection')
14
14
  const removeOptionsHelpParts = require('./../lib/helpers/removeOptionsHelpParts')
15
+ const normalizeDotenvConfigQuiet = require('./../lib/helpers/normalizeDotenvConfigQuiet')
15
16
 
16
17
  // for use with run
17
18
  const envs = []
@@ -38,7 +39,7 @@ program
38
39
  .option('-v, --verbose', 'sets log level to verbose')
39
40
  .option('-d, --debug', 'sets log level to debug')
40
41
  .hook('preAction', (thisCommand, actionCommand) => {
41
- const options = thisCommand.opts()
42
+ const options = normalizeDotenvConfigQuiet(thisCommand.opts())
42
43
 
43
44
  setLogLevel(options)
44
45
  })
@@ -0,0 +1,9 @@
1
+ function normalizeDotenvConfigQuiet (options) {
2
+ if (process.env.DOTENV_CONFIG_QUIET === 'true') {
3
+ options.quiet = true
4
+ }
5
+
6
+ return options
7
+ }
8
+
9
+ module.exports = normalizeDotenvConfigQuiet
package/src/lib/main.js CHANGED
@@ -22,6 +22,7 @@ const { determine } = require('./helpers/envResolution')
22
22
  const fsx = require('./helpers/fsx')
23
23
  const decryptKeyValue = require('./helpers/cryptography/decryptKeyValue')
24
24
  const Errors = require('./helpers/errors')
25
+ const normalizeDotenvConfigQuiet = require('./helpers/normalizeDotenvConfigQuiet')
25
26
 
26
27
  function uniqueInjectedKeys (processedEnvs) {
27
28
  const result = new Set()
@@ -35,6 +36,8 @@ function uniqueInjectedKeys (processedEnvs) {
35
36
 
36
37
  /** @type {import('./main').config} */
37
38
  const config = function (options = {}) {
39
+ options = normalizeDotenvConfigQuiet(options)
40
+
38
41
  // allow user to set processEnv to write to
39
42
  let processEnv = process.env
40
43
  if (options && options.processEnv != null) {
@@ -202,6 +205,8 @@ const parse = function (src, options = {}) {
202
205
 
203
206
  /* @type {import('./main').set} */
204
207
  const set = async function (key, value, options = {}) {
208
+ options = normalizeDotenvConfigQuiet(options)
209
+
205
210
  // encrypt
206
211
  let encrypt = true
207
212
  if (options.plain) {
@@ -45,8 +45,16 @@ async function encryptTransform (options = {}) {
45
45
  // set up keysSrc
46
46
  let keysSrc
47
47
  if (await fsx.exists(fk)) {
48
- const encoding = await detectEncoding(fk)
49
- keysSrc = await fsx.readFileX(fk, { encoding })
48
+ try {
49
+ const encoding = await detectEncoding(fk)
50
+ keysSrc = await fsx.readFileX(fk, { encoding })
51
+ } catch (err) {
52
+ if (err.code === 'EACCES' || err.code === 'EPERM') {
53
+ // do nothing (scenario: chmod a-r .env.keys)
54
+ } else {
55
+ throw err
56
+ }
57
+ }
50
58
  }
51
59
 
52
60
  for (const env of determine(envs, process.env)) {
@@ -46,8 +46,16 @@ async function setTransform (options = {}) {
46
46
  // set up keysSrc
47
47
  let keysSrc
48
48
  if (await fsx.exists(fk)) {
49
- const encoding = await detectEncoding(fk)
50
- keysSrc = await fsx.readFileX(fk, { encoding })
49
+ try {
50
+ const encoding = await detectEncoding(fk)
51
+ keysSrc = await fsx.readFileX(fk, { encoding })
52
+ } catch (err) {
53
+ if (err.code === 'EACCES' || err.code === 'EPERM') {
54
+ // do nothing (scenario: chmod a-r .env.keys)
55
+ } else {
56
+ throw err
57
+ }
58
+ }
51
59
  }
52
60
 
53
61
  for (const env of determine(envs, process.env)) {