@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/docs/doppler.md CHANGED
@@ -1,4 +1,4 @@
1
- # Doppler references and login
1
+ # Doppler references and CLI authentication
2
2
 
3
3
  Doppler is resenv's only built-in cloud provider. After Nx or another loader
4
4
  populates the environment, resenv fetches referenced values through HTTPS and
@@ -13,40 +13,57 @@ a provider option. `resolve-doppler` and
13
13
 
14
14
  ## Local setup
15
15
 
16
- From the checkout, build and log in:
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:
17
19
 
18
20
  ```sh
19
- npm run build
20
- node dist/bin/resenv.cjs login doppler
21
+ doppler login
21
22
  ```
22
23
 
23
- After installing a packed build, the same command is `resenv login doppler`.
24
- If the references are already loaded into the shell environment, `resenv login`
25
- infers Doppler without naming it. No cloud references means no login is needed.
26
- Neither command loads dotenv files; Nx remains responsible for file selection.
27
- It requests a browser authorization code, opens Doppler's authorization page,
28
- and waits up to five minutes for you to approve the login. `--no-browser`
29
- prints the page and code without opening it. Login requires a terminal outside
30
- CI; application startup never opens a browser or prompts for credentials.
31
- If login falls back to the Doppler CLI, that CLI handles its own browser prompt.
32
-
33
- The native flow follows the protocol observed in Doppler's published
34
- `@dopplerhq/mcp-server` 1.0.5 package. These login endpoints are not a documented
35
- third-party OAuth contract. They can change independently of the public API.
36
- resenv identifies itself with its own version and user agent.
37
-
38
- The user token is saved in the OS credential store under service
39
- `ciqol.envref.doppler`, account `default`. The identifier is retained across
40
- the resenv rename so existing logins continue to work. Nothing is saved in the repository,
41
- dotenv files or worktree. The current prototype stores one workplace login per
42
- OS user; logging in again replaces that saved identity. Each developer logs in
43
- separately and receives the permissions of their own Doppler account.
44
-
45
- Native persistence supports macOS Keychain via `/usr/bin/security` and Linux
46
- Secret Service via an installed `/usr/bin/secret-tool`. The token is passed to
47
- the helper through stdin, never through process arguments. resenv does not
48
- install these tools or fall back to a plaintext credential file. Windows can
49
- use a supplied `DOPPLER_TOKEN`; native Windows login/storage is not implemented.
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.
50
67
 
51
68
  ## Declare a reference
52
69
 
@@ -73,38 +90,31 @@ For an Nx command target, use `resenv run -- node app.mjs` inside the
73
90
  target. Preloading the outer Nx process would run before Nx loads target files.
74
91
  resenv does not choose, read or rewrite dotenv files.
75
92
 
76
- ## Credentials and CLI fallback
93
+ ## Runtime credential lookup
77
94
 
78
95
  Resolution checks these sources in order:
79
96
 
80
97
  1. An explicitly supplied `DOPPLER_TOKEN`.
81
- 2. The resenv credential in the OS store.
82
- 3. The current directory's existing Doppler CLI login, retrieved with the
98
+ 2. The current directory's existing Doppler CLI login, retrieved with the
83
99
  documented `doppler configure get token --plain` operation.
84
100
 
85
- The fallback captures that token internally and still fetches secrets through
86
- HTTPS. It does not parse the CLI's private config format. It invokes a fixed
87
- executable with separate arguments and a restricted environment. Current
88
- executable locations are `/opt/homebrew/bin/doppler`,
89
- `/usr/local/bin/doppler` and `/usr/bin/doppler`; a repository's `PATH` cannot
90
- select a different credential helper. Other installations can supply a token.
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.
91
107
 
92
- Native login falls back to `doppler login` when the OS store is unavailable or
93
- the authorization endpoint returns HTTP 404, 405 or 501. To select it directly:
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.
94
113
 
95
- ```sh
96
- resenv login doppler --cli
97
- ```
98
-
99
- An explicit invalid token, access denial, login rejection, timeout or network
100
- error stops the operation. These failures do not silently switch identities.
101
- Unset `DOPPLER_TOKEN` before interactive login because it overrides saved logins.
102
- In CI, supply a suitably scoped token through the runner's credential facility.
103
-
104
- `resenv logout doppler` removes only resenv's local credential. It does not
105
- revoke the remote token, unset an environment variable or log the Doppler CLI
106
- out. Those other credential sources can still authenticate. Revoke unwanted
107
- tokens from Doppler's CLI Tokens page.
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.
108
118
 
109
119
  ## Resolution and security boundaries
110
120
 
@@ -126,10 +136,9 @@ tokens from Doppler's CLI Tokens page.
126
136
  - Preloads use a child Node process to wait for asynchronous HTTPS while
127
137
  retaining `--require` compatibility. It receives only references and an
128
138
  explicit credential through stdin, with results returned through a private
129
- pipe. No Doppler CLI is required when a native credential is available.
139
+ pipe. No Doppler CLI is required when `DOPPLER_TOKEN` is supplied.
130
140
  - Diagnostics show variable names and error codes, never tokens, provider
131
- response bodies or resolved values. Only explicit interactive login displays
132
- its temporary human authorization code.
141
+ response bodies, CLI output or resolved values.
133
142
 
134
143
  This removes shell evaluation from Doppler lookups. It does not isolate
135
144
  untrusted repository code or agents that can access the same user's credential
@@ -139,8 +148,8 @@ to a specific config.
139
148
 
140
149
  ## Sources
141
150
 
142
- - [Doppler MCP authentication](https://docs.doppler.com/docs/mcp#1-authenticate)
143
- - [Published MCP package](https://www.npmjs.com/package/@dopplerhq/mcp-server/v/1.0.5)
151
+ - [Doppler CLI installation and authentication](https://docs.doppler.com/docs/cli)
152
+ - [Directory-scoped workplace logins](https://docs.doppler.com/docs/multiple-workplaces)
144
153
  - [Retrieve a secret](https://docs.doppler.com/reference/secrets-get)
145
154
  - [API authentication](https://docs.doppler.com/reference/api)
146
155
  - [Retrieve the CLI token](https://docs.doppler.com/docs/cli#fetch-cli-token-from-your-local-environment)
@@ -1,112 +1,40 @@
1
- # Maintainer handoff
1
+ # Maintainer guide
2
2
 
3
- ## Start a session
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.
4
8
 
5
- Open the repository folder as its own Codex project. Use the same checkout for
6
- local work or create an isolated worktree for a separately authorized task.
7
- Read [AGENTS.md](https://github.com/ciqol/resenv/blob/beta/AGENTS.md), [CONTRIBUTING.md](../CONTRIBUTING.md) and
8
- [the release guide](releasing.md). Inspect `git status`, the current branch,
9
- the push remote and recent commits before changing anything.
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.
10
13
 
11
- The repository is [ciqol/resenv](https://github.com/ciqol/resenv). Authenticate
12
- GitHub as `titan-ron` using the repository-local credential setup in AGENTS.md.
13
- `beta` is the sole remote and default branch. Work on a local `titan/*` branch;
14
- never commit directly on the default branch. The repository stores all source,
15
- tests, build configuration and operating instructions needed to continue.
16
- Do not depend on previous chat history or copy credentials between sessions.
17
-
18
- ## Product contract
19
-
20
- - Package: `@ciqol/resenv`; CLI: `resenv`.
21
- - Node preloads: `--require @ciqol/resenv/resolve` and
22
- `--import @ciqol/resenv/resolve`.
23
- - Public API: `resolve(env = process.env, { replace: false })`. Always return a
24
- copy; update the input only with `replace: true`.
25
- - Let Nx or the caller load dotenv files. Resolve values already in the
26
- environment, once before application imports.
27
- - Doppler is the only cloud provider. Infer it from
28
- `doppler://project/config/SECRET_NAME`; that syntax belongs to resenv.
29
- - Commands require explicit opt-in. Fetched values remain literal, and a
30
- failed pass leaves the caller's environment unchanged.
31
- - Debug selector: `NODE_DEBUG=ciqol:resenv`. Never log secret values, tokens,
32
- command text or provider response bodies.
33
- - Runtime npm dependencies: none. Dotenvx decryption has been removed;
34
- `encrypted:` values remain literal.
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 |
35
23
 
36
24
  ## Code map
37
25
 
38
26
  | Path | Responsibility |
39
27
  | --- | --- |
40
- | `src/index.ts` | Resolution API and atomic replacement |
28
+ | `src/index.ts` | Resolution API and atomic environment replacement |
41
29
  | `src/preload.ts`, `src/resolve*.ts` | Startup integration and shared preload state |
42
- | `src/doppler/` | Reference parsing, HTTPS, bounded concurrency, credentials and login |
30
+ | `src/doppler/` | References, HTTPS, concurrency and CLI credential lookup |
43
31
  | `src/commands.ts` | Explicit shell substitution and process limits |
44
- | `bin/resenv.ts` | Login, logout and child-process CLI |
45
- | `rollup.config.mjs`, `scripts/build.mjs` | CJS implementation, shared ESM facades and generated types |
46
- | `scripts/release-plan.mjs` | Official semantic-release analysis/notes plugins and beta counter |
47
- | `scripts/publish.mjs` | OIDC staging of the tested archive and post-publication tag recording |
48
- | `.github/workflows/ci.yml` | Build once, test the archive across runtimes, manually dispatched release |
49
-
50
- ## Verify changes
51
-
52
- Use the exact Node.js version in `.nvmrc` and normal npm lifecycle behavior:
53
-
54
- ```sh
55
- nvm use
56
- npm ci
57
- npm run audit
58
- npm run verify
59
- ```
60
-
61
- Unit specs live beside source modules and run with Vitest. Process tests live
62
- in `test/`. Clean-consumer checks exercise CJS, ESM, declarations, CLI and
63
- preloads against the packed archive. Tests use dummy values and mocked effects;
64
- do not use a developer's Doppler account or OS credential store as a fixture.
65
- See CONTRIBUTING for Nx integration checks and benchmarking.
66
-
67
- ## Recover release state before pushing
68
-
69
- Read current state rather than treating a dated handoff as authoritative:
70
-
71
- ```sh
72
- gh run list --repo ciqol/resenv --workflow ci.yml --limit 5
73
- gh release list --repo ciqol/resenv
74
- npm view @ciqol/resenv versions dist-tags --json
75
- npm stage list @ciqol/resenv --json
76
- ```
77
-
78
- The first intended version is `0.1.0-beta.1` on npm's `beta` tag. The planner
79
- uses semantic-release's official commit-analysis and notes plugins directly;
80
- it does not run the full semantic-release engine. Real published release tags
81
- supply later beta counters. Do not fabricate tags to advance a version.
82
-
83
- Publishing is staged: a trusted manual CI dispatch submits the exact archive
84
- that passed all consumer checks. The `release` environment accepts only `beta`
85
- and has no GitHub reviewer gate. npm approval with 2FA makes a stage public.
86
- After public availability and integrity verification, rerun the original
87
- release job to record its Git tag and GitHub prerelease. Keep `beta` at that
88
- candidate's commit until this step finishes, unless the maintainer explicitly
89
- chooses to reject and replace the pending stage. Do not rerun the whole
90
- workflow to recover an existing stage.
91
-
92
- A staged version reserves its version number. To replace an unapproved
93
- candidate, the maintainer must reject the old stage with npm 2FA before CI
94
- stages the replacement. Check stage status before retrying an ambiguous result.
95
- Never publish from a developer machine, add a publishing token, promote a beta
96
- to `latest`, or delete the whole npm package. The `0.0.0-stage` placeholder must
97
- remain until a functional beta is public; removing the last published version
98
- would remove the package and impose npm's publishing cooldown.
99
-
100
- ## Known limits and follow-ups
101
-
102
- - Native Doppler browser login has unit/mock coverage but has not been verified
103
- end to end with a fresh account. Linux credential storage has mock coverage;
104
- Windows native login/storage is not implemented. Explicit tokens and existing
105
- CLI credentials are supported. See [Doppler details](doppler.md).
106
- - The development release-tool tree has reviewed advisories. Exceptions expire
107
- November 9, 2026, and executable guards fail on expiry or drift. Review
108
- [release security](release-security.md); never broaden or bypass the policy.
109
- - This beta has not had an independent security audit. Passing tests or the
110
- static maturity checklist does not establish production readiness.
111
- - Consumer repositories are separate. Keep local links out of their committed
112
- package manifests, lockfiles and CI.
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.
@@ -1,134 +1,64 @@
1
- # Release-tool security review
2
-
3
- Reviewed October 10, 2026. Owner: `titan-ron`. Scope: semantic-release version
4
- planning in read-only CI. The runtime package has no advisory exceptions.
5
-
6
- ## Decision and controls
7
-
8
- Admit semantic-release 25.0.9, commit-analyzer 13.0.1 and release-notes-generator
9
- 14.1.1 as exact development dependencies for version calculation and notes.
10
- Use the bounded exceptions in [security-exceptions.json](security-exceptions.json)
11
- only with the executable controls below. These are engineering risk exceptions,
12
- not upstream fixes or a clean vulnerability scan. They expire November 9, 2026.
13
-
14
- The isolated audit reports 10 high and two moderate affected-package entries.
15
- Several entries propagate the same underlying finding to their parent packages.
16
- The final merged installation reports 12 active advisory IDs affecting six distinct packages:
17
-
18
- | Package | Reviewed location | Why its affected code cannot execute in the planner |
19
- | --- | --- | --- |
20
- | braces | Development dependency of micromatch | Every callable export is replaced by a throwing guard before loading semantic-release. The selected matching calls delegate to picomatch. |
21
- | brace-expansion | npm's bundled dependency | The unselected npm plugin and its bundled npm module are blocked by a Node resolution hook. |
22
- | http-cache-semantics | npm's bundled dependency | Same blocked npm module. |
23
- | ip-address | npm's bundled dependency | Same blocked npm module. |
24
- | postcss-selector-parser | npm's bundled dependency | Same blocked npm module. |
25
- | undici | npm's bundled dependency | Same blocked npm module. |
26
-
27
- The branch expander calls `micromatch(list, branch.name)`. The analyzer calls
28
- `micromatch.isMatch(commitField, ruleField)`. Both functions in micromatch 4.0.8
29
- delegate to picomatch rather than its braces-based parse/expand helpers. Patterns
30
- are the fixed branch `beta` and the analyzer's reviewed default rules; commit
31
- fields and remote branch names are matching subjects. Guarding all braces calls
32
- also prevents a later caller from silently opening the vulnerable path.
33
-
34
- Sources: [branch expansion](https://github.com/semantic-release/semantic-release/blob/v25.0.9/lib/branches/expand.js),
35
- [commit matching](https://github.com/semantic-release/commit-analyzer/blob/v13.0.1/lib/analyze-commit.js),
36
- [micromatch matching](https://github.com/micromatch/micromatch/blob/4.0.8/index.js),
37
- [braces advisory](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm).
38
-
39
- The guards pin the engine, analyzer, notes generator, micromatch and braces
40
- versions. Changed versions fail until the control is reviewed. The audit checks
41
- each advisory URL, exact affected version and development-only lockfile path.
42
- New findings, runtime occurrences, changed paths and expired reviews fail CI.
43
- Propagated parent findings do not create additional blanket exemptions.
44
- `npm audit --omit=dev --audit-level=high` also runs without exceptions.
45
-
46
- The planner receives no GitHub write token, npm credential or OIDC permission.
47
- It reads Git history and actual beta tags locally. The official commit-analysis
48
- and release-notes plugins are fixed in code; the full semantic-release engine
49
- is not invoked while beta is the sole branch. An explicit 0.1.0 beta line and
50
- monotonic counter replace its default 1.0.0 initial version. The publisher does
51
- not install dependencies or import release tools. It verifies candidate hashes
52
- and source identity, then stages the tested archive through npm OIDC. Maintainer approval through npm publishes it.
53
- A rerun verifies registry integrity before recording the computed tag/release
54
- through GitHub's API. Conventional Commit classification remains upstream.
55
-
56
- ## Verification
57
-
58
- An isolated test blocked direct braces calls and imports of the unselected npm
59
- and GitHub plugins. Normal and adversarial commit analysis passed with 10,000
60
- nested brace pairs in subjects and bodies. The planner tests cover
61
- `0.1.0-beta.1`, unchanged history, and subsequent beta counters using real history in a disposable clone without changing source refs.
62
-
63
- An isolated attempt to override npm's bundled vulnerable components did not
64
- replace their distributed copies. No ineffective override was admitted.
65
- Standalone patched releases do not establish that the bundled copy is fixed.
66
- Review and remove these exceptions when the upstream distributions are fixed.
67
-
68
- ## Dependency admission
69
-
70
- - **Need:** automate Conventional Commit analysis and release notes, as selected
71
- by the user. Platform APIs do not implement that versioning contract.
72
- - **Fit:** retain the selected engine rather than switch to release-please or
73
- maintain a custom analyzer. Native publication glue preserves the tested
74
- archive instead of letting a package-directory plugin repack it.
75
- - **Health:** registry review recorded monthly downloads of 12,515,497 for the
76
- engine, 12,542,138 for the analyzer and 12,802,125 for the notes generator,
77
- with three listed maintainers each. Selected release dates are August 5, 2026;
78
- January 3, 2025; and May 8, 2026. The older analyzer remains the component
79
- required by the current engine. Maintenance evidence is not a security guarantee.
80
- - **Trust:** the canonical semantic-release repositories match the distributed
81
- modules. The isolated installation verified 447 registry signatures and 121
82
- provenance attestations; the final merged installation verified 606 signatures
83
- and 186 attestations. Registry metadata does not expose individual MFA or
84
- independently prove historical ownership continuity; those limits remain.
85
- - **License:** the three direct artifacts contain MIT license text. The isolated
86
- tree's licenses are MIT, ISC, BSD-2-Clause, BSD-3-Clause, Apache-2.0, BlueOak-1.0.0,
87
- Python-2.0, Artistic-2.0, CC-BY-3.0, CC0-1.0 and permissive alternative sets.
88
- qrcode-terminal's absent SPDX metadata is resolved by its Apache-2.0 LICENSE.
89
- Some artifacts express the license in package metadata rather than a separate
90
- license file. No reciprocal source-disclosure license was identified. These
91
- development modules are excluded from the consumer package.
92
- - **Capabilities:** filesystem, subprocess and Git access are required for local
93
- history analysis. The selected plugin path does not publish, contact npm or
94
- post GitHub comments. The isolated tree contains no install lifecycle hooks.
95
- - **Control:** exact direct versions and the lockfile pin the tree; CODEOWNERS
96
- and Dependabot retain ownership and update visibility. The guards and expiring
97
- audit policy fail on drift. Removal means deleting the three development
98
- dependencies and disabling release planning/publication; local build and
99
- consumer verification remain available.
100
-
101
- The audit result must remain visible. Do not describe the release-tool tree as
102
- vulnerability-free, use an audit-wide ignore, or pass it to a privileged job.
103
-
104
- ## Publishing platform
105
-
106
- The publisher uses the npm CLI shipped with the pinned Node.js 24.19.0 runtime
107
- (npm 11.17.0). That platform CLI also bundles older components affected by
108
- advisories. npm 12.2.0 was inspected and still distributes affected versions;
109
- upgrading to it would not remove this risk. The development-only policy does
110
- not imply that the platform CLI is vulnerability-free.
111
-
112
- The staging path uses npm 11.17.0's existing `stage publish` subcommand and
113
- accepts only the validated archive, with no lifecycle
114
- scripts in its manifest. It uses a fresh home, configuration and cache, fixes
115
- the registry to HTTPS npmjs.org, and strips proxy, token and arbitrary npm
116
- configuration from the child environment. No package-query, login, shell,
117
- selector or arbitrary URL input is accepted. OIDC is supplied by GitHub for the
118
- specific repository, workflow and protected environment. Registry and signing
119
- services remain trusted inputs. This bounds exposure; it is not an upstream
120
- fix. The publisher checks the policy expiry again when it runs, including on a
121
- failed-job retry, and rejects platform version drift. Review the platform CLI
122
- again before November 9 alongside this policy.
123
-
124
- ## October 12 staging review
125
-
126
- The pinned npm platform includes `lib/commands/stage/publish.js`, which extends
127
- its reviewed publish command and sets `stage: true`. The same fixed tarball,
128
- registry, OIDC identity and provenance options apply. Approval/rejection remain
129
- interactive npm operations, outside CI. The publisher validates npm's JSON
130
- receipt against the candidate's name, version and SHA-512 integrity and records
131
- only its stage identifier and hashes. It creates no tag while the archive is
132
- staged or pending registry availability. After approval, rerun the same release
133
- job: its existing-version path verifies integrity and records the release.
134
- No dependency version, advisory exception or expiry was broadened.
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.