@ciqol/resenv 0.1.0 → 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 -158
- package/package.json +2 -8
- package/CONTRIBUTING.md +0 -211
- package/SECURITY.md +0 -74
- package/docs/build.md +0 -139
- package/docs/dependencies.md +0 -68
- package/docs/doppler.md +0 -155
- package/docs/maintainer-handoff.md +0 -40
- package/docs/release-security.md +0 -64
- package/docs/releasing.md +0 -78
- package/docs/security-exceptions.json +0 -6
package/README.md
CHANGED
|
@@ -1,29 +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
|
-
```
|
|
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)
|
|
18
6
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
resenv
|
|
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.
|
|
22
10
|
|
|
23
|
-
|
|
24
|
-
|
|
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.
|
|
25
15
|
|
|
26
|
-
|
|
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.
|
|
27
18
|
|
|
28
19
|
## Install
|
|
29
20
|
|
|
@@ -33,84 +24,60 @@ Install in your application project:
|
|
|
33
24
|
npm install --save-exact @ciqol/resenv
|
|
34
25
|
```
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
The CLI examples below use `npx --no-install` to run the copy installed in your
|
|
40
|
-
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.
|
|
41
29
|
|
|
42
30
|
## Use with Doppler
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
[Doppler's introduction](https://docs.doppler.com/docs/start).
|
|
46
|
-
|
|
47
|
-
### 1. Authenticate locally
|
|
32
|
+
### 1. Authenticate
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
|
|
34
|
+
Install the [official Doppler CLI](https://docs.doppler.com/docs/cli#installation),
|
|
35
|
+
then log in from your application directory:
|
|
51
36
|
|
|
52
37
|
```sh
|
|
53
38
|
doppler login
|
|
54
39
|
```
|
|
55
40
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
> and may vary by platform or CLI version. resenv only reuses its existing token;
|
|
61
|
-
> it does not manage login, logout or credential storage, or access the OS
|
|
62
|
-
> credential store directly.
|
|
63
|
-
|
|
64
|
-
At startup, resenv uses `DOPPLER_TOKEN` when supplied; otherwise it reads the
|
|
65
|
-
existing Doppler CLI token for the application's working directory. It then
|
|
66
|
-
fetches only referenced secrets through the HTTPS API. Missing credentials or
|
|
67
|
-
access stop startup without opening a browser or prompting for login.
|
|
68
|
-
|
|
69
|
-
For CI and other unattended environments, supply `DOPPLER_TOKEN` through your
|
|
70
|
-
runner's secret facility; the CLI is not needed in that mode. See
|
|
71
|
-
[Doppler authentication and platform details](docs/doppler.md), including
|
|
72
|
-
migration from the earlier resenv-managed login.
|
|
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.
|
|
73
45
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
and platform details.
|
|
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.
|
|
77
50
|
|
|
78
|
-
### 2. Declare references
|
|
51
|
+
### 2. Declare references
|
|
79
52
|
|
|
80
|
-
|
|
53
|
+
In the environment your application already loads, such as Nx's `.env.serve`:
|
|
81
54
|
|
|
82
55
|
```dotenv
|
|
83
56
|
API_TOKEN=doppler://my-project/dev/API_TOKEN
|
|
84
57
|
PORT=3000
|
|
85
58
|
```
|
|
86
59
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
The reference itself grants no access: the authenticated identity needs
|
|
90
|
-
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.
|
|
91
62
|
|
|
92
|
-
### 3. Preload
|
|
63
|
+
### 3. Preload on the application process
|
|
93
64
|
|
|
94
|
-
|
|
65
|
+
After your loader has populated the environment:
|
|
95
66
|
|
|
96
67
|
```sh
|
|
97
68
|
node --require @ciqol/resenv/resolve app.cjs
|
|
98
69
|
node --import @ciqol/resenv/resolve app.mjs
|
|
99
70
|
```
|
|
100
71
|
|
|
101
|
-
The preload replaces
|
|
102
|
-
imports execute. It infers Doppler from the value, so no provider flag is needed.
|
|
103
|
-
|
|
72
|
+
The preload replaces references before the application and its imports execute.
|
|
104
73
|
Alternatively, wrap a command whose environment is already populated:
|
|
105
74
|
|
|
106
75
|
```sh
|
|
107
76
|
npx --no-install resenv run -- node app.mjs
|
|
108
77
|
```
|
|
109
78
|
|
|
110
|
-
The wrapper
|
|
111
|
-
|
|
112
|
-
SIGHUP to that child. On POSIX, the child runs in its own session so terminal
|
|
113
|
-
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.
|
|
114
81
|
|
|
115
82
|
## Nx integration
|
|
116
83
|
|
|
@@ -133,126 +100,93 @@ Put the preload on the application's target, after Nx loads its dotenv files:
|
|
|
133
100
|
}
|
|
134
101
|
```
|
|
135
102
|
|
|
136
|
-
Run `nx serve app
|
|
137
|
-
|
|
138
|
-
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:
|
|
139
105
|
|
|
140
106
|
```json
|
|
141
107
|
"runtimeArgs": ["--require", "@ciqol/resenv/resolve"]
|
|
142
108
|
```
|
|
143
109
|
|
|
144
|
-
Preloading the outer `nx` process runs too early.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
its environment is loaded; values embedded in build output remain in that output.
|
|
148
|
-
|
|
149
|
-
## Resolution behavior
|
|
150
|
-
|
|
151
|
-
- Only the enabled reference forms are resolved. Ordinary values pass through.
|
|
152
|
-
- Doppler fetches only the named secrets; repeated references share one request
|
|
153
|
-
within a resolution pass. Values are not cached on disk.
|
|
154
|
-
- All lookups must succeed before the environment is changed or a child starts.
|
|
155
|
-
Missing access, malformed references and provider failures stop startup.
|
|
156
|
-
- Fetched values stay literal, even if they contain `$()` or another reference.
|
|
157
|
-
- The canonical preload leaves shell expressions literal. Executing commands
|
|
158
|
-
requires the separate opt-in described below.
|
|
159
|
-
- Application code can read its resolved environment. Access to the same
|
|
160
|
-
credentials also permits other code or sessions to retrieve those secrets.
|
|
161
|
-
|
|
162
|
-
See [Doppler limits](docs/doppler.md#resolution-and-security-boundaries) and
|
|
163
|
-
[security guidance](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.
|
|
164
113
|
|
|
165
114
|
## Library API
|
|
166
115
|
|
|
167
|
-
Call the
|
|
168
|
-
|
|
116
|
+
Call the synchronous resolver after loading the environment, before importing
|
|
117
|
+
modules that read configuration:
|
|
169
118
|
|
|
170
119
|
```js
|
|
171
120
|
import { resolve } from '@ciqol/resenv'
|
|
172
121
|
|
|
173
122
|
const childEnv = resolve()
|
|
174
|
-
|
|
175
|
-
// Also replace values in process.env; the returned copy can be ignored.
|
|
176
123
|
resolve(process.env, { replace: true })
|
|
177
124
|
```
|
|
178
125
|
|
|
179
|
-
`resolve(env = process.env, options = {})` always returns
|
|
180
|
-
|
|
181
|
-
`replace: true`, it also replaces values in the input after every lookup succeeds;
|
|
182
|
-
the return value is still an independent copy.
|
|
126
|
+
`resolve(env = process.env, options = {})` always returns an independent
|
|
127
|
+
resolved copy. CommonJS uses `require('@ciqol/resenv')`.
|
|
183
128
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
a Doppler token. Commands still require
|
|
190
|
-
`commands: true`. Returned secret values are never interpreted again.
|
|
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`. |
|
|
191
134
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
`code` identifies the failure. CLI and preload failures exit
|
|
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.
|
|
195
139
|
|
|
196
|
-
|
|
197
|
-
property, setter or Proxy target fails before any replacement is committed.
|
|
198
|
-
Keep the default copy mode for inputs that should remain unchanged. The Node
|
|
199
|
-
preloads enable in-place replacement so application imports see resolved values.
|
|
140
|
+
## Resolution and safety
|
|
200
141
|
|
|
201
|
-
|
|
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.
|
|
202
151
|
|
|
203
|
-
|
|
204
|
-
|
|
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
|
|
156
|
+
|
|
157
|
+
Enable commands alongside Doppler references through the library:
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
const env = resolve({ BUILD_LABEL: '$(printf local)' }, { commands: true })
|
|
205
161
|
```
|
|
206
162
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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).
|
|
167
|
+
|
|
168
|
+
## Debug startup
|
|
210
169
|
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
CIQOL:RESENV 12345: Done: replaced 1 secret value(s).
|
|
170
|
+
```sh
|
|
171
|
+
NODE_DEBUG=ciqol:resenv node --require @ciqol/resenv/resolve app.mjs
|
|
214
172
|
```
|
|
215
173
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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).
|
|
219
179
|
|
|
220
|
-
|
|
221
|
-
options containing credentials. resenv blocks its subprocess operations with
|
|
222
|
-
`UNSAFE_DEBUG_LOGGING` in that mode. Use `NODE_DEBUG=ciqol:resenv` instead.
|
|
180
|
+
## Further reading
|
|
223
181
|
|
|
224
|
-
|
|
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.
|
|
225
186
|
|
|
226
|
-
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
is set in the environment. `resenv run --commands -- ...` enables commands
|
|
230
|
-
alongside inferred Doppler references, as does the command preload. Use only
|
|
231
|
-
trusted configuration; commands run with your permissions. A timeout limits
|
|
232
|
-
execution time, but cannot undo file changes, network requests or other effects.
|
|
233
|
-
Leave this option disabled when the environment can contain untrusted input.
|
|
234
|
-
Commands have closed stdin, a 30-second timeout and a 64 KiB combined output
|
|
235
|
-
limit. Trailing LF characters are removed; fetched output stays literal.
|
|
236
|
-
Embedded forms such as `prefix$(command)suffix` are unsupported.
|
|
237
|
-
|
|
238
|
-
Values beginning with `encrypted:` are left unchanged. resenv resolves cloud
|
|
239
|
-
references; dotenvx decryption is outside its scope. The package has no runtime
|
|
240
|
-
npm dependencies.
|
|
241
|
-
|
|
242
|
-
`/resolve-doppler` is an equivalent name for `/resolve`; `run --doppler` remains
|
|
243
|
-
accepted. New integrations should use the canonical entry points above.
|
|
244
|
-
|
|
245
|
-
Use one preload mode per process. Combining `/resolve` and `/resolve-commands`
|
|
246
|
-
or combining a preload with `resenv run` fails with `CONFLICTING_PRELOADS` to
|
|
247
|
-
prevent reinterpreting fetched values. Do not configure a second resolver in
|
|
248
|
-
the child process through `NODE_OPTIONS` or other launch hooks.
|
|
249
|
-
For both modes together, use `resenv run --commands -- ...` or one library call
|
|
250
|
-
with `{ commands: true }`.
|
|
251
|
-
|
|
252
|
-
## Contributing
|
|
253
|
-
|
|
254
|
-
For checkout setup, building, testing, trying local changes in another project
|
|
255
|
-
and submitting fixes, see [CONTRIBUTING.md](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)
|
|
256
190
|
|
|
257
191
|
## License
|
|
258
192
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ciqol/resenv",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Replace environment references with their resolved values at application startup",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -71,7 +71,6 @@
|
|
|
71
71
|
"engines": {
|
|
72
72
|
"node": ">=20"
|
|
73
73
|
},
|
|
74
|
-
"dependencies": {},
|
|
75
74
|
"files": [
|
|
76
75
|
"*.cjs",
|
|
77
76
|
"*.mjs",
|
|
@@ -79,11 +78,6 @@
|
|
|
79
78
|
"*.d.mts",
|
|
80
79
|
"doppler",
|
|
81
80
|
"bin",
|
|
82
|
-
"types"
|
|
83
|
-
"README.md",
|
|
84
|
-
"LICENSE",
|
|
85
|
-
"CONTRIBUTING.md",
|
|
86
|
-
"SECURITY.md",
|
|
87
|
-
"docs"
|
|
81
|
+
"types"
|
|
88
82
|
]
|
|
89
83
|
}
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
# Contributing
|
|
2
|
-
|
|
3
|
-
Starting a new session? Read the [maintainer handoff](docs/maintainer-handoff.md)
|
|
4
|
-
and [repository instructions](https://github.com/ciqol/resenv/blob/main/AGENTS.md) before editing or releasing.
|
|
5
|
-
|
|
6
|
-
The [README](README.md) covers using resenv in an application. This guide covers
|
|
7
|
-
changing resenv itself and verifying those changes.
|
|
8
|
-
|
|
9
|
-
Merge to protected `main` approves release. CI uses standard semantic-release
|
|
10
|
-
and the official npm/GitHub plugins to publish regular `0.x.x` versions to
|
|
11
|
-
`latest`. The root and local builds stay private; only the protected release
|
|
12
|
-
job makes the tested build publishable. See [releasing](docs/releasing.md)
|
|
13
|
-
and [release security](docs/release-security.md).
|
|
14
|
-
The source uses the [MIT license](LICENSE), copyright ciqol contributors.
|
|
15
|
-
|
|
16
|
-
## Local development
|
|
17
|
-
|
|
18
|
-
Use the Node version in `.nvmrc` and npm:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
nvm use
|
|
22
|
-
npm ci
|
|
23
|
-
npm run verify
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
The committed `.npmrc` omits automatically installed peer dependencies. The
|
|
27
|
-
release planner calls the two official plugins directly, so their full engine
|
|
28
|
-
peer and its publisher dependencies are intentionally not installed. Audit and
|
|
29
|
-
planning enforce that absence. `npm ls` still reports the declared missing
|
|
30
|
-
engine peers; standalone plugin behavior is covered directly by the release
|
|
31
|
-
specs. Keep this install policy when refreshing the lockfile; do not use force
|
|
32
|
-
or legacy peer resolution. See [the dependency review](docs/dependencies.md).
|
|
33
|
-
|
|
34
|
-
`npm run verify` is the complete local check: lint, strict source/spec type
|
|
35
|
-
checks, build, unit/process tests and installed-package checks. To build without
|
|
36
|
-
running the checks, use `npm run build`.
|
|
37
|
-
|
|
38
|
-
After building, try the CLI from this checkout:
|
|
39
|
-
|
|
40
|
-
```sh
|
|
41
|
-
node dist/bin/resenv.cjs --help
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Author library and CLI code as `.ts`; Rollup's TypeScript plugin produces both
|
|
45
|
-
module formats and declarations from that implementation. Colocate Vitest unit
|
|
46
|
-
specs as `*.spec.ts` beside each tested module and import its source. Build and
|
|
47
|
-
release scripts have colocated `*.spec.mjs` Vitest specs. Keep
|
|
48
|
-
process, package and integration checks in `test/` as `.mjs`; they exercise
|
|
49
|
-
compiled output and installed packages. Tests use dummy credentials and commands.
|
|
50
|
-
Never use real secrets in fixtures, terminal output, screenshots, issues, or
|
|
51
|
-
pull requests.
|
|
52
|
-
|
|
53
|
-
Provider detection belongs to the original environment values, including library
|
|
54
|
-
calls without options. Keep shell execution behind `commands: true`, preserve
|
|
55
|
-
literal fetched output, and validate references before any command runs.
|
|
56
|
-
|
|
57
|
-
ESLint applies rules that use type information to the TypeScript implementation and specs
|
|
58
|
-
and checks the JavaScript build tooling.
|
|
59
|
-
Use `npm run lint:fix` for available automatic fixes; preserve the repository's
|
|
60
|
-
existing compact formatting. Public object shapes use `type` with `readonly`
|
|
61
|
-
properties. `Environment` is intentionally mutable because in-place resolution
|
|
62
|
-
updates it. `npm run typecheck` checks the entire library and CLI with `strict`
|
|
63
|
-
and `noUncheckedIndexedAccess`. A separate spec configuration checks tests without
|
|
64
|
-
shipping them in JavaScript or declarations. Do not maintain separate handwritten declarations.
|
|
65
|
-
|
|
66
|
-
```sh
|
|
67
|
-
npm run test:unit # colocated Vitest specs, no build required
|
|
68
|
-
npm run test:watch # watch unit specs while editing
|
|
69
|
-
npm run test:coverage # source unit coverage, text, lcov and Cobertura output
|
|
70
|
-
npm run test:integration # process checks, requires a build
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
`npm test` runs unit and process tests. Mock or inject provider calls, credential
|
|
74
|
-
lookup and process control in unit tests. Keep checks that spawn actual commands
|
|
75
|
-
or temporary applications in `test/`. The unit coverage
|
|
76
|
-
report measures source and is separate from packed-package and process checks.
|
|
77
|
-
`npm run verify` enforces a 90% global floor for source statements, branches,
|
|
78
|
-
functions and lines. Worker and preload entry files stay in the denominator;
|
|
79
|
-
the CLI is checked separately by process and packed-package tests. CI retains
|
|
80
|
-
LCOV and Cobertura reports for seven days in the `resenv-coverage` artifact.
|
|
81
|
-
The official `actions/upload-code-coverage` action uploads Cobertura in a separate
|
|
82
|
-
job for same-repository PRs and `main` runs; other runs retain the local gate and
|
|
83
|
-
report artifacts. The main `ci` job groups audits, lint, types, coverage, build
|
|
84
|
-
and packed-package/process checks on the pinned Node version. CLI lookup checks
|
|
85
|
-
use injected helpers and temporary
|
|
86
|
-
dummy executables; they never access a developer credential store or
|
|
87
|
-
authenticated provider session.
|
|
88
|
-
The `smoke` matrix checks that same archive on Linux Node 20 and 22 and macOS
|
|
89
|
-
with the pinned Node version; it does not build or rerun source unit specs.
|
|
90
|
-
|
|
91
|
-
Use normal npm lifecycle behavior locally and in CI. Review install hooks,
|
|
92
|
-
including implicit native builds, when changing dependencies; record any
|
|
93
|
-
required setup in [the dependency review](docs/dependencies.md). Suppressing
|
|
94
|
-
lifecycle hooks can skip required setup, so it is not part of the standard
|
|
95
|
-
installation commands. The explicit build/check commands remain required.
|
|
96
|
-
|
|
97
|
-
The package check packs `dist/` and installs that tarball into a temporary
|
|
98
|
-
consumer outside the repository. The install is offline, uses npm's existing
|
|
99
|
-
cache and the repository's reviewed runtime lock entries. It installs with
|
|
100
|
-
`npm ci` without needing cached registry metadata. It does not link the source
|
|
101
|
-
tree or publish. Run `npm ci` first to populate the archive cache. The check
|
|
102
|
-
exercises both module formats, CLI and preloads, shared error identity, single
|
|
103
|
-
preload execution and `.cts`/`.mts` consumer types.
|
|
104
|
-
|
|
105
|
-
Pass an existing archive to test the same build CI uses:
|
|
106
|
-
`npm run test:package -- /absolute/path/to/package.tgz`. For a final CI candidate,
|
|
107
|
-
also pass its `release.json` as the second argument. The supplied package's
|
|
108
|
-
name, version, executable mode and manifest are checked before runtime probes.
|
|
109
|
-
The README inside the archive must match the checkout, install from npm's
|
|
110
|
-
`latest` channel and avoid unpublished or local-archive installation guidance.
|
|
111
|
-
`npm run verify` runs lint, typecheck, build and tests; `npm run release:check`
|
|
112
|
-
also previews the package contents. Neither publishes or creates a tag.
|
|
113
|
-
|
|
114
|
-
Rebuild after source, declarations, metadata or documentation changes. The build
|
|
115
|
-
cleans `dist/` first and generates its manifest from the root package. See
|
|
116
|
-
[docs/build.md](docs/build.md). Ordinary local builds remain private. Only a validated CI release plan removes
|
|
117
|
-
that guard from the distribution manifest; never edit it by hand.
|
|
118
|
-
|
|
119
|
-
## Try changes in an application
|
|
120
|
-
|
|
121
|
-
### Install a local archive
|
|
122
|
-
|
|
123
|
-
From the resenv checkout:
|
|
124
|
-
|
|
125
|
-
```sh
|
|
126
|
-
npm run build
|
|
127
|
-
npm run pack:local
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Install the resulting archive from the application's directory:
|
|
131
|
-
|
|
132
|
-
```sh
|
|
133
|
-
npm install --save-exact /absolute/path/to/ciqol-resenv-0.1.0.tgz
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
This changes the application's manifest and lockfile. The archive must exist
|
|
137
|
-
wherever it installs dependencies. Use a new archive version for changes to an
|
|
138
|
-
already shared build; never overwrite an archive another project uses. Root
|
|
139
|
-
package overrides do not propagate to consumers; inspect the installed tree
|
|
140
|
-
against [the dependency review](docs/dependencies.md).
|
|
141
|
-
|
|
142
|
-
### Try local changes without changing the application's CI
|
|
143
|
-
|
|
144
|
-
Link this checkout's built `dist/` directory at the application's ignored
|
|
145
|
-
`node_modules/@ciqol/resenv`, retaining any existing installation first. Keep
|
|
146
|
-
references in an ignored `.env.serve.local` and the application's target edit
|
|
147
|
-
local. Leave its manifest, lockfile and CI configuration unchanged.
|
|
148
|
-
|
|
149
|
-
Rebuild resenv after source, metadata or documentation changes and restart the
|
|
150
|
-
application. An application `npm ci` can remove the link; recreate it when needed.
|
|
151
|
-
Authenticate with the official Doppler CLI from the application's directory:
|
|
152
|
-
|
|
153
|
-
```sh
|
|
154
|
-
doppler login
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
resenv reuses that login at runtime. Automated tests use injected or mocked
|
|
158
|
-
credentials; real login is a manual integration check owned by Doppler's CLI.
|
|
159
|
-
|
|
160
|
-
## Optional integration checks
|
|
161
|
-
|
|
162
|
-
`npm run bench` measures fresh-process startup, a plain 200-variable environment,
|
|
163
|
-
and a mocked provider with eight distinct lookups. It needs a build first and
|
|
164
|
-
does not contact a provider. Timings are observations, not CI pass/fail thresholds.
|
|
165
|
-
|
|
166
|
-
With an existing Nx installation:
|
|
167
|
-
|
|
168
|
-
```sh
|
|
169
|
-
npm run test:nx -- /absolute/path/to/workspace/node_modules
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
This creates a temporary Nx workspace and checks target-file loading,
|
|
173
|
-
precedence and secret resolution with dummy values. It does not use the
|
|
174
|
-
source workspace's dotenv files, credentials or remote cache.
|
|
175
|
-
|
|
176
|
-
## Changes
|
|
177
|
-
|
|
178
|
-
Keep dotenv file discovery with the caller. Doppler is the only built-in cloud
|
|
179
|
-
provider; its authentication and lookups live under `src/doppler/`.
|
|
180
|
-
Preserve all-or-nothing environment updates, strict failures, explicit command
|
|
181
|
-
opt-in and literal handling of resolved values. Update the public API types and
|
|
182
|
-
documentation together with behavior changes.
|
|
183
|
-
|
|
184
|
-
Keep one public resolver, `resolve()`. It always returns an independent
|
|
185
|
-
resolved copy and replaces input values only with `{ replace: true }`. Preloads
|
|
186
|
-
enable that option; the CLI passes the returned copy to its child process.
|
|
187
|
-
|
|
188
|
-
Add regression tests for changed behavior and avoid real provider calls. Use
|
|
189
|
-
Conventional Commit subjects, for example `fix(resolver): preserve empty values`.
|
|
190
|
-
Review dependency changes under the [dependency policy](docs/dependencies.md)
|
|
191
|
-
and put the evidence in the PR. Update the guide when a lasting choice changes.
|
|
192
|
-
|
|
193
|
-
CODEOWNERS identifies the maintainer. Keep bug reports and pull requests focused
|
|
194
|
-
on observable behavior and include the checks run. Weekly dependency updates are
|
|
195
|
-
grouped, with major version updates reviewed separately; bots cannot merge them.
|
|
196
|
-
|
|
197
|
-
Keep the README focused on installation, authentication, application integration,
|
|
198
|
-
API behavior and troubleshooting. Put contributor tooling, test commands and
|
|
199
|
-
local development instructions here; detailed internals belong in `docs/`.
|
|
200
|
-
Keep docs current rather than appending session logs, dated audit reports or
|
|
201
|
-
test transcripts. Record run results in PRs and CI.
|
|
202
|
-
|
|
203
|
-
Security reports follow [SECURITY.md](SECURITY.md). Publication and repository
|
|
204
|
-
visibility changes require a separate maintainer decision; see the
|
|
205
|
-
[release checklist](docs/releasing.md).
|
|
206
|
-
|
|
207
|
-
npm releases run only through GitHub Actions with npm trusted publishing (OIDC).
|
|
208
|
-
The maintainer configures the npm side. Local development and release checks
|
|
209
|
-
do not require `npm login`; do not publish from a developer machine or add npm
|
|
210
|
-
publishing tokens. CI must publish the exact candidate archive that its tests
|
|
211
|
-
verified.
|
package/SECURITY.md
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Security
|
|
2
|
-
|
|
3
|
-
## Scope and trust
|
|
4
|
-
|
|
5
|
-
resenv resolves values in a process environment. It does not provide a vault,
|
|
6
|
-
access-control service, key rotation, or isolation between programs running
|
|
7
|
-
with the same credentials. The application can read its resolved secrets and
|
|
8
|
-
any credentials supplied to it.
|
|
9
|
-
|
|
10
|
-
Doppler mode uses a fixed HTTPS API origin, disables redirects and fetches only
|
|
11
|
-
referenced secret names. It does not execute shell expressions. Credentials
|
|
12
|
-
come from an explicit `DOPPLER_TOKEN` or the current directory's existing
|
|
13
|
-
Doppler CLI login. A fixed CLI helper captures that token privately; resenv
|
|
14
|
-
does not parse Doppler's config files. An API rejection never triggers a switch
|
|
15
|
-
to another identity. The official Doppler CLI owns browser authorization,
|
|
16
|
-
token storage, login and logout. See [Doppler details](docs/doppler.md)
|
|
17
|
-
for lookup rules, credential scope, migration and platform limits.
|
|
18
|
-
The canonical `resolve` preload and `run` command select Doppler only for
|
|
19
|
-
`doppler://` values. They do not infer shell execution from `$()` values.
|
|
20
|
-
Startup does not initiate login. Use `doppler login` separately for local
|
|
21
|
-
development or supply a suitably scoped token for unattended runs.
|
|
22
|
-
|
|
23
|
-
Doppler's credential storage does not isolate credentials from other code
|
|
24
|
-
running as the same user with access to them. resenv does not read or write the
|
|
25
|
-
OS credential store directly or persist login tokens or fetched secrets.
|
|
26
|
-
It does not automatically remove an explicitly supplied `DOPPLER_TOKEN` from
|
|
27
|
-
the application environment. Tokens, captured CLI output and provider response
|
|
28
|
-
bodies are not logged. The Node preload's private worker exchanges credentials
|
|
29
|
-
and results over captured pipes, never process arguments or dotenv files.
|
|
30
|
-
|
|
31
|
-
Command mode executes trusted configuration with the current user's
|
|
32
|
-
permissions. Enable it only for configuration you have reviewed. Commands can
|
|
33
|
-
access files and the network; failed resolution cannot undo their external
|
|
34
|
-
effects. Commands are bounded by timeout and output limits, and their output
|
|
35
|
-
is not included in resenv diagnostics.
|
|
36
|
-
|
|
37
|
-
Node's `child_process` debug category prints spawn options, including stdin
|
|
38
|
-
and environment values. resenv refuses its own subprocess and credential-helper
|
|
39
|
-
operations when that category is enabled, including through `NODE_DEBUG=*`.
|
|
40
|
-
Use `NODE_DEBUG=ciqol:resenv` for diagnostics that omit values. This guard does not
|
|
41
|
-
control application logs, other instrumentation, or a debugger attached to the
|
|
42
|
-
process.
|
|
43
|
-
|
|
44
|
-
All values are resolved before resenv updates the caller's environment or
|
|
45
|
-
starts the application. Provider failures, command failures and invalid
|
|
46
|
-
environment values stop startup. Fetched values are never evaluated recursively. Application logs are outside resenv's control.
|
|
47
|
-
|
|
48
|
-
Different automatic preload modes cannot be combined in one process. Otherwise
|
|
49
|
-
the second mode could execute literal data fetched by the first.
|
|
50
|
-
Combining a preload with the CLI is rejected for the same reason. Do not add
|
|
51
|
-
another resolver to the child through `NODE_OPTIONS` or other launch hooks.
|
|
52
|
-
Use one `resenv run --commands` invocation or one library call with commands
|
|
53
|
-
enabled to resolve cloud references and commands together. Repeated manual
|
|
54
|
-
library calls are separate operations; only pass original configuration to them.
|
|
55
|
-
|
|
56
|
-
Provider responses must be valid UTF-8 and JSON, and resolved strings must not
|
|
57
|
-
contain lone Unicode surrogates or null bytes. In-place replacement preflights
|
|
58
|
-
all changed properties; read-only properties, setters and Proxy targets are
|
|
59
|
-
rejected before any values are committed. Use `resolve()` to obtain a copy
|
|
60
|
-
when the input is not a writable environment record.
|
|
61
|
-
|
|
62
|
-
This experimental package has not had an independent security audit. See
|
|
63
|
-
[verification](CONTRIBUTING.md) and [Doppler platform limits](docs/doppler.md).
|
|
64
|
-
|
|
65
|
-
## Reporting a vulnerability
|
|
66
|
-
|
|
67
|
-
Do not open a public issue containing a vulnerability, credentials or sensitive
|
|
68
|
-
output. [Report a vulnerability privately](https://github.com/ciqol/resenv/security/advisories/new)
|
|
69
|
-
through GitHub. If that option is unavailable, contact the maintainer through
|
|
70
|
-
an existing private channel.
|
|
71
|
-
|
|
72
|
-
Include affected versions, platform, impact and a minimal reproduction using
|
|
73
|
-
dummy data. Never include production tokens, private keys or environment dumps.
|
|
74
|
-
There is no guaranteed response time or long-term support policy yet.
|
package/docs/build.md
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# Build and package contract
|
|
2
|
-
|
|
3
|
-
The repository is one Node.js package. The library and CLI are authored in
|
|
4
|
-
strict TypeScript. Vitest unit specs use colocated `*.spec.ts` files. Process,
|
|
5
|
-
package and integration checks and build orchestration use `.mjs`. Rollup's official
|
|
6
|
-
TypeScript plugin compiles the implementation; consumers need no TypeScript
|
|
7
|
-
loader or compiler.
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
npm ci
|
|
11
|
-
npm run build
|
|
12
|
-
npm test
|
|
13
|
-
npm run test:package
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Output
|
|
17
|
-
|
|
18
|
-
| Public entry | ESM | CommonJS | Declarations |
|
|
19
|
-
| --- | --- | --- | --- |
|
|
20
|
-
| `@ciqol/resenv` | `index.mjs` | `index.cjs` | `index.d.mts`, `index.d.cts` |
|
|
21
|
-
| `@ciqol/resenv/resolve` | `resolve.mjs` | `resolve.cjs` | `resolve.d.mts`, `resolve.d.cts` |
|
|
22
|
-
| `@ciqol/resenv/resolve-commands` | `resolve-commands.mjs` | `resolve-commands.cjs` | `resolve-commands.d.mts`, `resolve-commands.d.cts` |
|
|
23
|
-
| `@ciqol/resenv/resolve-doppler` | `resolve-doppler.mjs` | `resolve-doppler.cjs` | `resolve-doppler.d.mts`, `resolve-doppler.d.cts` |
|
|
24
|
-
|
|
25
|
-
These paths are relative to `dist/`. The executable points to
|
|
26
|
-
`bin/resenv.cjs`; Rollup also emits its ESM wrapper. The command's user-facing
|
|
27
|
-
name stays `resenv`.
|
|
28
|
-
|
|
29
|
-
`resolve` reads the inherited environment and replaces Doppler references with
|
|
30
|
-
their fetched values before application code starts. Doppler is the only
|
|
31
|
-
built-in cloud provider. Original `encrypted:` values remain literal.
|
|
32
|
-
`resolve-doppler` imports that same preload, so loading both names does not resolve fetched output again. Arbitrary commands require the
|
|
33
|
-
separate `resolve-commands` entry or `run --commands`.
|
|
34
|
-
|
|
35
|
-
The private `doppler-worker.cjs` entry lets synchronous preloads wait for HTTPS
|
|
36
|
-
without turning the public CommonJS API into a promise. The worker is packed
|
|
37
|
-
alongside the entries but is not a public export. It is located through package
|
|
38
|
-
self-resolution, so the installed tarball does not depend on source paths.
|
|
39
|
-
|
|
40
|
-
The root exports map defines the public entries. The build compiles their
|
|
41
|
-
source with Rollup and its TypeScript plugin, then generates ESM facades from the exported
|
|
42
|
-
names. Both formats load one CommonJS implementation. This preserves error
|
|
43
|
-
class identity and shares the module cache when both preload forms are used.
|
|
44
|
-
It follows Node's documented mitigation for the
|
|
45
|
-
[dual-package hazard](https://nodejs.org/api/packages.html#dual-commonjs-es-module-packages).
|
|
46
|
-
|
|
47
|
-
The CommonJS build preserves the module graph. Source unit specs import their
|
|
48
|
-
adjacent modules; higher-level process and clean-consumer checks exercise the
|
|
49
|
-
compiled modules and the same archive. Matrix jobs do not recompile TypeScript. Only the
|
|
50
|
-
entries in the exports map are public package imports.
|
|
51
|
-
|
|
52
|
-
The package has no runtime npm dependencies. Node built-ins remain external;
|
|
53
|
-
Rollup does not bundle build tools into the application package. The build
|
|
54
|
-
resolves `import.meta.url` to the Node filename in CJS output; browser-like
|
|
55
|
-
globals in a Node test environment cannot change it.
|
|
56
|
-
[Rollup's external option](https://rollupjs.org/configuration-options/#external)
|
|
57
|
-
controls which imports remain outside the bundle.
|
|
58
|
-
|
|
59
|
-
The compiler emits declarations into `dist/types/`. Generated `.d.mts` and
|
|
60
|
-
`.d.cts` entry facades re-export that shared declaration graph; there is no
|
|
61
|
-
handwritten public declaration file or separate declaration-bundler dependency.
|
|
62
|
-
The generated package has no `type` field, so its shared `.d.ts` graph describes
|
|
63
|
-
the CommonJS implementation. The exports map lists `types` first and selects
|
|
64
|
-
the entry facade for the consumer's
|
|
65
|
-
module format, as described by
|
|
66
|
-
[TypeScript's ESM/CommonJS package guidance](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html).
|
|
67
|
-
Consumer compilation checks both formats, including invalid inputs that must
|
|
68
|
-
remain type errors.
|
|
69
|
-
|
|
70
|
-
Public options use type aliases and readonly properties. `Environment` stays
|
|
71
|
-
mutable for optional in-place replacement. `resolve()` always returns a new
|
|
72
|
-
`Environment`, with input replacement enabled only by `{ replace: true }`. It
|
|
73
|
-
does not preserve a generic input type: resolved strings cannot retain a
|
|
74
|
-
literal reference type.
|
|
75
|
-
ESLint uses type information and enforces the selected style rules. The compiler
|
|
76
|
-
checks all library/CLI source, colocated unit specs and both consumer formats with `strict` and
|
|
77
|
-
`noUncheckedIndexedAccess`. Provider responses and parsed worker input start as
|
|
78
|
-
`unknown` and are validated before use. Compiler failures stop the build.
|
|
79
|
-
|
|
80
|
-
The source target is ES2023. `ES2024.String` supplies the declaration for
|
|
81
|
-
`isWellFormed()`, whose availability is also checked by the Node 20/22/24 runtime
|
|
82
|
-
tests. Node types match the Node 24 development toolchain; the runtime matrix
|
|
83
|
-
remains necessary to detect use of APIs absent from the oldest supported Node.
|
|
84
|
-
|
|
85
|
-
## Generated manifest and packing
|
|
86
|
-
|
|
87
|
-
The build removes stale output first. It derives `dist/package.json` from the
|
|
88
|
-
root manifest, rebases entry paths, and omits development dependencies, scripts,
|
|
89
|
-
overrides and a package-wide `type` field. Explicit `.mjs` and `.cjs` extensions
|
|
90
|
-
select the output format. README, the MIT `LICENSE`, contributor/security guides
|
|
91
|
-
and docs are copied into the distribution and included in the archive.
|
|
92
|
-
|
|
93
|
-
Ordinary local and CI builds retain `private: true`. Only the protected release
|
|
94
|
-
job makes the tested build publishable and lets the npm plugin set its version.
|
|
95
|
-
The development root stays private. Release consumer checks validate the final
|
|
96
|
-
versioned package before direct publication; see
|
|
97
|
-
[releasing](releasing.md).
|
|
98
|
-
|
|
99
|
-
`npm run pack:local` packs the generated directory. `npm run test:package`
|
|
100
|
-
instead packs into a temporary directory and installs it offline into a clean
|
|
101
|
-
consumer. It checks imports, requires, preloads, CLI behavior and declarations;
|
|
102
|
-
the consumer cannot load resenv's source files or build dependencies. The
|
|
103
|
-
runtime entries from the repository lockfile are used in the consumer lockfile.
|
|
104
|
-
Its only direct dependency is the packed archive. An offline `npm ci` verifies
|
|
105
|
-
archive integrity and installs the reviewed versions without registry metadata.
|
|
106
|
-
|
|
107
|
-
With `npm run test:package -- /path/to/package.tgz`, the same checks inspect
|
|
108
|
-
and install the supplied archive without rebuilding it. Its name, version,
|
|
109
|
-
manifest and executable mode must match the package contract. CI uses this
|
|
110
|
-
form so every platform checks the same built bytes.
|
|
111
|
-
|
|
112
|
-
Keep tarballs already consumed by other projects immutable. No existing
|
|
113
|
-
consumer artifact is rebuilt in place by these tests.
|
|
114
|
-
|
|
115
|
-
## CI
|
|
116
|
-
|
|
117
|
-
The `ci` job checks advisories and registry signatures, lint, types and source
|
|
118
|
-
coverage, then builds and packs once. It tests the private archive and processes
|
|
119
|
-
on the pinned Node version. The `smoke` matrix tests that archive on Linux Node
|
|
120
|
-
20/22 and macOS with pinned Node 24; it never recompiles source. Coverage runs
|
|
121
|
-
once, with a separate job uploading the report on same-repository PRs and main.
|
|
122
|
-
Required archives and coverage reports are retained for seven days.
|
|
123
|
-
|
|
124
|
-
After a merge to protected `main`, `release` downloads the tested build and runs
|
|
125
|
-
semantic-release with the official npm/GitHub plugins. The npm plugin prepares
|
|
126
|
-
version metadata and a tarball; the local verification hook checks the final
|
|
127
|
-
package's consumer contract before publication. Source is never rebuilt in the
|
|
128
|
-
release job. The official npm plugin publishes the prepared directory with no
|
|
129
|
-
package lifecycle scripts. See [releasing](releasing.md) for the one-time 0.1.0
|
|
130
|
-
bootstrap and failure handling.
|
|
131
|
-
|
|
132
|
-
PRs and manual dispatches cannot publish. Release permissions are limited to
|
|
133
|
-
GitHub contents write and OIDC. Package and registry secrets are absent from
|
|
134
|
-
validation jobs. Every checkout disables persisted credentials, and the release
|
|
135
|
-
token is scoped to the release step. Official GitHub actions use exact release
|
|
136
|
-
tags; other remote actions require commit SHAs.
|
|
137
|
-
|
|
138
|
-
The protected branch requires `ci`, `coverage`, all three `smoke` contexts and
|
|
139
|
-
`Analyze (javascript-typescript)`. Keep these names stable when editing CI.
|
package/docs/dependencies.md
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Dependencies
|
|
2
|
-
|
|
3
|
-
resenv has no runtime npm dependencies. All tools are development-only and
|
|
4
|
-
excluded from the consumer package. Exact direct versions and archive integrity
|
|
5
|
-
live in package.json and package-lock.json. Use the pinned Node version and
|
|
6
|
-
normal `npm ci`; review install hooks instead of disabling them globally.
|
|
7
|
-
|
|
8
|
-
| Packages | Purpose | License |
|
|
9
|
-
| --- | --- | --- |
|
|
10
|
-
| `rollup`, `@rollup/plugin-typescript` | CommonJS, ESM facades and declarations | MIT |
|
|
11
|
-
| `typescript` | Strict implementation and consumer checks | Apache-2.0 |
|
|
12
|
-
| `tslib` | Build-time compiler helpers | 0BSD |
|
|
13
|
-
| `@types/node` | Pinned runtime types | MIT |
|
|
14
|
-
| `eslint`, `typescript-eslint` | Source and tooling lint | MIT |
|
|
15
|
-
| `vitest`, `@vitest/coverage-v8` | Unit tests and coverage | MIT |
|
|
16
|
-
| `semantic-release` | Standard version, tag and release orchestration | MIT |
|
|
17
|
-
| `@semantic-release/commit-analyzer`, `@semantic-release/release-notes-generator` | Commit classification and release notes | MIT |
|
|
18
|
-
| `@semantic-release/npm`, `@semantic-release/github` | Official npm/GitHub publishing | MIT |
|
|
19
|
-
| `npm-undici-patch`, `npm-ip-address-patch` | Exact upstream fixes for npm's bundled development dependencies | MIT |
|
|
20
|
-
|
|
21
|
-
## Release tooling
|
|
22
|
-
|
|
23
|
-
The user selected standard semantic-release on main instead of maintaining a
|
|
24
|
-
custom staging/finalization lifecycle. The official engine and plugins provide
|
|
25
|
-
the release conventions and integrations that would otherwise need custom code.
|
|
26
|
-
They are pinned to 25.0.9 (engine), 13.2.0 (npm), and 12.0.10 (GitHub), alongside
|
|
27
|
-
the existing analysis/notes plugins. npm is pinned transitively to 11.21.1 so its
|
|
28
|
-
bundled implementation remains reviewable.
|
|
29
|
-
|
|
30
|
-
The temporary development aliases resolve to upstream `undici@6.29.1` and
|
|
31
|
-
`ip-address@10.7.5`. Both have no runtime dependencies or registry install hooks
|
|
32
|
-
and support the pinned Node runtime. The root postinstall hook copies their
|
|
33
|
-
locked registry contents into npm's bundle; see the checks and removal procedure
|
|
34
|
-
in [release security](release-security.md#temporary-npm-bundle-repair). Upstream
|
|
35
|
-
sources are [Undici](https://github.com/nodejs/undici/releases/tag/v6.29.1) and
|
|
36
|
-
[ip-address](https://github.com/beaugunderson/ip-address/releases/tag/v10.7.5).
|
|
37
|
-
|
|
38
|
-
Canonical sources are [semantic-release](https://github.com/semantic-release/semantic-release),
|
|
39
|
-
[npm plugin](https://github.com/semantic-release/npm) and
|
|
40
|
-
[GitHub plugin](https://github.com/semantic-release/github). Distributed artifacts
|
|
41
|
-
declare MIT, have no install hooks, and expose npm provenance attestations.
|
|
42
|
-
The packages share four listed maintainers and each receives over 12 million
|
|
43
|
-
monthly npm downloads; published updates support the pinned Node runtime.
|
|
44
|
-
Registry signatures and attestations must be verified on changes. Public npm
|
|
45
|
-
metadata does not establish individual maintainer MFA or complete account
|
|
46
|
-
ownership history; provenance and the existing official namespace are the
|
|
47
|
-
available trust evidence.
|
|
48
|
-
|
|
49
|
-
The engine/plugin tree invokes Git and npm, reads/writes repository/package
|
|
50
|
-
files and contacts GitHub/npm. It runs with release authority only after the
|
|
51
|
-
protected merge. The complete installed tree remains subject to the blocking
|
|
52
|
-
audit; adoption does not authorize accepting an advisory. Bundled npm components
|
|
53
|
-
must be reviewed on disk, not just through root overrides. See
|
|
54
|
-
[release security](release-security.md).
|
|
55
|
-
|
|
56
|
-
Maintainer `titan-ron` owns updates, advisory review and removal. Replacing this
|
|
57
|
-
toolchain means changing release.config.mjs and the trusted release job; it does
|
|
58
|
-
not alter the library runtime. Use the previous explicit workflow only through
|
|
59
|
-
a reviewed change if upstream becomes unsuitable. Keep review evidence in PRs.
|
|
60
|
-
|
|
61
|
-
The Doppler CLI is separately installed and managed by the user. Rollup uses
|
|
62
|
-
platform-specific optional binaries; preserve clean Linux/macOS install checks.
|
|
63
|
-
The optional fsevents lock metadata can advertise an install script even when
|
|
64
|
-
its reviewed archive contains neither an install hook nor binding.gyp.
|
|
65
|
-
|
|
66
|
-
Run `npm ci`, `npm run audit`, `npm audit signatures`, and `npm run verify`.
|
|
67
|
-
Official GitHub actions use exact release tags under the repository publisher
|
|
68
|
-
policy; other remote actions require full SHAs.
|
package/docs/doppler.md
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
# Doppler references and CLI authentication
|
|
2
|
-
|
|
3
|
-
Doppler is resenv's only built-in cloud provider. After Nx or another loader
|
|
4
|
-
populates the environment, resenv fetches referenced values through HTTPS and
|
|
5
|
-
replaces them in memory before application startup. It resolves once per startup;
|
|
6
|
-
restart the application to fetch changed secrets. This mode does not execute
|
|
7
|
-
shell commands.
|
|
8
|
-
The canonical `--require @ciqol/resenv/resolve` preload infers Doppler from
|
|
9
|
-
`doppler://` values. The equivalent `--import` and `resenv run -- ...` do the
|
|
10
|
-
same. The library also infers Doppler from values; call `resolve()` without
|
|
11
|
-
a provider option. `resolve-doppler` and
|
|
12
|
-
`run --doppler` remain supported for compatibility.
|
|
13
|
-
|
|
14
|
-
## Local setup
|
|
15
|
-
|
|
16
|
-
After [installing resenv](../README.md#install) in your application project,
|
|
17
|
-
install the [official Doppler CLI](https://docs.doppler.com/docs/cli) and run
|
|
18
|
-
this from the application's directory:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
doppler login
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Doppler owns browser authorization, token persistence, login scopes and logout.
|
|
25
|
-
Use `doppler logout` to manage the CLI login. resenv never opens a browser,
|
|
26
|
-
prompts for login, issues or revokes tokens, or reads or writes the OS
|
|
27
|
-
credential store directly. There is no separate resenv login.
|
|
28
|
-
|
|
29
|
-
Existing Doppler users can reuse their login. resenv asks the CLI for the token
|
|
30
|
-
selected by its current working directory, so Doppler's directory-scoped
|
|
31
|
-
workplace identities continue to apply. See
|
|
32
|
-
[Doppler's scope guide](https://docs.doppler.com/docs/multiple-workplaces).
|
|
33
|
-
`doppler setup` is not required for resenv references: their project and config
|
|
34
|
-
are already explicit in each `doppler://` value. Nx or the caller remains
|
|
35
|
-
responsible for dotenv file loading.
|
|
36
|
-
|
|
37
|
-
### Platforms and installation locations
|
|
38
|
-
|
|
39
|
-
The CLI handles its own credential storage on macOS, Linux and Windows. resenv
|
|
40
|
-
does not require `secret-tool`, a separate keyring package or native Node addons.
|
|
41
|
-
It discovers the CLI in these standard locations:
|
|
42
|
-
|
|
43
|
-
| Platform | Locations, in lookup order |
|
|
44
|
-
| --- | --- |
|
|
45
|
-
| macOS / Linux | `/opt/homebrew/bin/doppler`, `/usr/local/bin/doppler`, `/usr/bin/doppler`, `~/.local/bin/doppler`, `~/bin/doppler` |
|
|
46
|
-
| Windows | `~/AppData/Local/Microsoft/WinGet/Links/doppler.exe`, `~/scoop/apps/doppler/current/doppler.exe` |
|
|
47
|
-
|
|
48
|
-
Here `~` is the OS user's home directory. Windows paths cover default per-user
|
|
49
|
-
WinGet and Scoop installations. Custom and system-wide Windows installations
|
|
50
|
-
outside these locations need an explicit `DOPPLER_TOKEN`. WSL uses the Linux
|
|
51
|
-
installation and login within WSL. The runtime deliberately ignores the
|
|
52
|
-
application's `PATH` so a repository-local executable cannot replace the
|
|
53
|
-
credential helper.
|
|
54
|
-
|
|
55
|
-
Windows discovery is covered with injected process tests; a native Windows
|
|
56
|
-
end-to-end run is not yet verified. Automated checks never use a developer's
|
|
57
|
-
Doppler login or OS credential store.
|
|
58
|
-
|
|
59
|
-
### Migration from resenv-managed login
|
|
60
|
-
|
|
61
|
-
`resenv login` and `resenv logout` have been removed. Run `doppler login` to
|
|
62
|
-
establish the CLI identity, then start the application normally. Earlier resenv
|
|
63
|
-
credentials stored under service `ciqol.envref.doppler`, account `default`, are
|
|
64
|
-
ignored and are not migrated or deleted automatically. If you used that flow,
|
|
65
|
-
remove the obsolete entry through your OS credential manager and revoke the
|
|
66
|
-
obsolete token in Doppler when it is no longer needed.
|
|
67
|
-
|
|
68
|
-
## Declare a reference
|
|
69
|
-
|
|
70
|
-
Put references in the dotenv file Nx already selects, such as `.env.serve`:
|
|
71
|
-
|
|
72
|
-
```dotenv
|
|
73
|
-
API_TOKEN=doppler://my-project/dev/API_TOKEN
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
This is **resenv's own syntax**, not an official Doppler URI standard or
|
|
77
|
-
SecretSpec's provider URI. All three fields are required: project, config and
|
|
78
|
-
secret name. Project/config slugs must be lowercase letters, digits, `_` or
|
|
79
|
-
`-`. Secret names can use Doppler's permissive punctuation; percent encoding
|
|
80
|
-
is accepted for a secret name, such as `payments%2Fapi.key`. Query strings,
|
|
81
|
-
fragments, credentials, ports and executable expressions are rejected.
|
|
82
|
-
|
|
83
|
-
For an Nx Node target, put the preload on the application process:
|
|
84
|
-
|
|
85
|
-
```json
|
|
86
|
-
"runtimeArgs": ["--require", "@ciqol/resenv/resolve"]
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
For an Nx command target, use `resenv run -- node app.mjs` inside the
|
|
90
|
-
target. Preloading the outer Nx process would run before Nx loads target files.
|
|
91
|
-
resenv does not choose, read or rewrite dotenv files.
|
|
92
|
-
|
|
93
|
-
## Runtime credential lookup
|
|
94
|
-
|
|
95
|
-
Resolution checks these sources in order:
|
|
96
|
-
|
|
97
|
-
1. An explicitly supplied `DOPPLER_TOKEN`.
|
|
98
|
-
2. The current directory's existing Doppler CLI login, retrieved with the
|
|
99
|
-
documented `doppler configure get token --plain` operation.
|
|
100
|
-
|
|
101
|
-
resenv captures the token internally and fetches secrets through HTTPS; it does
|
|
102
|
-
not parse the CLI's private config format. The command uses a fixed executable,
|
|
103
|
-
separate arguments, `--no-check-version` and `--no-read-env`, with a restricted
|
|
104
|
-
environment. It inherits the application's working directory to preserve login
|
|
105
|
-
scopes. Lookup has a fifteen-second timeout and a 16 KiB output limit. Captured
|
|
106
|
-
output and helper errors are never forwarded to application logs.
|
|
107
|
-
|
|
108
|
-
If the CLI is missing, install it in a supported location and run `doppler login`,
|
|
109
|
-
or supply `DOPPLER_TOKEN`. A failed or empty CLI lookup reports that login is
|
|
110
|
-
required. An explicitly supplied invalid token, malformed CLI token, access
|
|
111
|
-
denial or network failure stops the operation without switching identities or
|
|
112
|
-
starting login.
|
|
113
|
-
|
|
114
|
-
In CI, containers and other unattended environments, supply a suitably scoped
|
|
115
|
-
`DOPPLER_TOKEN` through the runner's secret facility. No CLI installation or
|
|
116
|
-
local credential store is needed in that mode. Changing the CLI login affects
|
|
117
|
-
the next application startup; resenv does not keep a persistent token cache.
|
|
118
|
-
|
|
119
|
-
## Resolution and security boundaries
|
|
120
|
-
|
|
121
|
-
- Fetches only named secrets from the public retrieve-secret endpoint. Repeated
|
|
122
|
-
references share one request per startup; values are not cached on disk.
|
|
123
|
-
- Requires the computed value. Restricted, missing, null and invalid values
|
|
124
|
-
fail startup; resenv never substitutes a raw value as a fallback.
|
|
125
|
-
- Keeps fetched output literal, including strings that start with `encrypted:`
|
|
126
|
-
or contain `$()`. Neither fetched nor original ciphertext is decrypted.
|
|
127
|
-
- Resolves everything before applying changes. A failure leaves the caller's
|
|
128
|
-
environment untouched. Existing command mode remains separately opt-in.
|
|
129
|
-
- Uses a fixed HTTPS origin, disables redirects, and has a ten-second timeout
|
|
130
|
-
per request. The synchronous preload uses a private Node worker with a
|
|
131
|
-
sixty-second overall limit. Up to four distinct lookups run concurrently;
|
|
132
|
-
duplicate references share one lookup. After a failure, no new lookups are
|
|
133
|
-
scheduled and active requests settle before failure is returned. Limits are
|
|
134
|
-
128 references, 64 KiB per value and
|
|
135
|
-
1 MiB for each response and the worker's captured output.
|
|
136
|
-
- Preloads use a child Node process to wait for asynchronous HTTPS while
|
|
137
|
-
retaining `--require` compatibility. It receives only references and an
|
|
138
|
-
explicit credential through stdin, with results returned through a private
|
|
139
|
-
pipe. No Doppler CLI is required when `DOPPLER_TOKEN` is supplied.
|
|
140
|
-
- Diagnostics show variable names and error codes, never tokens, provider
|
|
141
|
-
response bodies, CLI output or resolved values.
|
|
142
|
-
|
|
143
|
-
This removes shell evaluation from Doppler lookups. It does not isolate
|
|
144
|
-
untrusted repository code or agents that can access the same user's credential
|
|
145
|
-
store. Doppler account permissions remain the authorization boundary. CLI user
|
|
146
|
-
tokens inherit the user's privileges; a read-only service token can limit CI
|
|
147
|
-
to a specific config.
|
|
148
|
-
|
|
149
|
-
## Sources
|
|
150
|
-
|
|
151
|
-
- [Doppler CLI installation and authentication](https://docs.doppler.com/docs/cli)
|
|
152
|
-
- [Directory-scoped workplace logins](https://docs.doppler.com/docs/multiple-workplaces)
|
|
153
|
-
- [Retrieve a secret](https://docs.doppler.com/reference/secrets-get)
|
|
154
|
-
- [API authentication](https://docs.doppler.com/reference/api)
|
|
155
|
-
- [Retrieve the CLI token](https://docs.doppler.com/docs/cli#fetch-cli-token-from-your-local-environment)
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Maintainer guide
|
|
2
|
-
|
|
3
|
-
Start with [AGENTS.md](https://github.com/ciqol/resenv/blob/main/AGENTS.md) for repository policy and
|
|
4
|
-
[CONTRIBUTING.md](../CONTRIBUTING.md) for setup and verification. Work in an
|
|
5
|
-
isolated task worktree on a `titan/*` branch. Authenticate as `titan-ron` for
|
|
6
|
-
[ciqol/resenv](https://github.com/ciqol/resenv); `main` is the default and sole
|
|
7
|
-
release branch.
|
|
8
|
-
|
|
9
|
-
Inspect current Git status, branches, push remote and recent commits before
|
|
10
|
-
editing. Read live GitHub checks, releases and npm metadata before release
|
|
11
|
-
work; old chat messages or check results are not authoritative. Never copy
|
|
12
|
-
credentials between sessions.
|
|
13
|
-
|
|
14
|
-
| Guide | Maintained information |
|
|
15
|
-
| --- | --- |
|
|
16
|
-
| [README](../README.md) | Application installation, API and CLI usage |
|
|
17
|
-
| [Doppler](doppler.md) | CLI authentication, lookup, migration and platform limits |
|
|
18
|
-
| [Build](build.md) | Module formats, declarations, archive and CI contract |
|
|
19
|
-
| [Dependencies](dependencies.md) | Tool rationale, installation and update policy |
|
|
20
|
-
| [Releasing](releasing.md) | PR approval, main releases and recovery |
|
|
21
|
-
| [Release security](release-security.md) | Dependency audit and release-tool review deadline |
|
|
22
|
-
| [Security](../SECURITY.md) | Trust boundaries and private vulnerability reporting |
|
|
23
|
-
|
|
24
|
-
## Code map
|
|
25
|
-
|
|
26
|
-
| Path | Responsibility |
|
|
27
|
-
| --- | --- |
|
|
28
|
-
| `src/index.ts` | Resolution API and atomic environment replacement |
|
|
29
|
-
| `src/preload.ts`, `src/resolve*.ts` | Startup integration and shared preload state |
|
|
30
|
-
| `src/doppler/` | References, HTTPS, concurrency and CLI credential lookup |
|
|
31
|
-
| `src/commands.ts` | Explicit shell substitution and process limits |
|
|
32
|
-
| `bin/resenv.ts` | Child-process CLI |
|
|
33
|
-
| `rollup.config.mjs`, `scripts/build.mjs` | CJS implementation, ESM facades, types and manifest |
|
|
34
|
-
| `release.config.mjs` | Standard semantic-release plugins and main/0.x policy |
|
|
35
|
-
| `scripts/release.mjs` | One-time 0.1.0 bootstrap, then the standard release command |
|
|
36
|
-
| `scripts/verify-release.mjs` | Trusted event, review expiry, 0.x and final package checks |
|
|
37
|
-
| `.github/workflows/ci.yml` | Checks, one compiled build and publication on main merges |
|
|
38
|
-
|
|
39
|
-
Keep docs focused on current contracts, decisions and procedures. Put per-run
|
|
40
|
-
test results, benchmarks, audit snapshots and session history in PRs or CI.
|
package/docs/release-security.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Release-tool security
|
|
2
|
-
|
|
3
|
-
Maintainer: `titan-ron`. The complete installed tree must pass
|
|
4
|
-
`npm audit --audit-level=moderate`; there are no advisory exceptions. The
|
|
5
|
-
[review deadline](security-exceptions.json) remains **November 9, 2026 at
|
|
6
|
-
00:00 UTC** and is enforced before publication. Do not extend it or suppress
|
|
7
|
-
findings to unblock a release.
|
|
8
|
-
|
|
9
|
-
Standard semantic-release and the official npm/GitHub plugins replace the
|
|
10
|
-
standalone planner and staging controller. Their dependencies are now installed
|
|
11
|
-
and audited normally. The old peer-omission and module-blocking policy no longer
|
|
12
|
-
applies to tools explicitly selected for this pipeline. No release tool ships
|
|
13
|
-
to package consumers.
|
|
14
|
-
|
|
15
|
-
## Publishing authority
|
|
16
|
-
|
|
17
|
-
PR merge is approval. Branch rules require the real CI/CodeQL checks and prevent
|
|
18
|
-
direct pushes, force pushes, deletion and bypass. PRs and manual dispatches
|
|
19
|
-
cannot publish. Only main pushes may enter the `release` environment, with
|
|
20
|
-
contents write and OIDC permissions. There are no npm tokens or additional
|
|
21
|
-
reviewers. The release token is exposed only to the release step, and checkout
|
|
22
|
-
does not persist credentials.
|
|
23
|
-
|
|
24
|
-
The job consumes compiled output tested by CI. The npm plugin changes release
|
|
25
|
-
metadata and packs it; the verification hook tests the final package. Publishing
|
|
26
|
-
uses the prepared directory, whose manifest has no package lifecycle scripts.
|
|
27
|
-
The source is not rebuilt. The bootstrap publishes its checked tarball directly.
|
|
28
|
-
GitHub issue/PR comments and labels are disabled in the GitHub plugin so it
|
|
29
|
-
needs no issue or pull-request write permission.
|
|
30
|
-
|
|
31
|
-
## Dependency review
|
|
32
|
-
|
|
33
|
-
Review actual installed artifacts, including npm's bundled dependencies.
|
|
34
|
-
Overrides are not evidence that bundled files changed: inspect their manifests
|
|
35
|
-
on disk. A failing dependency audit blocks merge and release; it is not a
|
|
36
|
-
non-blocking report. Do not broaden exceptions or silently substitute an
|
|
37
|
-
unreviewed npm version.
|
|
38
|
-
|
|
39
|
-
### Temporary npm bundle repair
|
|
40
|
-
|
|
41
|
-
npm 11.21.1 bundles vulnerable `undici` and `ip-address` files that npm overrides
|
|
42
|
-
do not replace. Until an upstream npm release includes the fixes, the reviewed
|
|
43
|
-
root `postinstall` hook replaces those two directories with the exact registry
|
|
44
|
-
packages `undici@6.29.1` and `ip-address@10.7.5`, installed under development-only
|
|
45
|
-
aliases. Their integrity hashes are pinned in the lockfile, which also records
|
|
46
|
-
the repaired bundle versions. This is an actual file replacement, not an audit
|
|
47
|
-
exception or a metadata-only override.
|
|
48
|
-
|
|
49
|
-
`npm run audit` first compares every installed bundle file with the corresponding
|
|
50
|
-
locked upstream package. Missing, extra or modified files fail the check. The
|
|
51
|
-
repair accepts only the reviewed npm and dependency versions and rejects patch
|
|
52
|
-
packages with runtime dependencies. It does not fetch code or use credentials.
|
|
53
|
-
Registry signatures verify the upstream packages; they do not attest the locally
|
|
54
|
-
repaired npm bundle as an npm-maintained distribution.
|
|
55
|
-
|
|
56
|
-
Remove the hook, repair script/tests, aliases and repaired lock entries together
|
|
57
|
-
when upgrading to an npm release containing both fixes. Regenerate the lockfile
|
|
58
|
-
and validate a clean install, on-disk versions, audit, signatures and package
|
|
59
|
-
checks before removing the repair. The existing review deadline still applies.
|
|
60
|
-
|
|
61
|
-
Use pinned versions and the lockfile. Validate normal installs, registry
|
|
62
|
-
signatures/attestations, the full audit and the package tests. See
|
|
63
|
-
[dependencies](dependencies.md) for tool choices. Record dated findings and
|
|
64
|
-
per-run evidence in the PR, not in this document.
|
package/docs/releasing.md
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# Releases
|
|
2
|
-
|
|
3
|
-
**Merge the PR to `main`; CI publishes the release.** There is no separate
|
|
4
|
-
approval button, npm staging queue or Finalize job. Manual workflow dispatch
|
|
5
|
-
runs checks only. The default branch requires a PR, current passing checks,
|
|
6
|
-
resolved review threads and squash merging, with no bypass actors. The sole
|
|
7
|
-
maintainer approves by merging; no second reviewer is required.
|
|
8
|
-
|
|
9
|
-
## Normal flow
|
|
10
|
-
|
|
11
|
-
CI audits dependencies, checks signatures, lint, types and coverage, builds
|
|
12
|
-
once, and tests the packed build across Linux Node 20/22/24 and macOS Node 24.
|
|
13
|
-
After a merge, the protected release job downloads that build and invokes
|
|
14
|
-
standard semantic-release. The official npm plugin prepares the release
|
|
15
|
-
version and archive; consumer checks run again on the final package. The
|
|
16
|
-
official npm and GitHub plugins publish to npm `latest` and create the GitHub
|
|
17
|
-
release. No source is rebuilt during release.
|
|
18
|
-
|
|
19
|
-
Conventional Commits determine releases: fixes and performance changes bump
|
|
20
|
-
patch, features bump minor, and breaking changes bump minor while the package
|
|
21
|
-
remains below 1.0. Docs and maintenance commits alone do not trigger a release.
|
|
22
|
-
Squash PR titles must follow that convention. `0.x.x` denotes initial
|
|
23
|
-
development, not a SemVer prerelease; published versions have no beta suffix.
|
|
24
|
-
A guard blocks 1.0 until that transition is reviewed explicitly.
|
|
25
|
-
|
|
26
|
-
## Initial 0.1.0 release
|
|
27
|
-
|
|
28
|
-
semantic-release starts at 1.0.0 when no regular release tag exists. To preserve
|
|
29
|
-
0.x numbering without a fake tag, the first enabled main release publishes the
|
|
30
|
-
tested `0.1.0` archive through npm OIDC and records its real tag and GitHub
|
|
31
|
-
release. Thereafter the normal engine uses that baseline. Existing beta tags
|
|
32
|
-
and npm versions remain historical; the `beta` channel is not updated.
|
|
33
|
-
|
|
34
|
-
## Setup
|
|
35
|
-
|
|
36
|
-
- Default/release branch: `main`, protected by PRs and the actual CI/CodeQL checks.
|
|
37
|
-
- npm trusted publisher: `ciqol/resenv`, `ci.yml`, environment `release`, with
|
|
38
|
-
**direct publish** permission. Stage-only permission cannot run this flow.
|
|
39
|
-
- GitHub environment `release`: allow only `main`, with no required reviewers.
|
|
40
|
-
- `RELEASE_ENABLED=true` only after protection, the npm publisher and dependency
|
|
41
|
-
audit are verified. The maintainer manages the npm setting.
|
|
42
|
-
|
|
43
|
-
On npmjs.com, open **@ciqol/resenv → Settings → Trusted publishing** and
|
|
44
|
-
configure its GitHub Actions publisher with these exact values:
|
|
45
|
-
|
|
46
|
-
| Field | Value |
|
|
47
|
-
| --- | --- |
|
|
48
|
-
| Organization or user | `ciqol` |
|
|
49
|
-
| Repository | `resenv` |
|
|
50
|
-
| Workflow filename | `ci.yml` (filename only) |
|
|
51
|
-
| Environment name | `release` |
|
|
52
|
-
| Allow npm publish | Enabled |
|
|
53
|
-
| Allow npm dist-tag | Not needed for this single-branch release flow |
|
|
54
|
-
|
|
55
|
-
Save the configuration and complete npm's confirmation if prompted. Staging is
|
|
56
|
-
always allowed; enabling direct publishing is the required change. The branch
|
|
57
|
-
restriction lives in GitHub's `release` environment, which already allows only
|
|
58
|
-
`main`. Keep account 2FA and the existing token restrictions; no npm token is
|
|
59
|
-
needed. See [npm's trusted-publishing guide](https://docs.npmjs.com/trusted-publishers/).
|
|
60
|
-
|
|
61
|
-
Never publish from a developer machine, configure a permanent npm publishing
|
|
62
|
-
token, or request local npm login. Local `npm run release:check` is read-only
|
|
63
|
-
with respect to publication. Only the trusted main push can pass the release
|
|
64
|
-
guard. A merge does not waive a failing audit or the security review expiry.
|
|
65
|
-
|
|
66
|
-
## Failures
|
|
67
|
-
|
|
68
|
-
Inspect the failed run, npm version and GitHub tag before retrying. The standard
|
|
69
|
-
engine creates its tag before calling publishers; a failed publication may
|
|
70
|
-
therefore leave a tag or partial release. Rerunning is not a general repair for
|
|
71
|
-
that state. Recover the intended version using its original source and archive
|
|
72
|
-
after maintainer review; do not retag different code or silently replace a
|
|
73
|
-
published version. The initial bootstrap creates its tag after npm succeeds;
|
|
74
|
-
if GitHub recording fails, recover that published baseline before another run.
|
|
75
|
-
|
|
76
|
-
No workflow automatically deletes tags, releases or npm versions. Existing
|
|
77
|
-
beta versions without matching GitHub releases need separate recovery from
|
|
78
|
-
their original evidence. See [release security](release-security.md).
|