@ciqol/resenv 0.1.1 → 0.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/README.md +92 -162
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,33 +1,20 @@
|
|
|
1
1
|
# @ciqol/resenv
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
**Doppler is the only built-in cloud provider.** A value such as
|
|
8
|
-
`doppler://my-project/dev/API_TOKEN` tells resenv which secret to fetch. The
|
|
9
|
-
application then reads the actual value from `process.env.API_TOKEN`.
|
|
10
|
-
|
|
11
|
-
```text
|
|
12
|
-
Nx or another loader sets process.env
|
|
13
|
-
|
|
|
14
|
-
resenv fetches the referenced values and replaces them in memory
|
|
15
|
-
|
|
|
16
|
-
Application starts with ordinary environment values
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Resolution happens once at startup. It does not watch the provider for changes;
|
|
20
|
-
restart the application to fetch updated values. No filename is passed to
|
|
21
|
-
resenv, and dotenv files are never rewritten.
|
|
3
|
+
[](https://github.com/ciqol/resenv/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@ciqol/resenv)
|
|
5
|
+
[](https://www.npmjs.com/package/@ciqol/resenv)
|
|
22
6
|
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
**Resolve secret references already in `process.env` before application code
|
|
8
|
+
runs.** Your existing loader, such as Nx, chooses and loads dotenv files;
|
|
9
|
+
resenv replaces references in memory. It never rewrites those files.
|
|
25
10
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
11
|
+
Doppler is the only built-in cloud provider. For example,
|
|
12
|
+
`API_TOKEN=doppler://my-project/dev/API_TOKEN` becomes the fetched secret in
|
|
13
|
+
`process.env.API_TOKEN`. Resolution happens once at startup; restart the
|
|
14
|
+
application to fetch updated values.
|
|
29
15
|
|
|
30
|
-
|
|
16
|
+
Requires Node.js 20 or later. The package has no runtime npm dependencies and
|
|
17
|
+
is experimental; its API may change between 0.x releases.
|
|
31
18
|
|
|
32
19
|
## Install
|
|
33
20
|
|
|
@@ -37,84 +24,60 @@ Install in your application project:
|
|
|
37
24
|
npm install --save-exact @ciqol/resenv
|
|
38
25
|
```
|
|
39
26
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
The CLI examples below use `npx --no-install` to run the copy installed in your
|
|
44
|
-
project. In an npm script, use `resenv` directly.
|
|
27
|
+
The CLI examples use `npx --no-install` to run that installed copy. In an npm
|
|
28
|
+
script, use `resenv` directly.
|
|
45
29
|
|
|
46
30
|
## Use with Doppler
|
|
47
31
|
|
|
48
|
-
|
|
49
|
-
[Doppler's introduction](https://docs.doppler.com/docs/start).
|
|
50
|
-
|
|
51
|
-
### 1. Authenticate locally
|
|
32
|
+
### 1. Authenticate
|
|
52
33
|
|
|
53
|
-
|
|
54
|
-
|
|
34
|
+
Install the [official Doppler CLI](https://docs.doppler.com/docs/cli#installation),
|
|
35
|
+
then log in from your application directory:
|
|
55
36
|
|
|
56
37
|
```sh
|
|
57
38
|
doppler login
|
|
58
39
|
```
|
|
59
40
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
> and may vary by platform or CLI version. resenv only reuses its existing token;
|
|
65
|
-
> it does not manage login, logout or credential storage, or access the OS
|
|
66
|
-
> credential store directly.
|
|
41
|
+
resenv uses `DOPPLER_TOKEN` when supplied; otherwise it reuses the CLI login
|
|
42
|
+
selected for the application's working directory. Doppler owns login, logout
|
|
43
|
+
and credential storage. Missing credentials or access stop startup without
|
|
44
|
+
prompting for login.
|
|
67
45
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
46
|
+
For CI and other unattended environments, supply a suitably scoped
|
|
47
|
+
`DOPPLER_TOKEN` through your runner's secret facility; no CLI is needed.
|
|
48
|
+
See [authentication and platform details](https://github.com/ciqol/resenv/blob/main/docs/doppler.md)
|
|
49
|
+
for supported CLI locations and lookup rules.
|
|
72
50
|
|
|
73
|
-
|
|
74
|
-
runner's secret facility; the CLI is not needed in that mode. See
|
|
75
|
-
[Doppler authentication and platform details](https://github.com/ciqol/resenv/blob/main/docs/doppler.md), including
|
|
76
|
-
migration from the earlier resenv-managed login.
|
|
51
|
+
### 2. Declare references
|
|
77
52
|
|
|
78
|
-
|
|
79
|
-
[Request support](https://github.com/ciqol/resenv/issues/new) with your use case
|
|
80
|
-
and platform details.
|
|
81
|
-
|
|
82
|
-
### 2. Declare references in the environment your app already loads
|
|
83
|
-
|
|
84
|
-
For example, in an Nx application's `.env.serve`:
|
|
53
|
+
In the environment your application already loads, such as Nx's `.env.serve`:
|
|
85
54
|
|
|
86
55
|
```dotenv
|
|
87
56
|
API_TOKEN=doppler://my-project/dev/API_TOKEN
|
|
88
57
|
PORT=3000
|
|
89
58
|
```
|
|
90
59
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
The reference itself grants no access: the authenticated identity needs
|
|
94
|
-
permission to read that secret. Doppler references need no dotenvx private key.
|
|
60
|
+
Each reference names a project, config and secret. The authenticated identity
|
|
61
|
+
must have access to that secret. Plain values such as `PORT` pass through.
|
|
95
62
|
|
|
96
|
-
### 3. Preload
|
|
63
|
+
### 3. Preload on the application process
|
|
97
64
|
|
|
98
|
-
|
|
65
|
+
After your loader has populated the environment:
|
|
99
66
|
|
|
100
67
|
```sh
|
|
101
68
|
node --require @ciqol/resenv/resolve app.cjs
|
|
102
69
|
node --import @ciqol/resenv/resolve app.mjs
|
|
103
70
|
```
|
|
104
71
|
|
|
105
|
-
The preload replaces
|
|
106
|
-
imports execute. It infers Doppler from the value, so no provider flag is needed.
|
|
107
|
-
|
|
72
|
+
The preload replaces references before the application and its imports execute.
|
|
108
73
|
Alternatively, wrap a command whose environment is already populated:
|
|
109
74
|
|
|
110
75
|
```sh
|
|
111
76
|
npx --no-install resenv run -- node app.mjs
|
|
112
77
|
```
|
|
113
78
|
|
|
114
|
-
The wrapper
|
|
115
|
-
|
|
116
|
-
SIGHUP to that child. On POSIX, the child runs in its own session so terminal
|
|
117
|
-
signals reach it only through the wrapper.
|
|
79
|
+
The wrapper passes the resolved environment to its child, inherits terminal I/O,
|
|
80
|
+
preserves exit status and forwards termination signals.
|
|
118
81
|
|
|
119
82
|
## Nx integration
|
|
120
83
|
|
|
@@ -137,70 +100,70 @@ Put the preload on the application's target, after Nx loads its dotenv files:
|
|
|
137
100
|
}
|
|
138
101
|
```
|
|
139
102
|
|
|
140
|
-
Run `nx serve app
|
|
141
|
-
|
|
142
|
-
and target options. For an existing `@nx/js:node` target, add:
|
|
103
|
+
Run `nx serve app`, using your application's existing path and target options.
|
|
104
|
+
For an existing `@nx/js:node` target, add:
|
|
143
105
|
|
|
144
106
|
```json
|
|
145
107
|
"runtimeArgs": ["--require", "@ciqol/resenv/resolve"]
|
|
146
108
|
```
|
|
147
109
|
|
|
148
|
-
Preloading the outer `nx` process runs too early.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
its environment is loaded; values embedded in build output remain in that output.
|
|
152
|
-
|
|
153
|
-
## Resolution behavior
|
|
154
|
-
|
|
155
|
-
- Only the enabled reference forms are resolved. Ordinary values pass through.
|
|
156
|
-
- Doppler fetches only the named secrets; repeated references share one request
|
|
157
|
-
within a resolution pass. Values are not cached on disk.
|
|
158
|
-
- All lookups must succeed before the environment is changed or a child starts.
|
|
159
|
-
Missing access, malformed references and provider failures stop startup.
|
|
160
|
-
- Fetched values stay literal, even if they contain `$()` or another reference.
|
|
161
|
-
- The canonical preload leaves shell expressions literal. Executing commands
|
|
162
|
-
requires the separate opt-in described below.
|
|
163
|
-
- Application code can read its resolved environment. Access to the same
|
|
164
|
-
credentials also permits other code or sessions to retrieve those secrets.
|
|
165
|
-
|
|
166
|
-
See the current [Doppler limits](https://github.com/ciqol/resenv/blob/main/docs/doppler.md#resolution-and-security-boundaries)
|
|
167
|
-
and [security guidance](https://github.com/ciqol/resenv/blob/main/SECURITY.md).
|
|
110
|
+
Preloading the outer `nx` process runs too early. Keep the preload on each
|
|
111
|
+
application or build process that needs secrets, after its environment is loaded.
|
|
112
|
+
Secrets embedded in build output remain in that output.
|
|
168
113
|
|
|
169
114
|
## Library API
|
|
170
115
|
|
|
171
|
-
Call the
|
|
172
|
-
|
|
116
|
+
Call the synchronous resolver after loading the environment, before importing
|
|
117
|
+
modules that read configuration:
|
|
173
118
|
|
|
174
119
|
```js
|
|
175
120
|
import { resolve } from '@ciqol/resenv'
|
|
176
121
|
|
|
177
122
|
const childEnv = resolve()
|
|
178
|
-
|
|
179
|
-
// Also replace values in process.env; the returned copy can be ignored.
|
|
180
123
|
resolve(process.env, { replace: true })
|
|
181
124
|
```
|
|
182
125
|
|
|
183
|
-
`resolve(env = process.env, options = {})` always returns
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
126
|
+
`resolve(env = process.env, options = {})` always returns an independent
|
|
127
|
+
resolved copy. CommonJS uses `require('@ciqol/resenv')`.
|
|
128
|
+
|
|
129
|
+
| Option | Default | Behavior |
|
|
130
|
+
| --- | --- | --- |
|
|
131
|
+
| `replace` | `false` | Also replace input values after all lookups succeed. Requires `process.env` or writable data properties. |
|
|
132
|
+
| `commands` | `false` | Execute whole-value `$(command)` expressions through POSIX `/bin/sh`. |
|
|
133
|
+
| `commandTimeoutMs` | `30000` | Per-command timeout in milliseconds; a positive integer up to `2147483647`. |
|
|
134
|
+
|
|
135
|
+
Doppler is inferred from original values. Without references, the result is an
|
|
136
|
+
unchanged copy and no credentials are accessed. Library failures throw
|
|
137
|
+
`ResenvError`; its `code` identifies the failure. CLI and preload failures exit
|
|
138
|
+
with a safe message.
|
|
139
|
+
|
|
140
|
+
## Resolution and safety
|
|
141
|
+
|
|
142
|
+
- All lookups must succeed before the input environment changes or a child starts.
|
|
143
|
+
- Only named secrets are fetched; repeated references share a request within a
|
|
144
|
+
resolution pass. Values are not cached on disk.
|
|
145
|
+
- Fetched values stay literal, even if they contain another reference or `$()`.
|
|
146
|
+
- Shell commands require explicit opt-in and run with your permissions. Failed
|
|
147
|
+
resolution cannot undo their file or network effects.
|
|
148
|
+
- Use one preload mode per process. Combining modes or a preload with the CLI
|
|
149
|
+
fails with `CONFLICTING_PRELOADS`. Avoid additional resolvers in `NODE_OPTIONS`.
|
|
150
|
+
- Application code can read its secrets and any credentials supplied to it.
|
|
151
|
+
|
|
152
|
+
See [Doppler limits and compatibility](https://github.com/ciqol/resenv/blob/main/docs/doppler.md)
|
|
153
|
+
and [security guidance](https://github.com/ciqol/resenv/blob/main/SECURITY.md).
|
|
154
|
+
|
|
155
|
+
## Optional commands
|
|
187
156
|
|
|
188
|
-
|
|
189
|
-
`run`. Doppler is the only supported cloud provider today. No options are
|
|
190
|
-
required: without references, the result is an unchanged copy and no credentials
|
|
191
|
-
are accessed. An environment can contain several references, including different
|
|
192
|
-
Doppler projects/configs. Each value selects its own source; a command can supply
|
|
193
|
-
a Doppler token. Commands still require
|
|
194
|
-
`commands: true`. Returned secret values are never interpreted again.
|
|
157
|
+
Enable commands alongside Doppler references through the library:
|
|
195
158
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
159
|
+
```js
|
|
160
|
+
const env = resolve({ BUILD_LABEL: '$(printf local)' }, { commands: true })
|
|
161
|
+
```
|
|
199
162
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
163
|
+
Or use `resenv run --commands -- ...`, or preload
|
|
164
|
+
`@ciqol/resenv/resolve-commands`. The canonical `/resolve` preload leaves shell
|
|
165
|
+
expressions literal. Only use command mode with trusted configuration; see
|
|
166
|
+
[command limits](https://github.com/ciqol/resenv/blob/main/SECURITY.md#command-execution).
|
|
204
167
|
|
|
205
168
|
## Debug startup
|
|
206
169
|
|
|
@@ -208,55 +171,22 @@ preloads enable in-place replacement so application imports see resolved values.
|
|
|
208
171
|
NODE_DEBUG=ciqol:resenv node --require @ciqol/resenv/resolve app.mjs
|
|
209
172
|
```
|
|
210
173
|
|
|
211
|
-
For
|
|
212
|
-
|
|
213
|
-
`
|
|
174
|
+
For Nx, use `NODE_DEBUG=ciqol:resenv nx serve app`. Enable it when launching Node,
|
|
175
|
+
before dotenv loading. Diagnostics omit secrets, tokens, commands and provider
|
|
176
|
+
responses. `NODE_DEBUG=child_process` or `NODE_DEBUG=*` can expose credentials;
|
|
177
|
+
resenv blocks its subprocess operations in that mode. See
|
|
178
|
+
[diagnostic details](https://github.com/ciqol/resenv/blob/main/SECURITY.md#diagnostics).
|
|
214
179
|
|
|
215
|
-
|
|
216
|
-
CIQOL:RESENV 12345: Replaced secret value for "API_TOKEN".
|
|
217
|
-
CIQOL:RESENV 12345: Done: replaced 1 secret value(s).
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
With no matching references, the only message is `Nothing to handle.` Failures
|
|
221
|
-
include a safe error and completion summary. Logs omit values, tokens, command
|
|
222
|
-
text and provider responses; no log files are created.
|
|
223
|
-
|
|
224
|
-
`NODE_DEBUG=child_process` (including `NODE_DEBUG=*`) makes Node print spawn
|
|
225
|
-
options containing credentials. resenv blocks its subprocess operations with
|
|
226
|
-
`UNSAFE_DEBUG_LOGGING` in that mode. Use `NODE_DEBUG=ciqol:resenv` instead.
|
|
180
|
+
## Further reading
|
|
227
181
|
|
|
228
|
-
|
|
182
|
+
Each npm package includes this README for its installed version. The
|
|
183
|
+
[repository README](https://github.com/ciqol/resenv#readme) and linked online
|
|
184
|
+
guides follow current development and may describe newer versions. GitHub
|
|
185
|
+
[releases](https://github.com/ciqol/resenv/releases) contain version change notes.
|
|
229
186
|
|
|
230
|
-
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
is set in the environment. `resenv run --commands -- ...` enables commands
|
|
234
|
-
alongside inferred Doppler references, as does the command preload. Use only
|
|
235
|
-
trusted configuration; commands run with your permissions. A timeout limits
|
|
236
|
-
execution time, but cannot undo file changes, network requests or other effects.
|
|
237
|
-
Leave this option disabled when the environment can contain untrusted input.
|
|
238
|
-
Commands have closed stdin, a 30-second timeout and a 64 KiB combined output
|
|
239
|
-
limit. Trailing LF characters are removed; fetched output stays literal.
|
|
240
|
-
Embedded forms such as `prefix$(command)suffix` are unsupported.
|
|
241
|
-
|
|
242
|
-
Values beginning with `encrypted:` are left unchanged. resenv resolves cloud
|
|
243
|
-
references; dotenvx decryption is outside its scope. The package has no runtime
|
|
244
|
-
npm dependencies.
|
|
245
|
-
|
|
246
|
-
`/resolve-doppler` is an equivalent name for `/resolve`; `run --doppler` remains
|
|
247
|
-
accepted. New integrations should use the canonical entry points above.
|
|
248
|
-
|
|
249
|
-
Use one preload mode per process. Combining `/resolve` and `/resolve-commands`
|
|
250
|
-
or combining a preload with `resenv run` fails with `CONFLICTING_PRELOADS` to
|
|
251
|
-
prevent reinterpreting fetched values. Do not configure a second resolver in
|
|
252
|
-
the child process through `NODE_OPTIONS` or other launch hooks.
|
|
253
|
-
For both modes together, use `resenv run --commands -- ...` or one library call
|
|
254
|
-
with `{ commands: true }`.
|
|
255
|
-
|
|
256
|
-
## Contributing
|
|
257
|
-
|
|
258
|
-
For checkout setup, building, testing, trying local changes in another project
|
|
259
|
-
and submitting fixes, see [CONTRIBUTING.md](https://github.com/ciqol/resenv/blob/main/CONTRIBUTING.md).
|
|
187
|
+
- [Contributing, development and tests](https://github.com/ciqol/resenv/blob/main/CONTRIBUTING.md)
|
|
188
|
+
- [Request provider or platform support](https://github.com/ciqol/resenv/issues/new)
|
|
189
|
+
- [Background: A new Git worktree shouldn't mean another copy of your secrets](https://dev.to/titanron/a-new-git-worktree-shouldnt-mean-another-copy-of-your-secrets-424)
|
|
260
190
|
|
|
261
191
|
## License
|
|
262
192
|
|