@ciqol/resenv 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +189 -0
- package/LICENSE +21 -0
- package/README.md +243 -0
- package/SECURITY.md +74 -0
- package/assert-safe-diagnostics.cjs +15 -0
- package/bin/resenv.cjs +91 -0
- package/bin/resenv.mjs +1 -0
- package/commands.cjs +85 -0
- package/docs/build.md +136 -0
- package/docs/dependencies.md +505 -0
- package/docs/doppler.md +146 -0
- package/docs/maintainer-handoff.md +112 -0
- package/docs/maturity.md +61 -0
- package/docs/public-readiness.md +138 -0
- package/docs/release-security.md +134 -0
- package/docs/releasing.md +143 -0
- package/docs/security-exceptions.json +139 -0
- package/docs/security-performance-review.md +150 -0
- package/docs/validation.md +700 -0
- package/doppler/auth.cjs +125 -0
- package/doppler/bridge.cjs +66 -0
- package/doppler/http.cjs +77 -0
- package/doppler/references.cjs +28 -0
- package/doppler/resolve.cjs +58 -0
- package/doppler/system.cjs +99 -0
- package/doppler-worker.cjs +28 -0
- package/doppler-worker.mjs +1 -0
- package/errors.cjs +12 -0
- package/index.cjs +88 -0
- package/index.d.cts +1 -0
- package/index.d.mts +1 -0
- package/index.mjs +1 -0
- package/package.json +89 -0
- package/preload.cjs +31 -0
- package/resolve-commands.cjs +5 -0
- package/resolve-commands.d.cts +1 -0
- package/resolve-commands.d.mts +1 -0
- package/resolve-commands.mjs +1 -0
- package/resolve-doppler.cjs +4 -0
- package/resolve-doppler.d.cts +1 -0
- package/resolve-doppler.d.mts +1 -0
- package/resolve-doppler.mjs +1 -0
- package/resolve.cjs +5 -0
- package/resolve.d.cts +1 -0
- package/resolve.d.mts +1 -0
- package/resolve.mjs +1 -0
- package/types/bin/resenv.d.ts +2 -0
- package/types/src/assert-safe-diagnostics.d.ts +1 -0
- package/types/src/commands.d.ts +4 -0
- package/types/src/doppler/auth.d.ts +19 -0
- package/types/src/doppler/bridge.d.ts +4 -0
- package/types/src/doppler/http.d.ts +9 -0
- package/types/src/doppler/references.d.ts +9 -0
- package/types/src/doppler/resolve.d.ts +9 -0
- package/types/src/doppler/system.d.ts +24 -0
- package/types/src/doppler-worker.d.ts +1 -0
- package/types/src/errors.d.ts +5 -0
- package/types/src/index.d.ts +7 -0
- package/types/src/preload.d.ts +4 -0
- package/types/src/resolve-commands.d.ts +1 -0
- package/types/src/resolve-doppler.d.ts +1 -0
- package/types/src/resolve.d.ts +1 -0
- package/types/src/types.d.ts +9 -0
- package/types/src/values.d.ts +5 -0
- package/values.cjs +20 -0
|
@@ -0,0 +1,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.
|
package/docs/maturity.md
ADDED
|
@@ -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/).
|