@ciqol/resenv 0.1.0-beta.1 → 0.1.0
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 +41 -19
- package/README.md +36 -20
- package/SECURITY.md +20 -20
- package/bin/resenv.cjs +21 -23
- package/docs/build.md +29 -26
- package/docs/dependencies.md +65 -502
- package/docs/doppler.md +69 -60
- package/docs/maintainer-handoff.md +30 -102
- package/docs/release-security.md +64 -134
- package/docs/releasing.md +72 -137
- package/docs/security-exceptions.json +2 -135
- package/doppler/auth.cjs +4 -110
- package/doppler/http.cjs +3 -8
- package/doppler/system.cjs +26 -75
- package/package.json +2 -2
- package/types/src/doppler/auth.d.ts +2 -17
- package/types/src/doppler/http.d.ts +1 -3
- package/types/src/doppler/system.d.ts +3 -8
- package/docs/maturity.md +0 -61
- package/docs/public-readiness.md +0 -138
- package/docs/security-performance-review.md +0 -150
- package/docs/validation.md +0 -700
package/CONTRIBUTING.md
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
# Contributing
|
|
2
2
|
|
|
3
3
|
Starting a new session? Read the [maintainer handoff](docs/maintainer-handoff.md)
|
|
4
|
-
and [repository instructions](https://github.com/ciqol/resenv/blob/
|
|
4
|
+
and [repository instructions](https://github.com/ciqol/resenv/blob/main/AGENTS.md) before editing or releasing.
|
|
5
5
|
|
|
6
6
|
The [README](README.md) covers using resenv in an application. This guide covers
|
|
7
7
|
changing resenv itself and verifying those changes.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
the exact archive through npm OIDC for maintainer approval. See
|
|
15
|
-
[releasing](docs/releasing.md) and the bounded [release-tool review](docs/release-security.md).
|
|
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).
|
|
16
14
|
The source uses the [MIT license](LICENSE), copyright ciqol contributors.
|
|
17
15
|
|
|
18
16
|
## Local development
|
|
@@ -25,6 +23,14 @@ npm ci
|
|
|
25
23
|
npm run verify
|
|
26
24
|
```
|
|
27
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
|
+
|
|
28
34
|
`npm run verify` is the complete local check: lint, strict source/spec type
|
|
29
35
|
checks, build, unit/process tests and installed-package checks. To build without
|
|
30
36
|
running the checks, use `npm run build`.
|
|
@@ -60,14 +66,27 @@ shipping them in JavaScript or declarations. Do not maintain separate handwritte
|
|
|
60
66
|
```sh
|
|
61
67
|
npm run test:unit # colocated Vitest specs, no build required
|
|
62
68
|
npm run test:watch # watch unit specs while editing
|
|
63
|
-
npm run test:coverage # source unit coverage, text and
|
|
69
|
+
npm run test:coverage # source unit coverage, text, lcov and Cobertura output
|
|
64
70
|
npm run test:integration # process checks, requires a build
|
|
65
71
|
```
|
|
66
72
|
|
|
67
73
|
`npm test` runs unit and process tests. Mock or inject provider calls, credential
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
lookup and process control in unit tests. Keep checks that spawn actual commands
|
|
75
|
+
or temporary applications in `test/`. The unit coverage
|
|
70
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.
|
|
71
90
|
|
|
72
91
|
Use normal npm lifecycle behavior locally and in CI. Review install hooks,
|
|
73
92
|
including implicit native builds, when changing dependencies; record any
|
|
@@ -87,6 +106,8 @@ Pass an existing archive to test the same build CI uses:
|
|
|
87
106
|
`npm run test:package -- /absolute/path/to/package.tgz`. For a final CI candidate,
|
|
88
107
|
also pass its `release.json` as the second argument. The supplied package's
|
|
89
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.
|
|
90
111
|
`npm run verify` runs lint, typecheck, build and tests; `npm run release:check`
|
|
91
112
|
also previews the package contents. Neither publishes or creates a tag.
|
|
92
113
|
|
|
@@ -109,7 +130,7 @@ npm run pack:local
|
|
|
109
130
|
Install the resulting archive from the application's directory:
|
|
110
131
|
|
|
111
132
|
```sh
|
|
112
|
-
npm install --save-exact /absolute/path/to/ciqol-resenv-0.1.0
|
|
133
|
+
npm install --save-exact /absolute/path/to/ciqol-resenv-0.1.0.tgz
|
|
113
134
|
```
|
|
114
135
|
|
|
115
136
|
This changes the application's manifest and lockfile. The archive must exist
|
|
@@ -127,22 +148,20 @@ local. Leave its manifest, lockfile and CI configuration unchanged.
|
|
|
127
148
|
|
|
128
149
|
Rebuild resenv after source, metadata or documentation changes and restart the
|
|
129
150
|
application. An application `npm ci` can remove the link; recreate it when needed.
|
|
130
|
-
|
|
151
|
+
Authenticate with the official Doppler CLI from the application's directory:
|
|
131
152
|
|
|
132
153
|
```sh
|
|
133
|
-
|
|
154
|
+
doppler login
|
|
134
155
|
```
|
|
135
156
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
check; automated tests must use injected or mocked credentials.
|
|
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.
|
|
139
159
|
|
|
140
160
|
## Optional integration checks
|
|
141
161
|
|
|
142
162
|
`npm run bench` measures fresh-process startup, a plain 200-variable environment,
|
|
143
163
|
and a mocked provider with eight distinct lookups. It needs a build first and
|
|
144
164
|
does not contact a provider. Timings are observations, not CI pass/fail thresholds.
|
|
145
|
-
See [the review](docs/security-performance-review.md) for the recorded comparison.
|
|
146
165
|
|
|
147
166
|
With an existing Nx installation:
|
|
148
167
|
|
|
@@ -168,7 +187,8 @@ enable that option; the CLI passes the returned copy to its child process.
|
|
|
168
187
|
|
|
169
188
|
Add regression tests for changed behavior and avoid real provider calls. Use
|
|
170
189
|
Conventional Commit subjects, for example `fix(resolver): preserve empty values`.
|
|
171
|
-
|
|
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.
|
|
172
192
|
|
|
173
193
|
CODEOWNERS identifies the maintainer. Keep bug reports and pull requests focused
|
|
174
194
|
on observable behavior and include the checks run. Weekly dependency updates are
|
|
@@ -177,6 +197,8 @@ grouped, with major version updates reviewed separately; bots cannot merge them.
|
|
|
177
197
|
Keep the README focused on installation, authentication, application integration,
|
|
178
198
|
API behavior and troubleshooting. Put contributor tooling, test commands and
|
|
179
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.
|
|
180
202
|
|
|
181
203
|
Security reports follow [SECURITY.md](SECURITY.md). Publication and repository
|
|
182
204
|
visibility changes require a separate maintainer decision; see the
|
package/README.md
CHANGED
|
@@ -20,45 +20,60 @@ Resolution happens once at startup. It does not watch the provider for changes;
|
|
|
20
20
|
restart the application to fetch updated values. No filename is passed to
|
|
21
21
|
resenv, and dotenv files are never rewritten.
|
|
22
22
|
|
|
23
|
-
Requires Node.js 20 or later.
|
|
24
|
-
|
|
23
|
+
Requires Node.js 20 or later. The package is experimental and remains in initial
|
|
24
|
+
development; its API may change between 0.x releases.
|
|
25
|
+
|
|
26
|
+
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).
|
|
25
27
|
|
|
26
28
|
## Install
|
|
27
29
|
|
|
28
|
-
Install
|
|
30
|
+
Install in your application project:
|
|
29
31
|
|
|
30
32
|
```sh
|
|
31
|
-
npm install --save-exact /
|
|
33
|
+
npm install --save-exact @ciqol/resenv
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
This records
|
|
35
|
-
|
|
36
|
-
published to npm, you will be able to install `@ciqol/resenv@beta` instead.
|
|
36
|
+
This records the version selected by npm's `latest` tag in your project's
|
|
37
|
+
manifest and lockfile.
|
|
37
38
|
|
|
38
39
|
The CLI examples below use `npx --no-install` to run the copy installed in your
|
|
39
40
|
project. In an npm script, use `resenv` directly.
|
|
40
41
|
|
|
41
42
|
## Use with Doppler
|
|
42
43
|
|
|
44
|
+
Doppler manages application secrets. If you're new to it, start with
|
|
45
|
+
[Doppler's introduction](https://docs.doppler.com/docs/start).
|
|
46
|
+
|
|
43
47
|
### 1. Authenticate locally
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
Follow the [official Doppler CLI installation guide](https://docs.doppler.com/docs/cli#installation)
|
|
50
|
+
for your operating system, then log in from your application directory:
|
|
46
51
|
|
|
47
52
|
```sh
|
|
48
|
-
|
|
53
|
+
doppler login
|
|
49
54
|
```
|
|
50
55
|
|
|
51
|
-
Each developer authenticates with their own Doppler access.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
and
|
|
56
|
+
Each developer authenticates with their own Doppler access.
|
|
57
|
+
|
|
58
|
+
> [!WARNING]
|
|
59
|
+
> Authentication and credential storage depend on the Doppler CLI's implementation
|
|
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.
|
|
55
73
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
login is not yet verified end to end. Windows needs `DOPPLER_TOKEN` because
|
|
60
|
-
native login/storage is not implemented there. See
|
|
61
|
-
[Doppler login and platform details](docs/doppler.md).
|
|
74
|
+
Need another secrets provider, operating system or CLI installation method?
|
|
75
|
+
[Request support](https://github.com/ciqol/resenv/issues/new) with your use case
|
|
76
|
+
and platform details.
|
|
62
77
|
|
|
63
78
|
### 2. Declare references in the environment your app already loads
|
|
64
79
|
|
|
@@ -94,7 +109,8 @@ npx --no-install resenv run -- node app.mjs
|
|
|
94
109
|
|
|
95
110
|
The wrapper supplies resolved values to the child process. It inherits
|
|
96
111
|
stdin/stdout/stderr, preserves exit status and forwards SIGINT, SIGTERM and
|
|
97
|
-
SIGHUP to that child.
|
|
112
|
+
SIGHUP to that child. On POSIX, the child runs in its own session so terminal
|
|
113
|
+
signals reach it only through the wrapper.
|
|
98
114
|
|
|
99
115
|
## Nx integration
|
|
100
116
|
|
package/SECURITY.md
CHANGED
|
@@ -9,22 +9,24 @@ any credentials supplied to it.
|
|
|
9
9
|
|
|
10
10
|
Doppler mode uses a fixed HTTPS API origin, disables redirects and fetches only
|
|
11
11
|
referenced secret names. It does not execute shell expressions. Credentials
|
|
12
|
-
come from an explicit
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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.
|
|
17
18
|
The canonical `resolve` preload and `run` command select Doppler only for
|
|
18
19
|
`doppler://` values. They do not infer shell execution from `$()` values.
|
|
19
|
-
Startup does not initiate login
|
|
20
|
-
|
|
20
|
+
Startup does not initiate login. Use `doppler login` separately for local
|
|
21
|
+
development or supply a suitably scoped token for unattended runs.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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.
|
|
28
30
|
|
|
29
31
|
Command mode executes trusted configuration with the current user's
|
|
30
32
|
permissions. Enable it only for configuration you have reviewed. Commands can
|
|
@@ -57,17 +59,15 @@ all changed properties; read-only properties, setters and Proxy targets are
|
|
|
57
59
|
rejected before any values are committed. Use `resolve()` to obtain a copy
|
|
58
60
|
when the input is not a writable environment record.
|
|
59
61
|
|
|
60
|
-
This experimental package has not had an independent security audit.
|
|
61
|
-
|
|
62
|
+
This experimental package has not had an independent security audit. See
|
|
63
|
+
[verification](CONTRIBUTING.md) and [Doppler platform limits](docs/doppler.md).
|
|
62
64
|
|
|
63
65
|
## Reporting a vulnerability
|
|
64
66
|
|
|
65
67
|
Do not open a public issue containing a vulnerability, credentials or sensitive
|
|
66
|
-
output.
|
|
67
|
-
|
|
68
|
-
an existing private channel.
|
|
69
|
-
maintainers must enable GitHub private vulnerability reporting and verify that
|
|
70
|
-
it is available.
|
|
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
71
|
|
|
72
72
|
Include affected versions, platform, impact and a minimal reproduction using
|
|
73
73
|
dummy data. Never include production tokens, private keys or environment dumps.
|
package/bin/resenv.cjs
CHANGED
|
@@ -6,32 +6,15 @@ var node_os = require('node:os');
|
|
|
6
6
|
var assertSafeDiagnostics = require('../assert-safe-diagnostics.cjs');
|
|
7
7
|
var preload = require('../preload.cjs');
|
|
8
8
|
var index = require('../index.cjs');
|
|
9
|
-
var auth = require('../doppler/auth.cjs');
|
|
10
|
-
var system = require('../doppler/system.cjs');
|
|
11
|
-
var references = require('../doppler/references.cjs');
|
|
12
9
|
var values = require('../values.cjs');
|
|
13
10
|
|
|
14
|
-
const usage = 'Usage: resenv run [--commands] -- <command> [arguments...]\
|
|
15
|
-
|
|
11
|
+
const usage = 'Usage: resenv run [--commands] -- <command> [arguments...]\nInfer secret providers from values already in the environment.\nManage authentication with doppler login and doppler logout, or supply DOPPLER_TOKEN.\n--doppler remains accepted for compatibility.\n--commands enables whole-value $(command) expressions using /bin/sh.\n';
|
|
12
|
+
function main() {
|
|
16
13
|
const args = process.argv.slice(2);
|
|
17
14
|
if (args.length === 1 && ['--help', '-h'].includes(args[0] || '')) {
|
|
18
15
|
process.stdout.write(usage);
|
|
19
16
|
return;
|
|
20
17
|
}
|
|
21
|
-
const explicitProvider = args[1] === 'doppler';
|
|
22
|
-
if (args[0] === 'login' && args.slice(explicitProvider ? 2 : 1).every(arg => ['--cli', '--no-browser'].includes(arg))) {
|
|
23
|
-
if (!explicitProvider && !references.references(process.env).length) {
|
|
24
|
-
process.stderr.write('Nothing to handle: no cloud secret references in the environment. Load your target environment first, or use resenv login doppler.\n');
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
await auth.login({ cli: args.includes('--cli'), noBrowser: args.includes('--no-browser') });
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (args.length === 2 && args[0] === 'logout' && args[1] === 'doppler') {
|
|
31
|
-
system.createSystem().remove();
|
|
32
|
-
process.stderr.write('Removed the resenv credential. Doppler CLI credentials and DOPPLER_TOKEN are unchanged; revoke the token in Doppler to invalidate it.\n');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
18
|
let commands = false;
|
|
36
19
|
while (args[0] === 'run' && ['--commands', '--doppler'].includes(args[1] || '')) {
|
|
37
20
|
if (args[1] === '--commands')
|
|
@@ -55,11 +38,23 @@ async function main() {
|
|
|
55
38
|
return;
|
|
56
39
|
}
|
|
57
40
|
assertSafeDiagnostics.assertSafeDiagnostics();
|
|
58
|
-
|
|
41
|
+
// Isolate the child from terminal group signals; the wrapper forwards them once.
|
|
42
|
+
const child = node_child_process.spawn(command, commandArgs, { env, stdio: 'inherit', shell: false, detached: process.platform !== 'win32' });
|
|
59
43
|
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
|
|
60
44
|
const handlers = new Map();
|
|
61
45
|
for (const signal of signals) {
|
|
62
|
-
const handler = () => {
|
|
46
|
+
const handler = () => {
|
|
47
|
+
try {
|
|
48
|
+
if (process.platform !== 'win32' && child.pid)
|
|
49
|
+
process.kill(-child.pid, signal);
|
|
50
|
+
else
|
|
51
|
+
child.kill(signal);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (!values.hasErrorCode(err, 'ESRCH'))
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
63
58
|
handlers.set(signal, handler);
|
|
64
59
|
process.on(signal, handler);
|
|
65
60
|
}
|
|
@@ -85,7 +80,10 @@ async function main() {
|
|
|
85
80
|
}
|
|
86
81
|
});
|
|
87
82
|
}
|
|
88
|
-
|
|
83
|
+
try {
|
|
84
|
+
main();
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
89
87
|
process.stderr.write(`${index.formatError(err)}\n`);
|
|
90
88
|
process.exitCode = 1;
|
|
91
|
-
}
|
|
89
|
+
}
|
package/docs/build.md
CHANGED
|
@@ -71,7 +71,7 @@ Public options use type aliases and readonly properties. `Environment` stays
|
|
|
71
71
|
mutable for optional in-place replacement. `resolve()` always returns a new
|
|
72
72
|
`Environment`, with input replacement enabled only by `{ replace: true }`. It
|
|
73
73
|
does not preserve a generic input type: resolved strings cannot retain a
|
|
74
|
-
literal reference type.
|
|
74
|
+
literal reference type.
|
|
75
75
|
ESLint uses type information and enforces the selected style rules. The compiler
|
|
76
76
|
checks all library/CLI source, colocated unit specs and both consumer formats with `strict` and
|
|
77
77
|
`noUncheckedIndexedAccess`. Provider responses and parsed worker input start as
|
|
@@ -90,11 +90,11 @@ overrides and a package-wide `type` field. Explicit `.mjs` and `.cjs` extensions
|
|
|
90
90
|
select the output format. README, the MIT `LICENSE`, contributor/security guides
|
|
91
91
|
and docs are copied into the distribution and included in the archive.
|
|
92
92
|
|
|
93
|
-
Ordinary local builds retain `private: true`.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
98
|
|
|
99
99
|
`npm run pack:local` packs the generated directory. `npm run test:package`
|
|
100
100
|
instead packs into a temporary directory and installs it offline into a clean
|
|
@@ -114,23 +114,26 @@ consumer artifact is rebuilt in place by these tests.
|
|
|
114
114
|
|
|
115
115
|
## CI
|
|
116
116
|
|
|
117
|
-
The `
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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.
|