@ciqol/resenv 0.1.0-beta.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/CONTRIBUTING.md +189 -0
- package/LICENSE +21 -0
- package/README.md +243 -0
- package/SECURITY.md +74 -0
- package/assert-safe-diagnostics.cjs +15 -0
- package/bin/resenv.cjs +91 -0
- package/bin/resenv.mjs +1 -0
- package/commands.cjs +85 -0
- package/docs/build.md +136 -0
- package/docs/dependencies.md +505 -0
- package/docs/doppler.md +146 -0
- package/docs/maintainer-handoff.md +112 -0
- package/docs/maturity.md +61 -0
- package/docs/public-readiness.md +138 -0
- package/docs/release-security.md +134 -0
- package/docs/releasing.md +143 -0
- package/docs/security-exceptions.json +139 -0
- package/docs/security-performance-review.md +150 -0
- package/docs/validation.md +700 -0
- package/doppler/auth.cjs +125 -0
- package/doppler/bridge.cjs +66 -0
- package/doppler/http.cjs +77 -0
- package/doppler/references.cjs +28 -0
- package/doppler/resolve.cjs +58 -0
- package/doppler/system.cjs +99 -0
- package/doppler-worker.cjs +28 -0
- package/doppler-worker.mjs +1 -0
- package/errors.cjs +12 -0
- package/index.cjs +88 -0
- package/index.d.cts +1 -0
- package/index.d.mts +1 -0
- package/index.mjs +1 -0
- package/package.json +89 -0
- package/preload.cjs +31 -0
- package/resolve-commands.cjs +5 -0
- package/resolve-commands.d.cts +1 -0
- package/resolve-commands.d.mts +1 -0
- package/resolve-commands.mjs +1 -0
- package/resolve-doppler.cjs +4 -0
- package/resolve-doppler.d.cts +1 -0
- package/resolve-doppler.d.mts +1 -0
- package/resolve-doppler.mjs +1 -0
- package/resolve.cjs +5 -0
- package/resolve.d.cts +1 -0
- package/resolve.d.mts +1 -0
- package/resolve.mjs +1 -0
- package/types/bin/resenv.d.ts +2 -0
- package/types/src/assert-safe-diagnostics.d.ts +1 -0
- package/types/src/commands.d.ts +4 -0
- package/types/src/doppler/auth.d.ts +19 -0
- package/types/src/doppler/bridge.d.ts +4 -0
- package/types/src/doppler/http.d.ts +9 -0
- package/types/src/doppler/references.d.ts +9 -0
- package/types/src/doppler/resolve.d.ts +9 -0
- package/types/src/doppler/system.d.ts +24 -0
- package/types/src/doppler-worker.d.ts +1 -0
- package/types/src/errors.d.ts +5 -0
- package/types/src/index.d.ts +7 -0
- package/types/src/preload.d.ts +4 -0
- package/types/src/resolve-commands.d.ts +1 -0
- package/types/src/resolve-doppler.d.ts +1 -0
- package/types/src/resolve.d.ts +1 -0
- package/types/src/types.d.ts +9 -0
- package/types/src/values.d.ts +5 -0
- package/values.cjs +20 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expires": "2026-11-09T00:00:00.000Z",
|
|
3
|
+
"owner": "titan-ron",
|
|
4
|
+
"scope": "Release planning only; runtime audit has no exceptions.",
|
|
5
|
+
"exceptions": [
|
|
6
|
+
{
|
|
7
|
+
"advisory": "https://github.com/advisories/GHSA-q2hr-2g5m-vwhr",
|
|
8
|
+
"package": "brace-expansion",
|
|
9
|
+
"versions": [
|
|
10
|
+
"5.0.9"
|
|
11
|
+
],
|
|
12
|
+
"nodes": [
|
|
13
|
+
"node_modules/npm/node_modules/brace-expansion"
|
|
14
|
+
],
|
|
15
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"advisory": "https://github.com/advisories/GHSA-qhr7-859c-m2p7",
|
|
19
|
+
"package": "brace-expansion",
|
|
20
|
+
"versions": [
|
|
21
|
+
"5.0.9"
|
|
22
|
+
],
|
|
23
|
+
"nodes": [
|
|
24
|
+
"node_modules/npm/node_modules/brace-expansion"
|
|
25
|
+
],
|
|
26
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"advisory": "https://github.com/advisories/GHSA-6j4f-fj2g-mc7p",
|
|
30
|
+
"package": "brace-expansion",
|
|
31
|
+
"versions": [
|
|
32
|
+
"5.0.9"
|
|
33
|
+
],
|
|
34
|
+
"nodes": [
|
|
35
|
+
"node_modules/npm/node_modules/brace-expansion"
|
|
36
|
+
],
|
|
37
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"advisory": "https://github.com/advisories/GHSA-vfj7-8cjw-p6xm",
|
|
41
|
+
"package": "braces",
|
|
42
|
+
"versions": [
|
|
43
|
+
"3.0.3"
|
|
44
|
+
],
|
|
45
|
+
"nodes": [
|
|
46
|
+
"node_modules/braces"
|
|
47
|
+
],
|
|
48
|
+
"reason": "The planner blocks every braces callable and only uses micromatch matching, which delegates to picomatch."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"advisory": "https://github.com/advisories/GHSA-ch52-4w7c-c8xp",
|
|
52
|
+
"package": "http-cache-semantics",
|
|
53
|
+
"versions": [
|
|
54
|
+
"4.2.0"
|
|
55
|
+
],
|
|
56
|
+
"nodes": [
|
|
57
|
+
"node_modules/npm/node_modules/http-cache-semantics"
|
|
58
|
+
],
|
|
59
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"advisory": "https://github.com/advisories/GHSA-rpw4-54j3-4h4q",
|
|
63
|
+
"package": "ip-address",
|
|
64
|
+
"versions": [
|
|
65
|
+
"10.5.0"
|
|
66
|
+
],
|
|
67
|
+
"nodes": [
|
|
68
|
+
"node_modules/npm/node_modules/ip-address"
|
|
69
|
+
],
|
|
70
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"advisory": "https://github.com/advisories/GHSA-2vr4-cq9g-pvrc",
|
|
74
|
+
"package": "ip-address",
|
|
75
|
+
"versions": [
|
|
76
|
+
"10.5.0"
|
|
77
|
+
],
|
|
78
|
+
"nodes": [
|
|
79
|
+
"node_modules/npm/node_modules/ip-address"
|
|
80
|
+
],
|
|
81
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"advisory": "https://github.com/advisories/GHSA-j6r3-76f7-8jcv",
|
|
85
|
+
"package": "ip-address",
|
|
86
|
+
"versions": [
|
|
87
|
+
"10.5.0"
|
|
88
|
+
],
|
|
89
|
+
"nodes": [
|
|
90
|
+
"node_modules/npm/node_modules/ip-address"
|
|
91
|
+
],
|
|
92
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"advisory": "https://github.com/advisories/GHSA-h3mg-xc3c-68pw",
|
|
96
|
+
"package": "ip-address",
|
|
97
|
+
"versions": [
|
|
98
|
+
"10.5.0"
|
|
99
|
+
],
|
|
100
|
+
"nodes": [
|
|
101
|
+
"node_modules/npm/node_modules/ip-address"
|
|
102
|
+
],
|
|
103
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"advisory": "https://github.com/advisories/GHSA-rj75-hqrm-r3gf",
|
|
107
|
+
"package": "postcss-selector-parser",
|
|
108
|
+
"versions": [
|
|
109
|
+
"7.1.4"
|
|
110
|
+
],
|
|
111
|
+
"nodes": [
|
|
112
|
+
"node_modules/npm/node_modules/postcss-selector-parser"
|
|
113
|
+
],
|
|
114
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"advisory": "https://github.com/advisories/GHSA-3wwx-pv8p-q78v",
|
|
118
|
+
"package": "undici",
|
|
119
|
+
"versions": [
|
|
120
|
+
"6.28.0"
|
|
121
|
+
],
|
|
122
|
+
"nodes": [
|
|
123
|
+
"node_modules/npm/node_modules/undici"
|
|
124
|
+
],
|
|
125
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"advisory": "https://github.com/advisories/GHSA-rfgv-xxqx-mfg5",
|
|
129
|
+
"package": "undici",
|
|
130
|
+
"versions": [
|
|
131
|
+
"6.28.0"
|
|
132
|
+
],
|
|
133
|
+
"nodes": [
|
|
134
|
+
"node_modules/npm/node_modules/undici"
|
|
135
|
+
],
|
|
136
|
+
"reason": "Bundled inside npm for the unselected @semantic-release/npm plugin. The planner blocks loading that plugin, the GitHub plugin and bundled npm; the publisher does not install release dependencies."
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Security and performance review
|
|
2
|
+
|
|
3
|
+
Historical review: the October 12 beta removes dotenvx decryption and its entire
|
|
4
|
+
runtime dependency tree. Earlier cryptography and ciphertext findings below
|
|
5
|
+
apply to the prototype. Current behavior is in [Security](../SECURITY.md).
|
|
6
|
+
|
|
7
|
+
## Release preparation update - 2026-10-10
|
|
8
|
+
|
|
9
|
+
The current release pipeline and launch state are documented in [releasing](releasing.md).
|
|
10
|
+
The release-tool review and expiring advisory policy are in [release security](release-security.md).
|
|
11
|
+
Earlier dated entries below remain historical evidence and are superseded where
|
|
12
|
+
the current release guide describes a different state.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
Reviewed on 2026-10-06 against the private 0.1.0 candidate, starting at
|
|
16
|
+
`b50fa9b`. This is a source review with targeted reproductions, regression tests
|
|
17
|
+
and measurements. It is not an independent audit or a security certification.
|
|
18
|
+
|
|
19
|
+
A later change on the same day migrates the implementation and CLI to strict
|
|
20
|
+
TypeScript. The findings below describe the reviewed baseline and fixes; see
|
|
21
|
+
[the current build contract](build.md) and [validation](validation.md) for the
|
|
22
|
+
generated declarations and implementation checks that supersede the earlier
|
|
23
|
+
declaration-only setup.
|
|
24
|
+
|
|
25
|
+
## Findings and changes
|
|
26
|
+
|
|
27
|
+
| Priority | Finding reproduced | Change and regression coverage |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| P1 | Node's `child_process` debug category printed dummy credentials from subprocess environment values and private worker stdin. | Reject resenv subprocess/helper operations before spawning when that native debug category is enabled. Cover wildcards, case, cached debug state and safe no-work preloads in [diagnostic tests](https://github.com/ciqol/resenv/blob/e57a8fe72ecf956fc99c661d40b1ca707bbcd172/test/diagnostics.test.mjs). |
|
|
30
|
+
| P1 | Combining automatic resolution modes could interpret a fetched secret as a shell expression on the second pass. | Share preload state across CJS/ESM, reject mixed modes and reject CLI resolution after a preload. Verify both preload orders and the CLI combination in [runtime tests](https://github.com/ciqol/resenv/blob/e57a8fe72ecf956fc99c661d40b1ca707bbcd172/test/doppler-runtime.test.mjs). |
|
|
31
|
+
| P2 | Invalid UTF-8 from the provider was silently converted to a different secret value; escaped lone surrogates were also accepted. | Decode JSON with fatal UTF-8 validation and reject malformed Unicode values. Cover both paths in [Doppler tests](https://github.com/ciqol/resenv/blob/e57a8fe72ecf956fc99c661d40b1ca707bbcd172/test/doppler.test.mjs). |
|
|
32
|
+
| P2 | A non-writable second property could fail after the first environment property had already changed. | Preflight all changed descriptors before committing; reject setters and Proxy targets. Preserve writable sealed records. Cover atomicity in [resolver tests](https://github.com/ciqol/resenv/blob/e57a8fe72ecf956fc99c661d40b1ca707bbcd172/test/resolver.test.mjs). |
|
|
33
|
+
| P2 | Unique Doppler lookups ran sequentially, making startup latency grow with each request. | Deduplicate references and allow four requests at a time. Stop scheduling after failure, await active requests and discard partial results. Deterministic tests check overlap, deduplication and failure behavior. |
|
|
34
|
+
| P2 | The generic in-place return type preserved an input's literal reference type after its value had changed. | Return `Environment`; add compile-time regression checks to both installed CJS and ESM consumers. |
|
|
35
|
+
|
|
36
|
+
Unexpected cleanup errors now produce safe errors instead of disappearing in
|
|
37
|
+
empty catch blocks. Known already-exited process groups remain harmless.
|
|
38
|
+
Credential-revocation failures retain a safe message without raw provider
|
|
39
|
+
details. Regression tests cover these cases with dummy values.
|
|
40
|
+
|
|
41
|
+
The debug guard uses Node's actual `debuglog().enabled` state. Clearing
|
|
42
|
+
`NODE_DEBUG` after Node initializes it is insufficient. Use `NODE_DEBUG=ciqol:resenv`
|
|
43
|
+
for variable names and outcome messages without values. See Node's
|
|
44
|
+
[debuglog documentation](https://nodejs.org/api/util.html#utildebuglogsection-callback).
|
|
45
|
+
|
|
46
|
+
## Reviewed boundaries
|
|
47
|
+
|
|
48
|
+
- Only original environment references are processed within a resolution call.
|
|
49
|
+
Fetched and decrypted output remains literal.
|
|
50
|
+
- Doppler requests use a fixed HTTPS origin, reject redirects and request only
|
|
51
|
+
named secrets. An explicit identity is not silently replaced after rejection.
|
|
52
|
+
- The synchronous worker receives references and an optional token over stdin.
|
|
53
|
+
Credential helpers receive a filtered environment and fixed executable paths.
|
|
54
|
+
Application secrets, loader options and a repository's PATH are not forwarded
|
|
55
|
+
to those helpers.
|
|
56
|
+
- Requests have a ten-second deadline and a 1 MiB response limit. A resolution
|
|
57
|
+
allows at most 128 references, with a 64 KiB limit per cloud value. The worker
|
|
58
|
+
has a 60-second deadline and 1 MiB captured-output limit.
|
|
59
|
+
- Shell execution requires explicit opt-in. Startup never starts interactive
|
|
60
|
+
login automatically; login rejects CI and noninteractive use.
|
|
61
|
+
- Plain environments avoid subprocesses, credential discovery and loading the
|
|
62
|
+
cryptography dependency. Runtime dependency versions are unchanged.
|
|
63
|
+
|
|
64
|
+
These boundaries do not isolate secrets from the application, a debugger or
|
|
65
|
+
other code running as the same user. Commands execute with that user's access,
|
|
66
|
+
and their external effects cannot be rolled back. Configure one resolver per
|
|
67
|
+
launch; repeated manual calls or a separately installed child-process preload
|
|
68
|
+
can reinterpret values. See [SECURITY.md](../SECURITY.md).
|
|
69
|
+
|
|
70
|
+
## Performance measurements
|
|
71
|
+
|
|
72
|
+
Run `npm run bench` after building. The benchmark uses dummy values and a mocked
|
|
73
|
+
provider, with no real credentials or network requests. Measurements below use
|
|
74
|
+
Node 24.19.0 on macOS arm64; they are observations, not CI timing thresholds.
|
|
75
|
+
|
|
76
|
+
| Measurement | Before | After |
|
|
77
|
+
| --- | ---: | ---: |
|
|
78
|
+
| 16 references, eight unique requests, 40 ms simulated latency per request; median of five runs | 332.069 ms | 81.705 ms |
|
|
79
|
+
| Peak concurrent provider requests | 1 | 4 |
|
|
80
|
+
| No-work library call with 200 plain variables; median of 5,000 calls | 0.047 ms | 0.045 ms |
|
|
81
|
+
|
|
82
|
+
The mocked lookup case is about 4.1 times faster. Real Doppler latency, rate
|
|
83
|
+
limits and credential-store latency may differ; four is a conservative client
|
|
84
|
+
limit, not a published provider concurrency allowance.
|
|
85
|
+
|
|
86
|
+
The final fresh-process measurements interleave baseline, CJS preload and ESM
|
|
87
|
+
preload runs. Each reports the median of 20 samples after discarding three
|
|
88
|
+
warmup samples; disk caches remain warm.
|
|
89
|
+
|
|
90
|
+
| Final startup measurement | Median |
|
|
91
|
+
| --- | ---: |
|
|
92
|
+
| Node alone | 46.427 ms |
|
|
93
|
+
| Node with `--require @ciqol/resenv/resolve` and no references | 52.177 ms |
|
|
94
|
+
| Node with `--import @ciqol/resenv/resolve` and no references | 50.722 ms |
|
|
95
|
+
|
|
96
|
+
The observed extra startup cost was about 4-6 ms. Scheduling and filesystem
|
|
97
|
+
noise affect these small measurements; no startup speedup is claimed.
|
|
98
|
+
|
|
99
|
+
## Standards applied
|
|
100
|
+
|
|
101
|
+
The requested TypeScript authoring, library-build and style standards were
|
|
102
|
+
applied to the existing `.mjs` project and its public declarations:
|
|
103
|
+
|
|
104
|
+
- Public option objects use type aliases and readonly properties. `Environment`
|
|
105
|
+
remains mutable because in-place resolution writes it.
|
|
106
|
+
- ESLint checks runtime/build JavaScript and declarations. Rules cover undefined
|
|
107
|
+
names, empty handlers, parameter count, catch naming and the selected public
|
|
108
|
+
TypeScript conventions. Existing compact JavaScript formatting is preserved.
|
|
109
|
+
- Declaration checks and installed `.cts`/`.mts` consumers use `strict` and
|
|
110
|
+
`noUncheckedIndexedAccess`. This checks the declaration contract, not the
|
|
111
|
+
`.mjs` implementation with TypeScript.
|
|
112
|
+
- Rollup still emits explicit CJS/ESM extensions with a shared implementation,
|
|
113
|
+
types-first conditional exports and external runtime dependencies. Clean
|
|
114
|
+
consumers verify the packed artifact without source-tree links or lint/build
|
|
115
|
+
tools installed as runtime dependencies.
|
|
116
|
+
- CI runs lint and declaration checks before building one archive for every
|
|
117
|
+
compatibility job. Actions are pinned, permissions are read-only and install
|
|
118
|
+
lifecycle scripts are disabled. Both manifests remain private by request.
|
|
119
|
+
|
|
120
|
+
The new development dependencies and their provenance limits are recorded in
|
|
121
|
+
[the dependency review](dependencies.md). No new runtime dependency was added.
|
|
122
|
+
|
|
123
|
+
## Validation and remaining work
|
|
124
|
+
|
|
125
|
+
- All 70 unit/process tests passed locally on Node 20.20.2, 22.22.3 and 24.19.0.
|
|
126
|
+
- The packed package passed 13 runtime checks and two typed consumers on Node
|
|
127
|
+
24. Lint and strict declaration checks passed.
|
|
128
|
+
- Nx 23.2.1 passed target dotenv loading, local/shell precedence, target
|
|
129
|
+
isolation and strict failures for command and Doppler modes. Tests used a
|
|
130
|
+
temporary workspace, dummy credentials and an existing Nx installation
|
|
131
|
+
read-only; consumer files were not changed.
|
|
132
|
+
- npm reported zero known vulnerabilities, 103 verified registry signatures
|
|
133
|
+
and 37 verified attestations in the installed development tree. Advisory and
|
|
134
|
+
signature checks do not rule out unknown vulnerabilities.
|
|
135
|
+
- [Hosted CI](https://github.com/ciqol/resenv/actions/runs/37462966577) passed for
|
|
136
|
+
`e57a8fe`: one build and four compatibility jobs on Linux (Node 20, 22 and 24)
|
|
137
|
+
and macOS (Node 24). Each job passed all 70 tests, 13 installed runtime checks
|
|
138
|
+
and two typed consumers against the same archive. The Linux build verified
|
|
139
|
+
103 registry signatures and 38 attestations with zero known vulnerabilities.
|
|
140
|
+
Counts apply to each platform's installed tree.
|
|
141
|
+
- Workflow structure and documentation links passed local checks. Existing
|
|
142
|
+
distributed archives retained their original SHA-256 hashes. The final
|
|
143
|
+
documentation update records the tested commit; it does not change runtime code.
|
|
144
|
+
|
|
145
|
+
Before public release, settle the license and whether to retain the older
|
|
146
|
+
dotenvx decryption feature. The fresh native browser-login flow and live Linux
|
|
147
|
+
keyring integration still need verification. Windows native login/storage is
|
|
148
|
+
not implemented. Repository reporting/protection and npm publishing setup are
|
|
149
|
+
also outstanding in [the release plan](releasing.md). The repository remains
|
|
150
|
+
private and unpublished, with PR creation on hold.
|