@dotenvx/dotenvx 2.14.0 → 2.15.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.
- package/CHANGELOG.md +13 -1
- package/README.md +84 -24
- package/package.json +11 -2
- package/src/cli/actions/get.js +2 -0
- package/src/cli/actions/run.js +2 -0
- package/src/cli/actions/validate.js +2 -0
- package/src/cli/dotenvx.js +23 -17
- package/src/lib/helpers/createElapsedStatus.js +17 -0
- package/src/lib/helpers/createSpinner.js +17 -1
- package/src/lib/helpers/errors.js +26 -0
- package/src/lib/helpers/resolveBitwardenPassword.js +164 -0
- package/src/lib/helpers/resolveOnePassword.js +84 -0
- package/src/lib/main.d.ts +32 -0
- package/src/lib/main.js +5 -1
- package/src/lib/resolvers/envs.js +80 -9
- package/src/lib/resolvers/get.js +2 -0
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.
|
|
5
|
+
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v2.15.1...main)
|
|
6
|
+
|
|
7
|
+
## [2.15.1](https://github.com/dotenvx/dotenvx/compare/v2.15.0...v2.15.1) (2026-07-20)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
* Better communicate time waiting on 1password with elapsed time ([#909](https://github.com/dotenvx/dotenvx/pull/909))
|
|
12
|
+
|
|
13
|
+
## [2.15.0](https://github.com/dotenvx/dotenvx/compare/v2.14.0...v2.15.0) (2026-07-20)
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
* Add support for 1Password `op://` secrets in your .env files. ([#908](https://github.com/dotenvx/dotenvx/pull/908))
|
|
6
18
|
|
|
7
19
|
## [2.14.0](https://github.com/dotenvx/dotenvx/compare/v2.13.0...v2.14.0) (2026-07-16)
|
|
8
20
|
|
package/README.md
CHANGED
|
@@ -153,6 +153,19 @@ Hello [REDACTED]
|
|
|
153
153
|
|
|
154
154
|
see [Codex redaction guide](https://dotenvx.com/docs/cli/run-redact-codex-exec)
|
|
155
155
|
|
|
156
|
+
</details>
|
|
157
|
+
<details><summary>1Password 🔐</summary><br>
|
|
158
|
+
|
|
159
|
+
Run with secrets resolved directly from 1Password.
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
$ echo "HELLO=op://Personal/hello/password" > .env
|
|
163
|
+
$ dotenvx run -- sh -c 'echo Hello $HELLO'
|
|
164
|
+
Hello World
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
see [1Password guide](https://dotenvx.com/docs/secrets-in-1password)
|
|
168
|
+
|
|
156
169
|
</details>
|
|
157
170
|
<details><summary>TypeScript 📘</summary><br>
|
|
158
171
|
|
|
@@ -1156,6 +1169,30 @@ $ dotenvx get GOODBYE
|
|
|
1156
1169
|
[MISSING_KEY] missing key (GOODBYE)
|
|
1157
1170
|
```
|
|
1158
1171
|
|
|
1172
|
+
</details>
|
|
1173
|
+
<details><summary>`run` - 1Password</summary><br>
|
|
1174
|
+
|
|
1175
|
+
Resolve [1Password op://](https://developer.1password.com/docs/cli/secrets-reference-syntax/) directly from your `.env` file.
|
|
1176
|
+
|
|
1177
|
+
```ini
|
|
1178
|
+
# .env
|
|
1179
|
+
API_KEY=op://Personal/my_api_key/password
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
Install the [1Password CLI](https://developer.1password.com/docs/cli/get-started/) and authenticate with `op`. Dotenvx automatically reads `op://` values through `op read` before injecting them.
|
|
1183
|
+
|
|
1184
|
+
```sh
|
|
1185
|
+
$ dotenvx run -- node index.js
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
Use `--no-1password` to leave `op://` values unresolved.
|
|
1189
|
+
|
|
1190
|
+
```sh
|
|
1191
|
+
$ dotenvx run --no-1password -- node index.js
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
The same flag is available for `dotenvx get` and `dotenvx validate`.
|
|
1195
|
+
|
|
1159
1196
|
</details>
|
|
1160
1197
|
<details><summary>`run -f <directory>`</summary><br>
|
|
1161
1198
|
|
|
@@ -1478,29 +1515,6 @@ $ dotenvx run --validate --strict -- node index.js
|
|
|
1478
1515
|
|
|
1479
1516
|
Any inline comment containing the word `optional` marks that key as optional. If `.env.example` is missing, dotenvx reports `MISSING_ENV_EXAMPLE`. An empty `.env.example` is valid and declares no required variables.
|
|
1480
1517
|
|
|
1481
|
-
</details>
|
|
1482
|
-
<details><summary>`validate`</summary><br>
|
|
1483
|
-
|
|
1484
|
-
Validate `.env` file(s) against `.env.example` without running a command.
|
|
1485
|
-
|
|
1486
|
-
```ini
|
|
1487
|
-
# .env.example
|
|
1488
|
-
DATABASE_URL=
|
|
1489
|
-
API_KEY=
|
|
1490
|
-
SENTRY_DSN= # optional
|
|
1491
|
-
```
|
|
1492
|
-
|
|
1493
|
-
```sh
|
|
1494
|
-
$ dotenvx validate
|
|
1495
|
-
[VALIDATION_FAILED] missing required (DATABASE_URL, API_KEY). fix: [https://github.com/dotenvx/dotenvx/issues/907]
|
|
1496
|
-
```
|
|
1497
|
-
|
|
1498
|
-
Use `-f` and `-fk` to validate a specific env file and keys file. The command exits with code `1` when validation fails and prints errors to stderr. On success, it exits with code `0`.
|
|
1499
|
-
|
|
1500
|
-
```sh
|
|
1501
|
-
$ dotenvx validate -f .env.production -fk .env.keys
|
|
1502
|
-
```
|
|
1503
|
-
|
|
1504
1518
|
</details>
|
|
1505
1519
|
<details><summary>`run --strict`</summary><br>
|
|
1506
1520
|
|
|
@@ -2490,6 +2504,29 @@ $ dotenvx ls --json
|
|
|
2490
2504
|
$ dotenvx ls --json > dotenv-files.json
|
|
2491
2505
|
```
|
|
2492
2506
|
|
|
2507
|
+
</details>
|
|
2508
|
+
<details><summary>`validate`</summary><br>
|
|
2509
|
+
|
|
2510
|
+
Validate `.env` file(s) against `.env.example` without running a command.
|
|
2511
|
+
|
|
2512
|
+
```ini
|
|
2513
|
+
# .env.example
|
|
2514
|
+
DATABASE_URL=
|
|
2515
|
+
API_KEY=
|
|
2516
|
+
SENTRY_DSN= # optional
|
|
2517
|
+
```
|
|
2518
|
+
|
|
2519
|
+
```sh
|
|
2520
|
+
$ dotenvx validate
|
|
2521
|
+
[VALIDATION_FAILED] missing required (DATABASE_URL, API_KEY). fix: [https://github.com/dotenvx/dotenvx/issues/907]
|
|
2522
|
+
```
|
|
2523
|
+
|
|
2524
|
+
Use `-f` and `-fk` to validate a specific env file and keys file. The command exits with code `1` when validation fails and prints errors to stderr. On success, it exits with code `0`.
|
|
2525
|
+
|
|
2526
|
+
```sh
|
|
2527
|
+
$ dotenvx validate -f .env.production -fk .env.keys
|
|
2528
|
+
```
|
|
2529
|
+
|
|
2493
2530
|
</details>
|
|
2494
2531
|
<details><summary>`genexample`</summary><br>
|
|
2495
2532
|
|
|
@@ -3225,6 +3262,30 @@ Turn off [Dotenvx Armor ⛨](https://dotenvx.com/armor) features.
|
|
|
3225
3262
|
require('@dotenvx/dotenvx').config({noArmor: true})
|
|
3226
3263
|
```
|
|
3227
3264
|
|
|
3265
|
+
</details>
|
|
3266
|
+
<details><summary>`config(no1Password:)` - no1Password</summary><br>
|
|
3267
|
+
|
|
3268
|
+
By default, `config()` automatically resolves `op://` values through the installed [1Password CLI](https://developer.1password.com/docs/cli/get-started/).
|
|
3269
|
+
|
|
3270
|
+
```ini
|
|
3271
|
+
# .env
|
|
3272
|
+
API_KEY=op://Personal/my_api_key/password
|
|
3273
|
+
```
|
|
3274
|
+
|
|
3275
|
+
```js
|
|
3276
|
+
// index.js
|
|
3277
|
+
require('@dotenvx/dotenvx').config()
|
|
3278
|
+
|
|
3279
|
+
console.log(process.env.API_KEY)
|
|
3280
|
+
```
|
|
3281
|
+
|
|
3282
|
+
Set `no1Password` to leave `op://` values unresolved and avoid calling `op`.
|
|
3283
|
+
|
|
3284
|
+
```js
|
|
3285
|
+
// index.js
|
|
3286
|
+
require('@dotenvx/dotenvx').config({no1Password: true})
|
|
3287
|
+
```
|
|
3288
|
+
|
|
3228
3289
|
</details>
|
|
3229
3290
|
<details><summary>`parse(src)`</summary><br>
|
|
3230
3291
|
|
|
@@ -3385,7 +3446,6 @@ Set `mask: 0` to fully mask values.
|
|
|
3385
3446
|
* [GitHub Actions](https://dotenvx.com/docs/cis/github-actions)
|
|
3386
3447
|
* [Password Managers](https://dotenvx.com/docs#password-managers)
|
|
3387
3448
|
* [1Password](https://dotenvx.com/docs/guides/1password)
|
|
3388
|
-
* [Bitwarden](https://dotenvx.com/docs/guides/bitwarden)
|
|
3389
3449
|
* [Background Jobs](https://dotenvx.com/docs#background-jobs)
|
|
3390
3450
|
* [Trigger.dev](https://dotenvx.com/docs/background-jobs/triggerdotdev)
|
|
3391
3451
|
* [Package Managers](https://dotenvx.com/docs#package-managers)
|
package/package.json
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.15.1",
|
|
3
3
|
"name": "@dotenvx/dotenvx",
|
|
4
4
|
"description": "a secure dotenv–from the creator of `dotenv`",
|
|
5
5
|
"author": "@motdotla",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"dotenv",
|
|
8
|
-
"env"
|
|
8
|
+
"env",
|
|
9
|
+
".env",
|
|
10
|
+
"environment",
|
|
11
|
+
"variables",
|
|
12
|
+
"config",
|
|
13
|
+
"settings",
|
|
14
|
+
"env vars",
|
|
15
|
+
"environment variables",
|
|
16
|
+
"secret-management",
|
|
17
|
+
"secrets"
|
|
9
18
|
],
|
|
10
19
|
"homepage": "https://github.com/dotenvx/dotenvx",
|
|
11
20
|
"repository": {
|
package/src/cli/actions/get.js
CHANGED
|
@@ -38,6 +38,8 @@ async function get (key) {
|
|
|
38
38
|
envKeysFile: resolveEnvKeysFile(options.envKeysFile),
|
|
39
39
|
noArmor,
|
|
40
40
|
noKeychain,
|
|
41
|
+
no1Password: options['1password'] === false || options.no1Password === true,
|
|
42
|
+
noBitwarden: options.bitwarden === false || options.noBitwarden === true,
|
|
41
43
|
onStatus: (text) => {
|
|
42
44
|
if (spinner && text) {
|
|
43
45
|
spinner.text = text
|
package/src/cli/actions/run.js
CHANGED
|
@@ -118,6 +118,8 @@ async function run () {
|
|
|
118
118
|
envKeysFile: resolveEnvKeysFile(options.envKeysFile),
|
|
119
119
|
noArmor,
|
|
120
120
|
noKeychain,
|
|
121
|
+
no1Password: options['1password'] === false || options.no1Password === true,
|
|
122
|
+
noBitwarden: options.bitwarden === false || options.noBitwarden === true,
|
|
121
123
|
token: options.token,
|
|
122
124
|
command: commandArgs,
|
|
123
125
|
onStatus: (text) => {
|
|
@@ -37,6 +37,8 @@ async function validate () {
|
|
|
37
37
|
envKeysFile: resolveEnvKeysFile(options.envKeysFile),
|
|
38
38
|
noArmor,
|
|
39
39
|
noKeychain,
|
|
40
|
+
no1Password: options['1password'] === false || options.no1Password === true,
|
|
41
|
+
noBitwarden: options.bitwarden === false || options.noBitwarden === true,
|
|
40
42
|
token: options.token,
|
|
41
43
|
onStatus: (text) => {
|
|
42
44
|
if (spinner && text) {
|
package/src/cli/dotenvx.js
CHANGED
|
@@ -74,6 +74,8 @@ program.command('run')
|
|
|
74
74
|
.option('--mask [characters]', 'inject masked values, optionally setting visible characters')
|
|
75
75
|
.option('--no-armor', 'disable Dotenvx Armor features')
|
|
76
76
|
.option('--no-native', 'disable OS secret store features')
|
|
77
|
+
.option('--no-1password', 'disable 1Password secret reference resolution')
|
|
78
|
+
.option('--no-bitwarden', 'disable Bitwarden secret reference resolution')
|
|
77
79
|
.action(function (...args) {
|
|
78
80
|
this.envs = envs
|
|
79
81
|
return require('./actions/run').apply(this, args)
|
|
@@ -98,6 +100,8 @@ program.command('get')
|
|
|
98
100
|
.option('--format <type>', 'format of the output (json, shell, colon, eval, eval-export)', 'json')
|
|
99
101
|
.option('--no-armor', 'disable Dotenvx Armor features')
|
|
100
102
|
.option('--no-native', 'disable OS secret store features')
|
|
103
|
+
.option('--no-1password', 'disable 1Password secret reference resolution')
|
|
104
|
+
.option('--no-bitwarden', 'disable Bitwarden secret reference resolution')
|
|
101
105
|
.action(function (...args) {
|
|
102
106
|
this.envs = envs
|
|
103
107
|
return require('./actions/get').apply(this, args)
|
|
@@ -183,6 +187,25 @@ program.command('ls')
|
|
|
183
187
|
return require('./actions/ls').apply(this, args)
|
|
184
188
|
})
|
|
185
189
|
|
|
190
|
+
// dotenvx validate
|
|
191
|
+
program.command('validate')
|
|
192
|
+
.description('validate .env file(s) against .env.example')
|
|
193
|
+
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
|
194
|
+
.option('-f, --env-file <path>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
195
|
+
.option('-fk, --env-keys-file <path>', 'path(s) to your .env.keys file(s) (default: same path as your env file)', collectEnvKeys)
|
|
196
|
+
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
|
197
|
+
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
|
198
|
+
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
|
199
|
+
.option('--token <token>', 'set Armor ⛨ token')
|
|
200
|
+
.option('--no-armor', 'disable Dotenvx Armor features')
|
|
201
|
+
.option('--no-native', 'disable OS secret store features')
|
|
202
|
+
.option('--no-1password', 'disable 1Password secret reference resolution')
|
|
203
|
+
.option('--no-bitwarden', 'disable Bitwarden secret reference resolution')
|
|
204
|
+
.action(function (...args) {
|
|
205
|
+
this.envs = envs
|
|
206
|
+
return require('./actions/validate').apply(this, args)
|
|
207
|
+
})
|
|
208
|
+
|
|
186
209
|
// dotenvx gitignore
|
|
187
210
|
program.command('gitignore')
|
|
188
211
|
.description('append to .gitignore')
|
|
@@ -201,23 +224,6 @@ program.command('genexample')
|
|
|
201
224
|
return require('./actions/ext/genexample').apply(this, args)
|
|
202
225
|
})
|
|
203
226
|
|
|
204
|
-
// dotenvx validate
|
|
205
|
-
program.command('validate')
|
|
206
|
-
.description('validate .env file(s) against .env.example')
|
|
207
|
-
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
|
208
|
-
.option('-f, --env-file <path>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
209
|
-
.option('-fk, --env-keys-file <path>', 'path(s) to your .env.keys file(s) (default: same path as your env file)', collectEnvKeys)
|
|
210
|
-
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
|
211
|
-
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
|
212
|
-
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
|
213
|
-
.option('--token <token>', 'set Armor ⛨ token')
|
|
214
|
-
.option('--no-armor', 'disable Dotenvx Armor features')
|
|
215
|
-
.option('--no-native', 'disable OS secret store features')
|
|
216
|
-
.action(function (...args) {
|
|
217
|
-
this.envs = envs
|
|
218
|
-
return require('./actions/validate').apply(this, args)
|
|
219
|
-
})
|
|
220
|
-
|
|
221
227
|
// dotenvx precommit
|
|
222
228
|
program.command('precommit')
|
|
223
229
|
.description('prevent committing .env files to code')
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function createElapsedStatus (onStatus, text) {
|
|
2
|
+
if (!onStatus) return () => {}
|
|
3
|
+
|
|
4
|
+
let elapsed = 0
|
|
5
|
+
onStatus(text)
|
|
6
|
+
|
|
7
|
+
const timer = setInterval(() => {
|
|
8
|
+
elapsed += 1
|
|
9
|
+
onStatus(`${text} (${elapsed}s)`)
|
|
10
|
+
}, 1000)
|
|
11
|
+
|
|
12
|
+
if (timer.unref) timer.unref()
|
|
13
|
+
|
|
14
|
+
return () => clearInterval(timer)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = createElapsedStatus
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const FRAMES = ['◇', '⬖', '◆', '⬗']
|
|
2
2
|
const FRAME_INTERVAL_MS = 80
|
|
3
|
+
let activeSpinner
|
|
3
4
|
|
|
4
5
|
async function createSpinner (options = {}) {
|
|
5
6
|
const stream = process.stderr
|
|
@@ -11,7 +12,7 @@ async function createSpinner (options = {}) {
|
|
|
11
12
|
const frames = options.frames || FRAMES
|
|
12
13
|
|
|
13
14
|
const { default: yoctoSpinner } = await import('yocto-spinner')
|
|
14
|
-
|
|
15
|
+
activeSpinner = yoctoSpinner({
|
|
15
16
|
text,
|
|
16
17
|
spinner: {
|
|
17
18
|
frames,
|
|
@@ -19,6 +20,21 @@ async function createSpinner (options = {}) {
|
|
|
19
20
|
},
|
|
20
21
|
stream
|
|
21
22
|
}).start()
|
|
23
|
+
|
|
24
|
+
return activeSpinner
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
createSpinner.stop = function () {
|
|
28
|
+
if (activeSpinner) activeSpinner.stop()
|
|
29
|
+
activeSpinner = null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
createSpinner.pause = function () {
|
|
33
|
+
if (activeSpinner) activeSpinner.stop()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
createSpinner.resume = function () {
|
|
37
|
+
if (activeSpinner) activeSpinner.start()
|
|
22
38
|
}
|
|
23
39
|
|
|
24
40
|
module.exports = createSpinner
|
|
@@ -9,6 +9,8 @@ const ISSUE_BY_CODE = {
|
|
|
9
9
|
INVALID_PASSPHRASE: 'try again with the correct passphrase',
|
|
10
10
|
INVALID_PRIVATE_KEY: 'https://github.com/dotenvx/dotenvx/issues/465',
|
|
11
11
|
INVALID_PUBLIC_KEY: 'https://github.com/dotenvx/dotenvx/issues/756',
|
|
12
|
+
'1PASSWORD_FAILED': 'https://www.1password.dev/cli/get-started',
|
|
13
|
+
BITWARDEN_FAILED: 'https://bitwarden.com/help/cli/',
|
|
12
14
|
MALFORMED_ENCRYPTED_DATA: 'https://github.com/dotenvx/dotenvx/issues/467',
|
|
13
15
|
MISPAIRED_PRIVATE_KEY: 'https://github.com/dotenvx/dotenvx/issues/752',
|
|
14
16
|
MISSING_DIRECTORY: 'https://github.com/dotenvx/dotenvx/issues/758',
|
|
@@ -100,6 +102,30 @@ class Errors {
|
|
|
100
102
|
return e
|
|
101
103
|
}
|
|
102
104
|
|
|
105
|
+
onePasswordFailed () {
|
|
106
|
+
const code = '1PASSWORD_FAILED'
|
|
107
|
+
const message = `[${code}] ${this.message}`
|
|
108
|
+
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
|
109
|
+
|
|
110
|
+
const e = new Error(message)
|
|
111
|
+
e.code = code
|
|
112
|
+
e.help = help
|
|
113
|
+
e.messageWithHelp = `${message}. ${help}`
|
|
114
|
+
return e
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
bitwardenFailed () {
|
|
118
|
+
const code = 'BITWARDEN_FAILED'
|
|
119
|
+
const message = `[${code}] ${this.message}`
|
|
120
|
+
const help = this.help || `fix: [${ISSUE_BY_CODE[code]}]`
|
|
121
|
+
|
|
122
|
+
const e = new Error(message)
|
|
123
|
+
e.code = code
|
|
124
|
+
e.help = help
|
|
125
|
+
e.messageWithHelp = `${message}. ${help}`
|
|
126
|
+
return e
|
|
127
|
+
}
|
|
128
|
+
|
|
103
129
|
invalidColor () {
|
|
104
130
|
const code = 'INVALID_COLOR'
|
|
105
131
|
const message = `[${code}] Invalid color ${this.color}`
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const { execFile, execFileSync } = require('child_process')
|
|
2
|
+
const Errors = require('./errors')
|
|
3
|
+
const prompts = require('./prompts')
|
|
4
|
+
const createSpinner = require('./createSpinner')
|
|
5
|
+
const createElapsedStatus = require('./createElapsedStatus')
|
|
6
|
+
|
|
7
|
+
const FIELDS = new Set(['username', 'password', 'uri'])
|
|
8
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
9
|
+
|
|
10
|
+
function execFileAsync (command, args, options) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
execFile(command, args, options, (error, stdout) => {
|
|
13
|
+
if (error) return reject(error)
|
|
14
|
+
resolve(stdout)
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isSecretReference (value) {
|
|
20
|
+
return typeof value === 'string' && value.startsWith('bw://')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function parseSecretReference (value) {
|
|
24
|
+
const [itemId, field, ...extra] = value.slice('bw://'.length).split('/')
|
|
25
|
+
|
|
26
|
+
if (!UUID.test(itemId) || !field || extra.length > 0) {
|
|
27
|
+
throw new Error('invalid Bitwarden Password Manager reference')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!FIELDS.has(field)) {
|
|
31
|
+
throw new Error(`unsupported Bitwarden Password Manager field ${field}`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { itemId, field }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function session (options) {
|
|
38
|
+
if (options.session) return options.session
|
|
39
|
+
|
|
40
|
+
if (process.stdin.isTTY && process.stderr.isTTY) {
|
|
41
|
+
createSpinner.pause()
|
|
42
|
+
const password = await prompts.password({
|
|
43
|
+
message: 'Bitwarden master password',
|
|
44
|
+
prefix: '◇',
|
|
45
|
+
separator: '='
|
|
46
|
+
}, {
|
|
47
|
+
input: process.stdin,
|
|
48
|
+
output: process.stderr
|
|
49
|
+
})
|
|
50
|
+
createSpinner.resume()
|
|
51
|
+
if (options.startStatus) options.startStatus()
|
|
52
|
+
const passwordEnv = 'DOTENVX_BITWARDEN_PASSWORD'
|
|
53
|
+
options.session = secretValue(await execFileAsync('bw', ['unlock', '--passwordenv', passwordEnv, '--raw'], {
|
|
54
|
+
encoding: 'utf8',
|
|
55
|
+
windowsHide: true,
|
|
56
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
57
|
+
env: { ...process.env, [passwordEnv]: password }
|
|
58
|
+
}))
|
|
59
|
+
return options.session
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!options.session) {
|
|
63
|
+
const error = new Error('Bitwarden Password Manager requires an unlocked BW_SESSION')
|
|
64
|
+
error.code = 'BW_SESSION_MISSING'
|
|
65
|
+
throw error
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function resolutionError (key, error) {
|
|
70
|
+
let message
|
|
71
|
+
if (error && error.code === 'ENOENT') {
|
|
72
|
+
message = `Bitwarden Password Manager CLI is not installed and could not resolve ${key}`
|
|
73
|
+
} else if (error && error.code === 'BW_SESSION_MISSING') {
|
|
74
|
+
message = `Bitwarden Password Manager is locked and could not resolve ${key}; run 'export BW_SESSION="$(bw unlock --raw)"'`
|
|
75
|
+
} else if (error && error.message && error.message.startsWith('unsupported Bitwarden Password Manager field')) {
|
|
76
|
+
message = `${error.message} for ${key}`
|
|
77
|
+
} else if (error && error.message === 'invalid Bitwarden Password Manager reference') {
|
|
78
|
+
message = `invalid Bitwarden Password Manager reference for ${key}`
|
|
79
|
+
} else {
|
|
80
|
+
message = `Bitwarden Password Manager CLI failed to resolve ${key}`
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return new Errors({
|
|
84
|
+
message,
|
|
85
|
+
help: 'fix: [https://bitwarden.com/help/cli/]'
|
|
86
|
+
}).bitwardenFailed()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function secretValue (stdout) {
|
|
90
|
+
return stdout.replace(/\r?\n$/, '')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function resolveBitwardenPassword (parsed, options = {}) {
|
|
94
|
+
const errors = []
|
|
95
|
+
const unresolved = []
|
|
96
|
+
options.session = options.session || process.env.BW_SESSION
|
|
97
|
+
let stopStatus
|
|
98
|
+
const startStatus = () => {
|
|
99
|
+
if (!stopStatus) stopStatus = createElapsedStatus(options.onStatus, 'awaiting bitwarden')
|
|
100
|
+
}
|
|
101
|
+
options.startStatus = startStatus
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
105
|
+
if (!isSecretReference(value)) continue
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const { itemId, field } = parseSecretReference(value)
|
|
109
|
+
if (options.session) startStatus()
|
|
110
|
+
const bwSession = await session(options)
|
|
111
|
+
const stdout = await execFileAsync('bw', ['get', field, itemId], {
|
|
112
|
+
encoding: 'utf8',
|
|
113
|
+
windowsHide: true,
|
|
114
|
+
env: { ...process.env, BW_SESSION: bwSession }
|
|
115
|
+
})
|
|
116
|
+
parsed[key] = secretValue(stdout)
|
|
117
|
+
} catch (error) {
|
|
118
|
+
errors.push(resolutionError(key, error))
|
|
119
|
+
unresolved.push(key)
|
|
120
|
+
delete parsed[key]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} finally {
|
|
124
|
+
if (stopStatus) {
|
|
125
|
+
stopStatus()
|
|
126
|
+
if (options.onStatus) options.onStatus('injecting')
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return { errors, unresolved }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function resolveBitwardenPasswordSync (parsed) {
|
|
134
|
+
const errors = []
|
|
135
|
+
const unresolved = []
|
|
136
|
+
|
|
137
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
138
|
+
if (!isSecretReference(value)) continue
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const { itemId, field } = parseSecretReference(value)
|
|
142
|
+
if (!process.env.BW_SESSION) {
|
|
143
|
+
const error = new Error('Bitwarden Password Manager requires an unlocked BW_SESSION')
|
|
144
|
+
error.code = 'BW_SESSION_MISSING'
|
|
145
|
+
throw error
|
|
146
|
+
}
|
|
147
|
+
const stdout = execFileSync('bw', ['get', field, itemId], {
|
|
148
|
+
encoding: 'utf8',
|
|
149
|
+
windowsHide: true,
|
|
150
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
151
|
+
})
|
|
152
|
+
parsed[key] = secretValue(stdout)
|
|
153
|
+
} catch (error) {
|
|
154
|
+
errors.push(resolutionError(key, error))
|
|
155
|
+
unresolved.push(key)
|
|
156
|
+
delete parsed[key]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { errors, unresolved }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
module.exports = resolveBitwardenPassword
|
|
164
|
+
module.exports.sync = resolveBitwardenPasswordSync
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const { execFile, execFileSync } = require('child_process')
|
|
2
|
+
const Errors = require('./errors')
|
|
3
|
+
const createElapsedStatus = require('./createElapsedStatus')
|
|
4
|
+
|
|
5
|
+
function execFileAsync (command, args, options) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
execFile(command, args, options, (error, stdout) => {
|
|
8
|
+
if (error) return reject(error)
|
|
9
|
+
resolve(stdout)
|
|
10
|
+
})
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isSecretReference (value) {
|
|
15
|
+
return typeof value === 'string' && value.startsWith('op://')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function resolutionError (key, error) {
|
|
19
|
+
const message = error && error.code === 'ENOENT'
|
|
20
|
+
? `1Password CLI is not installed and could not resolve ${key}`
|
|
21
|
+
: `1Password CLI failed to resolve ${key}`
|
|
22
|
+
|
|
23
|
+
return new Errors({ message }).onePasswordFailed()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function resolveOnePassword (parsed, options = {}) {
|
|
27
|
+
const errors = []
|
|
28
|
+
const unresolved = []
|
|
29
|
+
const hasSecretReferences = Object.values(parsed).some(isSecretReference)
|
|
30
|
+
const stopStatus = hasSecretReferences
|
|
31
|
+
? createElapsedStatus(options.onStatus, 'awaiting 1password')
|
|
32
|
+
: null
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
36
|
+
if (!isSecretReference(value)) continue
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const stdout = await execFileAsync('op', ['read', value, '--no-newline'], {
|
|
40
|
+
encoding: 'utf8',
|
|
41
|
+
windowsHide: true
|
|
42
|
+
})
|
|
43
|
+
parsed[key] = stdout
|
|
44
|
+
} catch (error) {
|
|
45
|
+
errors.push(resolutionError(key, error))
|
|
46
|
+
unresolved.push(key)
|
|
47
|
+
delete parsed[key]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} finally {
|
|
51
|
+
if (stopStatus) {
|
|
52
|
+
stopStatus()
|
|
53
|
+
if (options.onStatus) options.onStatus('injecting')
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { errors, unresolved }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveOnePasswordSync (parsed) {
|
|
61
|
+
const errors = []
|
|
62
|
+
const unresolved = []
|
|
63
|
+
|
|
64
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
65
|
+
if (!isSecretReference(value)) continue
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
parsed[key] = execFileSync('op', ['read', value, '--no-newline'], {
|
|
69
|
+
encoding: 'utf8',
|
|
70
|
+
windowsHide: true,
|
|
71
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
72
|
+
})
|
|
73
|
+
} catch (error) {
|
|
74
|
+
errors.push(resolutionError(key, error))
|
|
75
|
+
unresolved.push(key)
|
|
76
|
+
delete parsed[key]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { errors, unresolved }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = resolveOnePassword
|
|
84
|
+
module.exports.sync = resolveOnePasswordSync
|
package/src/lib/main.d.ts
CHANGED
|
@@ -194,6 +194,22 @@ export interface DotenvConfigOptions {
|
|
|
194
194
|
*/
|
|
195
195
|
noNative?: boolean;
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Turn off 1Password secret reference resolution.
|
|
199
|
+
*
|
|
200
|
+
* @default false
|
|
201
|
+
* @example require('@dotenvx/dotenvx').config({ no1Password: true })
|
|
202
|
+
*/
|
|
203
|
+
no1Password?: boolean;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Turn off Bitwarden secret reference resolution.
|
|
207
|
+
*
|
|
208
|
+
* @default false
|
|
209
|
+
* @example require('@dotenvx/dotenvx').config({ noBitwarden: true })
|
|
210
|
+
*/
|
|
211
|
+
noBitwarden?: boolean;
|
|
212
|
+
|
|
197
213
|
}
|
|
198
214
|
|
|
199
215
|
export type DotenvConfigEnv =
|
|
@@ -370,6 +386,22 @@ export interface GetOptions {
|
|
|
370
386
|
*/
|
|
371
387
|
noNative?: boolean;
|
|
372
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Turn off 1Password secret reference resolution.
|
|
391
|
+
*
|
|
392
|
+
* @default false
|
|
393
|
+
* @example require('@dotenvx/dotenvx').get('KEY', { no1Password: true })
|
|
394
|
+
*/
|
|
395
|
+
no1Password?: boolean;
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Turn off Bitwarden secret reference resolution.
|
|
399
|
+
*
|
|
400
|
+
* @default false
|
|
401
|
+
* @example require('@dotenvx/dotenvx').get('KEY', { noBitwarden: true })
|
|
402
|
+
*/
|
|
403
|
+
noBitwarden?: boolean;
|
|
404
|
+
|
|
373
405
|
}
|
|
374
406
|
|
|
375
407
|
/**
|
package/src/lib/main.js
CHANGED
|
@@ -87,6 +87,8 @@ const config = function (options = {}) {
|
|
|
87
87
|
envKeysFile,
|
|
88
88
|
noArmor,
|
|
89
89
|
noKeychain,
|
|
90
|
+
no1Password: options.no1Password,
|
|
91
|
+
noBitwarden: options.noBitwarden,
|
|
90
92
|
noSpinner: options.noSpinner,
|
|
91
93
|
token: options.token
|
|
92
94
|
})
|
|
@@ -331,7 +333,9 @@ const get = async function (key, options = {}) {
|
|
|
331
333
|
all: options.all,
|
|
332
334
|
envKeysFile: options.envKeysFile,
|
|
333
335
|
noArmor,
|
|
334
|
-
noKeychain
|
|
336
|
+
noKeychain,
|
|
337
|
+
no1Password: options.no1Password,
|
|
338
|
+
noBitwarden: options.noBitwarden
|
|
335
339
|
})
|
|
336
340
|
|
|
337
341
|
if (options.mask !== undefined) {
|
|
@@ -12,6 +12,8 @@ const keynames = require('./../conventions/keynames')
|
|
|
12
12
|
const providers = require('./../providers')
|
|
13
13
|
const decryptors = require('./../decryptors')
|
|
14
14
|
const parseWithDecryptor = require('./../helpers/parseWithDecryptor')
|
|
15
|
+
const resolveOnePassword = require('./../helpers/resolveOnePassword')
|
|
16
|
+
const resolveBitwardenPassword = require('./../helpers/resolveBitwardenPassword')
|
|
15
17
|
|
|
16
18
|
function unresolvedEncryptedErrors (parsed) {
|
|
17
19
|
const keys = []
|
|
@@ -70,7 +72,7 @@ function buildParseOptions ({ processEnv, overload, envKeysFilepath, provider, d
|
|
|
70
72
|
return options
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
async function injectEnv ({ env, overload, processEnv, envKeysFilepath, provider, decryptor }) {
|
|
75
|
+
async function injectEnv ({ env, overload, processEnv, envKeysFilepath, provider, decryptor, no1Password, noBitwarden, onStatus }) {
|
|
74
76
|
const row = {}
|
|
75
77
|
row.type = TYPE_ENV
|
|
76
78
|
row.string = env.value
|
|
@@ -101,6 +103,21 @@ async function injectEnv ({ env, overload, processEnv, envKeysFilepath, provider
|
|
|
101
103
|
row.injected = injected || {}
|
|
102
104
|
row.existed = existed || {}
|
|
103
105
|
|
|
106
|
+
if (!no1Password) {
|
|
107
|
+
const result = await resolveOnePassword(row.injected, { onStatus })
|
|
108
|
+
row.errors.push(...result.errors)
|
|
109
|
+
for (const key of result.unresolved) delete row.parsed[key]
|
|
110
|
+
Object.assign(row.parsed, row.injected)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!noBitwarden) {
|
|
114
|
+
const passwordResult = await resolveBitwardenPassword(row.injected, { onStatus })
|
|
115
|
+
row.errors.push(...passwordResult.errors)
|
|
116
|
+
for (const key of passwordResult.unresolved) delete row.parsed[key]
|
|
117
|
+
|
|
118
|
+
Object.assign(row.parsed, row.injected)
|
|
119
|
+
}
|
|
120
|
+
|
|
104
121
|
inject(processEnv, row.parsed)
|
|
105
122
|
} catch (e) {
|
|
106
123
|
row.errors = [e]
|
|
@@ -109,7 +126,7 @@ async function injectEnv ({ env, overload, processEnv, envKeysFilepath, provider
|
|
|
109
126
|
return row
|
|
110
127
|
}
|
|
111
128
|
|
|
112
|
-
function injectEnvSync ({ env, overload, processEnv, envKeysFilepath, provider, decryptor }) {
|
|
129
|
+
function injectEnvSync ({ env, overload, processEnv, envKeysFilepath, provider, decryptor, no1Password, noBitwarden }) {
|
|
113
130
|
const row = {}
|
|
114
131
|
row.type = TYPE_ENV
|
|
115
132
|
row.string = env.value
|
|
@@ -140,6 +157,21 @@ function injectEnvSync ({ env, overload, processEnv, envKeysFilepath, provider,
|
|
|
140
157
|
row.injected = injected || {}
|
|
141
158
|
row.existed = existed || {}
|
|
142
159
|
|
|
160
|
+
if (!no1Password) {
|
|
161
|
+
const result = resolveOnePassword.sync(row.injected)
|
|
162
|
+
row.errors.push(...result.errors)
|
|
163
|
+
for (const key of result.unresolved) delete row.parsed[key]
|
|
164
|
+
Object.assign(row.parsed, row.injected)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!noBitwarden) {
|
|
168
|
+
const passwordResult = resolveBitwardenPassword.sync(row.injected)
|
|
169
|
+
row.errors.push(...passwordResult.errors)
|
|
170
|
+
for (const key of passwordResult.unresolved) delete row.parsed[key]
|
|
171
|
+
|
|
172
|
+
Object.assign(row.parsed, row.injected)
|
|
173
|
+
}
|
|
174
|
+
|
|
143
175
|
inject(processEnv, row.parsed)
|
|
144
176
|
} catch (e) {
|
|
145
177
|
row.errors = [e]
|
|
@@ -148,7 +180,7 @@ function injectEnvSync ({ env, overload, processEnv, envKeysFilepath, provider,
|
|
|
148
180
|
return row
|
|
149
181
|
}
|
|
150
182
|
|
|
151
|
-
async function injectEnvFile ({ env, overload, processEnv, envKeysFilepath, provider, decryptor, readableFilepaths }) {
|
|
183
|
+
async function injectEnvFile ({ env, overload, processEnv, envKeysFilepath, provider, decryptor, readableFilepaths, no1Password, noBitwarden, onStatus }) {
|
|
152
184
|
const row = {}
|
|
153
185
|
row.type = TYPE_ENV_FILE
|
|
154
186
|
row.filepath = env.value
|
|
@@ -182,6 +214,21 @@ async function injectEnvFile ({ env, overload, processEnv, envKeysFilepath, prov
|
|
|
182
214
|
row.errors = decryptErrors(parsed, errors)
|
|
183
215
|
row.existed = existed || {}
|
|
184
216
|
|
|
217
|
+
if (!no1Password) {
|
|
218
|
+
const result = await resolveOnePassword(row.injected, { onStatus })
|
|
219
|
+
row.errors.push(...result.errors)
|
|
220
|
+
for (const key of result.unresolved) delete row.parsed[key]
|
|
221
|
+
Object.assign(row.parsed, row.injected)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (!noBitwarden) {
|
|
225
|
+
const passwordResult = await resolveBitwardenPassword(row.injected, { onStatus })
|
|
226
|
+
row.errors.push(...passwordResult.errors)
|
|
227
|
+
for (const key of passwordResult.unresolved) delete row.parsed[key]
|
|
228
|
+
|
|
229
|
+
Object.assign(row.parsed, row.injected)
|
|
230
|
+
}
|
|
231
|
+
|
|
185
232
|
inject(processEnv, parsed)
|
|
186
233
|
} catch (e) {
|
|
187
234
|
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
|
@@ -194,7 +241,7 @@ async function injectEnvFile ({ env, overload, processEnv, envKeysFilepath, prov
|
|
|
194
241
|
return row
|
|
195
242
|
}
|
|
196
243
|
|
|
197
|
-
function injectEnvFileSync ({ env, overload, processEnv, envKeysFilepath, provider, decryptor, readableFilepaths }) {
|
|
244
|
+
function injectEnvFileSync ({ env, overload, processEnv, envKeysFilepath, provider, decryptor, readableFilepaths, no1Password, noBitwarden }) {
|
|
198
245
|
const row = {}
|
|
199
246
|
row.type = TYPE_ENV_FILE
|
|
200
247
|
row.filepath = env.value
|
|
@@ -228,6 +275,21 @@ function injectEnvFileSync ({ env, overload, processEnv, envKeysFilepath, provid
|
|
|
228
275
|
row.errors = decryptErrors(parsed, errors)
|
|
229
276
|
row.existed = existed || {}
|
|
230
277
|
|
|
278
|
+
if (!no1Password) {
|
|
279
|
+
const result = resolveOnePassword.sync(row.injected)
|
|
280
|
+
row.errors.push(...result.errors)
|
|
281
|
+
for (const key of result.unresolved) delete row.parsed[key]
|
|
282
|
+
Object.assign(row.parsed, row.injected)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!noBitwarden) {
|
|
286
|
+
const passwordResult = resolveBitwardenPassword.sync(row.injected)
|
|
287
|
+
row.errors.push(...passwordResult.errors)
|
|
288
|
+
for (const key of passwordResult.unresolved) delete row.parsed[key]
|
|
289
|
+
|
|
290
|
+
Object.assign(row.parsed, row.injected)
|
|
291
|
+
}
|
|
292
|
+
|
|
231
293
|
inject(processEnv, parsed)
|
|
232
294
|
} catch (e) {
|
|
233
295
|
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
|
@@ -247,7 +309,6 @@ async function envs (options = {}) {
|
|
|
247
309
|
const envKeysFilepath = options.envKeysFilepath || options.envKeysFile || null
|
|
248
310
|
const provider = await providers(options)
|
|
249
311
|
const decryptor = await decryptors(options)
|
|
250
|
-
|
|
251
312
|
for (const env of options.envs || []) {
|
|
252
313
|
if (env.type === TYPE_ENV_FILE) {
|
|
253
314
|
processedEnvs.push(await injectEnvFile({
|
|
@@ -257,7 +318,10 @@ async function envs (options = {}) {
|
|
|
257
318
|
envKeysFilepath,
|
|
258
319
|
provider,
|
|
259
320
|
decryptor,
|
|
260
|
-
readableFilepaths
|
|
321
|
+
readableFilepaths,
|
|
322
|
+
no1Password: options.no1Password,
|
|
323
|
+
noBitwarden: options.noBitwarden,
|
|
324
|
+
onStatus: options.onStatus
|
|
261
325
|
}))
|
|
262
326
|
} else if (env.type === TYPE_ENV) {
|
|
263
327
|
processedEnvs.push(await injectEnv({
|
|
@@ -266,7 +330,10 @@ async function envs (options = {}) {
|
|
|
266
330
|
processEnv,
|
|
267
331
|
envKeysFilepath,
|
|
268
332
|
provider,
|
|
269
|
-
decryptor
|
|
333
|
+
decryptor,
|
|
334
|
+
no1Password: options.no1Password,
|
|
335
|
+
noBitwarden: options.noBitwarden,
|
|
336
|
+
onStatus: options.onStatus
|
|
270
337
|
}))
|
|
271
338
|
}
|
|
272
339
|
}
|
|
@@ -294,7 +361,9 @@ function envsSync (options = {}) {
|
|
|
294
361
|
envKeysFilepath,
|
|
295
362
|
provider,
|
|
296
363
|
decryptor,
|
|
297
|
-
readableFilepaths
|
|
364
|
+
readableFilepaths,
|
|
365
|
+
no1Password: options.no1Password,
|
|
366
|
+
noBitwarden: options.noBitwarden
|
|
298
367
|
}))
|
|
299
368
|
} else if (env.type === TYPE_ENV) {
|
|
300
369
|
processedEnvs.push(injectEnvSync({
|
|
@@ -303,7 +372,9 @@ function envsSync (options = {}) {
|
|
|
303
372
|
processEnv,
|
|
304
373
|
envKeysFilepath,
|
|
305
374
|
provider,
|
|
306
|
-
decryptor
|
|
375
|
+
decryptor,
|
|
376
|
+
no1Password: options.no1Password,
|
|
377
|
+
noBitwarden: options.noBitwarden
|
|
307
378
|
}))
|
|
308
379
|
}
|
|
309
380
|
}
|
package/src/lib/resolvers/get.js
CHANGED
|
@@ -51,6 +51,8 @@ function buildOptions (options, processEnv) {
|
|
|
51
51
|
envKeysFilepath: options.envKeysFilepath || options.envKeysFile || null,
|
|
52
52
|
noArmor: options.noArmor,
|
|
53
53
|
noKeychain: options.noKeychain,
|
|
54
|
+
no1Password: options.no1Password,
|
|
55
|
+
noBitwarden: options.noBitwarden,
|
|
54
56
|
onStatus: options.onStatus
|
|
55
57
|
}
|
|
56
58
|
}
|