@ciqol/resenv 0.1.0-beta.1 → 0.1.0-beta.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/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,39 @@
1
- # Maintainer handoff
1
+ # Maintainer guide
2
2
 
3
- ## Start a session
3
+ Start with [AGENTS.md](https://github.com/ciqol/resenv/blob/beta/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); `beta` 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) | Candidate checks, npm staging/approval and recovery |
21
+ | [Release security](release-security.md) | Isolation guards, advisory policy and platform 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
+ | `scripts/release-plan.mjs` | Official release plugins and beta counter |
35
+ | `scripts/publish.mjs` | Tested-archive staging and verified release recording |
36
+ | `.github/workflows/ci.yml` | Build once, archive matrix tests and manual release |
37
+
38
+ Keep docs focused on current contracts, decisions and procedures. Put per-run
39
+ test results, benchmarks, audit snapshots and session history in PRs or CI.
@@ -1,134 +1,70 @@
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.
1
+ # Release-tool security
2
+
3
+ Maintainer: `titan-ron`. Runtime dependencies have no advisory exceptions.
4
+ The executable development policy is [security-exceptions.json](security-exceptions.json).
5
+ Its review expires **November 9, 2026 at 00:00 UTC**. This is a project review
6
+ deadline, also enforced by the publisher for platform npm; removing unused
7
+ development tools does not extend it.
8
+
9
+ ## Release planning
10
+
11
+ The planner calls the official commit-analysis and release-notes plugins
12
+ directly. It reads Git history and published beta tags without GitHub write,
13
+ npm or OIDC credentials. The full `semantic-release` engine and its publishing
14
+ plugins are unnecessary for this beta-only workflow.
15
+
16
+ The committed peer-omission policy keeps the engine, `@semantic-release/npm`,
17
+ `@semantic-release/github` and their npm module off disk. Before auditing or
18
+ planning, `scripts/release-guards.mjs` requires that none resolve from the
19
+ project or either selected plugin. Its planner hook also rejects bare and
20
+ resolved imports of those tools. An audit explicitly including omitted peers
21
+ can still report their locked entries; see [installation policy](dependencies.md).
22
+
23
+ The guard pins both plugins, micromatch and braces. It replaces every callable
24
+ braces export with a throwing guard before loading the plugins. The selected
25
+ micromatch matching calls use picomatch; vulnerable brace expansion must never
26
+ execute. Version drift fails until the guards are reviewed.
27
+
28
+ `npm run audit` checks runtime dependencies without exceptions, then the
29
+ installed development tree. Moderate/high/critical findings must match an exact
30
+ advisory URL, development-only lockfile path, version and unexpired policy
31
+ entry. New advisories, changed paths, runtime occurrences and expired
32
+ exceptions fail. The retained exception entries do not authorize reinstalling
33
+ the excluded tools. Prefer an upstream fix or removing unused dependencies;
34
+ never broaden the policy to make a check pass.
103
35
 
104
36
  ## Publishing platform
105
37
 
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.
38
+ The privileged publisher installs no release-tool dependencies and accepts only
39
+ the archive described by the verified candidate plan. It checks source identity
40
+ and hashes before invoking npm. Publication follows the [release runbook](releasing.md).
41
+
42
+ The platform is pinned to Node.js 24.19.0 and its npm 11.17.0. Platform npm has
43
+ separately reviewed bundled-component risks; omitting development peers does
44
+ not fix those components. `scripts/publish.mjs` rejects platform version drift
45
+ and an expired review, including on a failed-job retry.
46
+
47
+ The staging command accepts a fixed tarball and HTTPS npm registry, with no
48
+ package lifecycle scripts in the generated manifest. It runs with a fresh home,
49
+ configuration and cache, strips proxy/token/arbitrary npm configuration, and
50
+ uses the protected workflow's OIDC identity. It accepts no login, shell,
51
+ selector or arbitrary URL input. Registry and signing services remain trusted
52
+ inputs. These controls bound exposure; they do not patch the platform CLI.
53
+
54
+ The publisher validates the staging receipt's package name, version and
55
+ integrity. npm approval publishes the stage. A retry verifies the public
56
+ archive's integrity and both npm tags before recording the Git tag/release.
57
+ No tag is created for a pending stage.
58
+
59
+ ## Reviewing changes
60
+
61
+ Review the actual published artifacts, including bundled copies; patching a
62
+ standalone package does not establish that npm's bundled copy is fixed.
63
+ Recheck platform npm before the deadline and remove obsolete exception entries
64
+ when upstream fixes or dependency removal make them unnecessary. Do not extend
65
+ the deadline or bypass executable controls to unblock publication.
66
+
67
+ Run `npm run audit`, `npm audit signatures` and `npm run verify`. Release tooling
68
+ specs cover absence/version guards, policy scope and expiry, adversarial commit
69
+ analysis, real Git release history and publisher isolation. Keep review evidence
70
+ in the PR and CI, and maintain this document as the current policy.