@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.
Files changed (65) hide show
  1. package/CONTRIBUTING.md +189 -0
  2. package/LICENSE +21 -0
  3. package/README.md +243 -0
  4. package/SECURITY.md +74 -0
  5. package/assert-safe-diagnostics.cjs +15 -0
  6. package/bin/resenv.cjs +91 -0
  7. package/bin/resenv.mjs +1 -0
  8. package/commands.cjs +85 -0
  9. package/docs/build.md +136 -0
  10. package/docs/dependencies.md +505 -0
  11. package/docs/doppler.md +146 -0
  12. package/docs/maintainer-handoff.md +112 -0
  13. package/docs/maturity.md +61 -0
  14. package/docs/public-readiness.md +138 -0
  15. package/docs/release-security.md +134 -0
  16. package/docs/releasing.md +143 -0
  17. package/docs/security-exceptions.json +139 -0
  18. package/docs/security-performance-review.md +150 -0
  19. package/docs/validation.md +700 -0
  20. package/doppler/auth.cjs +125 -0
  21. package/doppler/bridge.cjs +66 -0
  22. package/doppler/http.cjs +77 -0
  23. package/doppler/references.cjs +28 -0
  24. package/doppler/resolve.cjs +58 -0
  25. package/doppler/system.cjs +99 -0
  26. package/doppler-worker.cjs +28 -0
  27. package/doppler-worker.mjs +1 -0
  28. package/errors.cjs +12 -0
  29. package/index.cjs +88 -0
  30. package/index.d.cts +1 -0
  31. package/index.d.mts +1 -0
  32. package/index.mjs +1 -0
  33. package/package.json +89 -0
  34. package/preload.cjs +31 -0
  35. package/resolve-commands.cjs +5 -0
  36. package/resolve-commands.d.cts +1 -0
  37. package/resolve-commands.d.mts +1 -0
  38. package/resolve-commands.mjs +1 -0
  39. package/resolve-doppler.cjs +4 -0
  40. package/resolve-doppler.d.cts +1 -0
  41. package/resolve-doppler.d.mts +1 -0
  42. package/resolve-doppler.mjs +1 -0
  43. package/resolve.cjs +5 -0
  44. package/resolve.d.cts +1 -0
  45. package/resolve.d.mts +1 -0
  46. package/resolve.mjs +1 -0
  47. package/types/bin/resenv.d.ts +2 -0
  48. package/types/src/assert-safe-diagnostics.d.ts +1 -0
  49. package/types/src/commands.d.ts +4 -0
  50. package/types/src/doppler/auth.d.ts +19 -0
  51. package/types/src/doppler/bridge.d.ts +4 -0
  52. package/types/src/doppler/http.d.ts +9 -0
  53. package/types/src/doppler/references.d.ts +9 -0
  54. package/types/src/doppler/resolve.d.ts +9 -0
  55. package/types/src/doppler/system.d.ts +24 -0
  56. package/types/src/doppler-worker.d.ts +1 -0
  57. package/types/src/errors.d.ts +5 -0
  58. package/types/src/index.d.ts +7 -0
  59. package/types/src/preload.d.ts +4 -0
  60. package/types/src/resolve-commands.d.ts +1 -0
  61. package/types/src/resolve-doppler.d.ts +1 -0
  62. package/types/src/resolve.d.ts +1 -0
  63. package/types/src/types.d.ts +9 -0
  64. package/types/src/values.d.ts +5 -0
  65. package/values.cjs +20 -0
@@ -0,0 +1,112 @@
1
+ # Maintainer handoff
2
+
3
+ ## Start a session
4
+
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.
10
+
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.
35
+
36
+ ## Code map
37
+
38
+ | Path | Responsibility |
39
+ | --- | --- |
40
+ | `src/index.ts` | Resolution API and atomic replacement |
41
+ | `src/preload.ts`, `src/resolve*.ts` | Startup integration and shared preload state |
42
+ | `src/doppler/` | Reference parsing, HTTPS, bounded concurrency, credentials and login |
43
+ | `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.
@@ -0,0 +1,61 @@
1
+ # Maturity evaluation
2
+
3
+ Evaluated on October 8, 2026 with the Tashtit maturity 0.3.1 catalog, using
4
+ static working-tree evidence only. This measures the catalog's repository
5
+ hygiene rules; it does not certify security or readiness to publish. Tests
6
+ and hosted checks are recorded separately in [validation](validation.md).
7
+
8
+ ## Maturity: 91% (11/120 weight failing)
9
+
10
+ The maintained source tree scores 100% (0/97 weight failing). The full catalog
11
+ also discovers the generated `dist/package.json`, so its findings are retained.
12
+
13
+ | Scope | Failing weight | Relevant weight |
14
+ | --- | ---: | ---: |
15
+ | Root npm project | 0 | 41 |
16
+ | Generated distribution | 11 | 23 |
17
+ | Repository hygiene | 0 | 24 |
18
+ | GitHub Actions | 0 | 32 |
19
+ | Total | 11 | 120 |
20
+
21
+ ## Findings
22
+
23
+ - **High: generated package has no sibling lockfile** (`lockfile-missing`, 8).
24
+ Evidence: `dist/package.json:2`; no `dist/package-lock.json` exists. A maintained
25
+ npm project needs a lockfile. This directory is generated from the root's v3
26
+ lockfile and consumers maintain their own locks; it is not another workspace.
27
+ Reference: [npm lockfiles](https://docs.npmjs.com/cli/configuring-npm/package-lock-json).
28
+ - **Medium: generated package has no sibling runtime-version file**
29
+ (`setup-nvmrc`, 3). Evidence: `dist/package.json:2`; no `dist/.nvmrc` exists.
30
+ Development projects should pin a runtime. The generated package declares
31
+ `engines.node: >=20` and does not need contributor setup files. The root
32
+ `.nvmrc` pins Node 24.19.0. Reference: [nvm version files](https://github.com/nvm-sh/nvm#nvmrc).
33
+
34
+ ## Passed checks
35
+
36
+ - Root: one v3 npm lockfile, no competing yarn lockfile, `.npmrc`, `.nvmrc`, and
37
+ registry dependencies with exact direct versions. CI uses `npm ci` and
38
+ normal lifecycle behavior; it does not pass `--ignore-scripts`.
39
+ - Repository: valid CODEOWNERS syntax, README, CONTRIBUTING and `.editorconfig`.
40
+ - CI: a parseable workflow, explicit scoped token permissions, bounded job
41
+ timeouts, no `pull_request_target`, and pinned remote actions. The GitHub-owned
42
+ upload action's exact `v7.0.1` tag is permitted by the catalog.
43
+
44
+ The earlier 88% score included a lifecycle-script finding that is now resolved.
45
+ No dependency installation, build, test, or remote request was used to derive
46
+ this static score.
47
+
48
+ ## Not evaluated by this catalog
49
+
50
+ - Docker rules: no candidate Dockerfile exists.
51
+ - Repository protections, private vulnerability reporting and maintainer access.
52
+ - License suitability, secret history, provider login, and runtime behavior.
53
+
54
+ See [public readiness](public-readiness.md) for the separate exposure audit and
55
+ [validation](validation.md) for observed checks.
56
+
57
+ ## Fixable findings
58
+
59
+ No automatic fix is appropriate. The generated package's broad runtime range
60
+ does not identify a development version to pin, and adding another lockfile
61
+ would misrepresent it as a maintained workspace.
@@ -0,0 +1,138 @@
1
+ # Public repository readiness
2
+
3
+ ## Follow-up review — 2026-10-12
4
+
5
+ The repository is now public, with `beta` as the sole remote and default branch.
6
+ CI has staged the first `0.1.0-beta.1` candidate; npm approval and release
7
+ recording are still pending. The accidental public `1.0.0` has been removed,
8
+ and the `0.0.0-stage` placeholder remains. Recheck live state before release work.
9
+
10
+ Private vulnerability reporting returned `enabled: false` during this review.
11
+ The security policy's reporting prerequisite remains outstanding until that
12
+ setting is enabled and verified. See [the session handoff](maintainer-handoff.md)
13
+ and [validation](validation.md) for current behavior and observed checks.
14
+ The dated transition plan below is historical evidence.
15
+
16
+ ## Approved transition - 2026-10-10
17
+
18
+ The current release pipeline and launch state are documented in [releasing](releasing.md).
19
+ The release-tool review and expiring advisory policy are in [release security](release-security.md).
20
+ Earlier dated entries below remain historical evidence and are superseded where
21
+ the current release guide describes a different state.
22
+
23
+ The user approved public visibility, default branch `beta`, and deletion of
24
+ the four older ancestor branch references. A fresh settings snapshot, complete
25
+ Git bundle and verified restore are retained outside the repository. Recheck
26
+ remote heads and ancestry immediately before deletion. Other governance changes
27
+ and PR creation remain outside this transition.
28
+
29
+
30
+ Reviewed on October 8, 2026 at `cb6ebe92c3182051a034dd29e192d51a182b5d22`, before
31
+ the accompanying documentation cleanup. Repository: `ciqol/resenv`. Maintainer
32
+ and authenticated GitHub account: `titan-ron`.
33
+
34
+ ## Result
35
+
36
+ No real credentials or private machine/employer references were identified in
37
+ the reviewed Git history or hosted Actions outputs. The source can become a
38
+ public experimental repository after the remaining decisions below. This does
39
+ not establish npm release readiness or an independent security audit.
40
+
41
+ The repository remains private. No branch, default-branch, access, protection,
42
+ or visibility setting was changed by this audit.
43
+
44
+ ## Exposure review
45
+
46
+ - Gitleaks 8.30.1 scanned all 24 commits reachable from the fetched refs. Its
47
+ nine matches were synthetic Doppler credentials in tests: eight use a dummy
48
+ marker and one uses an alternative fixture marker with sequential digits.
49
+ The tests inject provider and credential helpers instead of authenticating
50
+ those values. No detector exception or history rewrite was added.
51
+ - TruffleHog 3.97.4 scanned the local Git history with network verification and
52
+ update checks disabled. It reported no credentials. Sandbox process-inspection
53
+ restrictions produced temporary-cleanup warnings; the scan completed.
54
+ - Reachable-blob inspection found no committed dotenv/private-key files,
55
+ absolute developer paths, employer references, or private service URLs.
56
+ - All 14 existing Actions log archives and 14 unexpired package artifacts were
57
+ downloaded into a private audit folder and scanned offline. Gitleaks found
58
+ no secrets. Package inspection covered 755 regular files across the archives
59
+ and found no credential files or private developer/employer references.
60
+ - There are no existing issues or pull requests to review for public exposure.
61
+ - The latest pre-cleanup [CI run](https://github.com/ciqol/resenv/actions/runs/37778134741)
62
+ passed on Linux Node 20/22/24 and macOS Node 24.
63
+
64
+ Detection tools cannot prove the absence of every secret. No candidate
65
+ credential was sent to a provider to test whether it works. Git history remains
66
+ visible after deleting an ancestor branch. GitHub exposes existing Actions
67
+ history and logs when visibility becomes public; see
68
+ [GitHub's visibility documentation](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/setting-repository-visibility).
69
+
70
+ ## Cleanup prepared
71
+
72
+ - Ignore local `.idea/` settings without deleting the developer's files.
73
+ - Keep installation and contributor text independent of repository visibility.
74
+ - Include the MIT license and ciqol contributors copyright, selected on October 8.
75
+ Registry publication remains disabled.
76
+ - Mark historical validation/dependency entries so old APIs and version plans
77
+ are not mistaken for current usage instructions.
78
+ - Remove unnecessary references to other project names from current docs.
79
+ Historical commits remain unchanged.
80
+ - Direct security questions from the issue chooser to the security policy.
81
+ - Prepare `beta` as the sole normal release branch on npm's `beta` channel. CI
82
+ also checks the current `titan/beta` preparation branch until branch cleanup.
83
+ PR checks and manual dispatch remain; publishing stays disabled.
84
+ - Recalculate maturity: 91% including generated output, 100% for the maintained
85
+ source tree. These scores do not establish release readiness.
86
+
87
+ ## Remaining decisions and settings
88
+
89
+ 1. **License resolved:** MIT was selected on October 8, 2026, with copyright
90
+ held by ciqol contributors. The root and generated manifests declare MIT;
91
+ the [license](../LICENSE) is included in the package archive.
92
+ 2. **Branches:** the selected sole normal release branch is `beta`, with npm
93
+ channel `beta`. A local dry run with only that branch calculated `1.0.0`;
94
+ another stable branch is unnecessary. Default-branch selection and deletion
95
+ of the older branches remain pending. See [release preparation](releasing.md).
96
+ 3. **Private reporting:** the endpoint returned HTTP 404 while the repository
97
+ is private. Enable and verify it after the approved visibility transition,
98
+ and verify the reporting option described in SECURITY.md. It is not yet available.
99
+ 4. **Protections:** all branch entries report `protected: false`; the ruleset
100
+ API returned HTTP 403 under the current private plan. Re-audit effective
101
+ protections after the transition. No protection policy was applied.
102
+
103
+ ## Proposed transition
104
+
105
+ This plan is for review. It does not authorize npm publication, collaborator or
106
+ team changes, merge-policy changes, rulesets, or a pull request.
107
+
108
+ | Branch | Observed head | Action for the beta-only layout |
109
+ | --- | --- | --- |
110
+ | `beta` | Same reviewed source head as the preparation branch | Keep; make default |
111
+ | `titan/beta` | Current preparation branch | Delete after verifying its head is retained by `beta` |
112
+ | `titan/bootstrap-envref` | `b25da7cfe730bfaca0a470d9a31a303cef7d33ad` | Delete branch pointer |
113
+ | `titan/rename-resenv` | `60e70a4e43b39fc9a87379990e4ed44de50726cb` | Delete branch pointer |
114
+ | `titan/prepare-first-release` | `0c313483d7123b8b4afd360b4e8daae58abc4241` | Delete after changing the default |
115
+
116
+ At the original audit, all three older heads were ancestors of `titan/beta`;
117
+ none contained unique commits. Before deletion, re-check every remote head and
118
+ verify all four older branches are ancestors of the retained `beta` head. Stop
119
+ if any contains newer or unique work.
120
+
121
+ After the branch decision, obtain explicit approval for the default
122
+ branch, listed deletions, public visibility, and private vulnerability reporting.
123
+ The CI push filter and release docs are prepared for this layout. Apply
124
+ only approved scopes and verify branches, default, visibility, reporting and
125
+ CI by read-back. Keep npm publishing disabled until its separate prerequisites
126
+ are complete.
127
+
128
+ ## Recovery
129
+
130
+ A private settings snapshot and complete Git bundle are retained outside this
131
+ repository. Bundle verification and a restore into a separate local bare
132
+ repository reproduced all four original remote branch heads exactly.
133
+
134
+ Restore deleted branch pointers from their recorded SHAs or bundle before
135
+ restoring the old default branch. Visibility can be set back to private, but
136
+ public forks, downloaded code and copied logs cannot be recalled. A settings
137
+ rollback cannot undo public disclosure. Never overwrite newer branch work or
138
+ weaken protections to force a restore.
@@ -0,0 +1,134 @@
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.
@@ -0,0 +1,143 @@
1
+ # Releases
2
+
3
+ ## Versions
4
+
5
+ `beta` is the sole remote and default branch. Releases start at `0.1.0-beta.1`
6
+ and use the npm `beta` tag. A beta tag is not promoted to `latest`.
7
+
8
+ The planner uses semantic-release's official commit-analysis and release-notes
9
+ plugins. Conventional Commits decide whether changes need a release. Each
10
+ releasable update increments the counter from the latest reachable
11
+ `v0.1.0-beta.N` tag; docs-only changes do not release. Breaking changes during
12
+ this experimental line also increment the beta counter. Selecting a stable
13
+ line or another base version is a separate release-policy change.
14
+
15
+ The full semantic-release engine requires a normal release branch and defaults
16
+ to a first version of 1.0.0. Using its official plugins directly preserves the
17
+ requested sole-beta-branch setup without inventing a stable branch or a release
18
+ that never happened. The base line is declared in `release.config.mjs`.
19
+
20
+ The development manifest and ordinary local builds stay private. Only a valid
21
+ release plan sets the distribution version and removes `private` before packing.
22
+ Never edit a generated manifest or overwrite a previously shared archive.
23
+
24
+ ## CI pipeline
25
+
26
+ The [CI workflow](../.github/workflows/ci.yml) builds one archive:
27
+
28
+ 1. **Build:** normal npm installation, runtime/development audits, registry
29
+ signatures, lint, strict types and colocated Vitest specs. The read-only
30
+ planner generates the beta version and notes from Git history. Rollup builds
31
+ it once; npm packs it and records SHA-256 and SHA-512 integrity.
32
+ 2. **Consumers:** Linux Node 20, 22 and the pinned Node 24, plus macOS Node 24,
33
+ install and test the same archive. Checks cover ESM, CJS, types, preloads,
34
+ CLI, literal secret output and failure boundaries. Nothing is rebuilt.
35
+ 3. **Release:** a manual dispatch from `beta` with `publish: true`, after every
36
+ check passes. The protected job verifies hashes, workflow identity and the
37
+ current branch head. It installs no project dependencies and runs no package
38
+ code. `npm stage publish` submits the exact archive through OIDC with
39
+ provenance and the explicit `beta` tag. The job validates and saves npm's
40
+ staging receipt; no Git tag or GitHub release is created yet.
41
+ 4. **Approval and recording:** the maintainer reviews and approves the staged
42
+ package in npm using interactive 2FA. Wait for npm to make it available,
43
+ then rerun the original release job. It verifies the published integrity
44
+ against the original tested archive before creating its Git tag and GitHub
45
+ prerelease. It does not stage or publish the package again.
46
+
47
+ Pushes, PRs and dispatches with `publish: false` cannot stage a package. Release
48
+ jobs are serialized and not cancelled. Artifacts last seven days. A fresh
49
+ workflow run is not a substitute for rerunning the original release job when
50
+ recovering an already staged/published candidate.
51
+
52
+ ## Required setup
53
+
54
+ The existing npm trusted publisher must match:
55
+
56
+ | Field | Value |
57
+ | --- | --- |
58
+ | Provider | GitHub Actions |
59
+ | Organization | `ciqol` |
60
+ | Repository | `resenv` |
61
+ | Workflow filename | `ci.yml` |
62
+ | Environment | `release` |
63
+ | Permission | `npm stage publish` |
64
+
65
+ No permanent npm token or direct-publish permission is needed. The pinned
66
+ Node 24.19.0/npm 11.17.0 platform includes staged publishing. New trusted
67
+ publisher configurations must be validated by a successful CI operation before
68
+ the deadline shown in npm settings.
69
+
70
+ The GitHub environment `release` accepts only the `beta` branch and has no
71
+ required GitHub reviewers. CI submits staged packages; the maintainer approves
72
+ publication in npm. After reading back the branch policy and verifying npm
73
+ setup, set Actions variable `RELEASE_ENABLED=true`. Leave it unset until then
74
+ to prevent a dispatch from creating an unrestricted environment automatically.
75
+ Environment creation or protection changes require explicit authorization.
76
+
77
+ ## Run the first beta
78
+
79
+ Open [CI](https://github.com/ciqol/resenv/actions/workflows/ci.yml), choose
80
+ **Run workflow**, select `beta`, and enable the staging input. When build and
81
+ consumer checks pass, the release job stages the archive without another GitHub
82
+ approval. Its summary and the `resenv-stage` artifact contain the stage
83
+ identifier and tested integrity.
84
+
85
+ Review the staged package in npm, then approve it with the stage identifier:
86
+
87
+ ```sh
88
+ npm stage view <stage-id> --json
89
+ npm stage approve <stage-id>
90
+ ```
91
+
92
+ These are maintainer review/approval commands; the archive is built and staged
93
+ by GitHub Actions. OIDC cannot perform the approval step. Wait for npm scanning
94
+ and public availability, then rerun the original release job to record the tag.
95
+ Verify the npm version, `beta` tag, archive integrity, provenance and GitHub
96
+ prerelease. Never infer success from a staging receipt alone.
97
+
98
+ For a hosted rehearsal, leave the staging input off. Local verification is:
99
+
100
+ ```sh
101
+ npm ci
102
+ npm run audit
103
+ npm run release:check
104
+ ```
105
+
106
+ None of these commands publishes. The planner can generate a non-publishing
107
+ plan with `node scripts/release-plan.mjs /absolute/path/to/candidate-directory`.
108
+
109
+ ## Recovery and old versions
110
+
111
+ A failed stage operation creates no Git tag or GitHub release. Check npm before
112
+ retrying an ambiguous outcome: a staged version reserves its version number.
113
+ Do not attempt to stage it again while awaiting approval. Approve or reject the
114
+ existing stage through npm. Rejection requires a reviewed replacement candidate.
115
+
116
+ The original release job accepts an existing public version only if integrity
117
+ matches its candidate. A conflicting archive, changed beta head or conflicting
118
+ Git tag stops recovery. Keep the beta branch at the reviewed commit until the
119
+ release is recorded. If its artifact expires, review recovery separately.
120
+
121
+ The maintainer removed the accidental `1.0.0` publication. Retain the
122
+ `0.0.0-stage` placeholder until `0.1.0-beta.1` is publicly available and verified.
123
+ With explicit authorization, remove that exact placeholder version and check
124
+ remaining versions and tags. Never unpublish the whole package. npm's unpublish
125
+ policy still applies; deleted versions cannot be reused.
126
+ See [npm's policy](https://docs.npmjs.com/policies/unpublish/).
127
+
128
+ ## Security and platform limits
129
+
130
+ The runtime package has no npm dependencies or advisory exceptions. The
131
+ release-tool tree has bounded, executable advisory exceptions expiring November
132
+ 9, 2026; it is not vulnerability-free. The privileged job does not install that
133
+ tree. See [release security](release-security.md).
134
+
135
+ Doppler is the only built-in cloud provider. Fresh native browser login has not
136
+ been verified end to end, Linux credential storage has mock coverage, and
137
+ Windows native login/storage is not implemented. Explicit tokens and existing
138
+ CLI credentials remain supported. Commands require explicit opt-in. Dotenvx
139
+ ciphertext is left unchanged. See [Security](../SECURITY.md).
140
+
141
+ Sources: [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/),
142
+ [staged publishing](https://docs.npmjs.com/cli/v11/commands/npm-stage/),
143
+ [semantic-release branching](https://semantic-release.org/foundation/workflow-configuration/).