@lenne.tech/nest-server 11.26.3 → 11.27.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/FRAMEWORK-API.md +3 -2
- package/dist/core/common/helpers/meta.helper.d.ts +13 -0
- package/dist/core/common/helpers/meta.helper.js +18 -0
- package/dist/core/common/helpers/meta.helper.js.map +1 -0
- package/dist/core/common/interfaces/server-options.interface.d.ts +4 -0
- package/dist/core/modules/health-check/core-health-check.service.js +5 -0
- package/dist/core/modules/health-check/core-health-check.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/migration-guides/11.26.3-to-11.27.0.md +249 -0
- package/migration-guides/11.27.0-to-11.27.1.md +256 -0
- package/package.json +22 -6
- package/src/core/common/helpers/meta.helper.ts +69 -0
- package/src/core/common/interfaces/server-options.interface.ts +29 -0
- package/src/core/modules/health-check/core-health-check.service.ts +13 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Migration Guide: 11.26.3 → 11.27.0
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
|----------|---------|
|
|
7
|
+
| **Breaking Changes** | None |
|
|
8
|
+
| **New Features** | Build-identity helpers (`getCommit()` / `getBuildInfo()`); the running build's commit / version / environment is now surfaced in the `/health-check` response; new `IServerOptions.version` and `healthCheck.configs.build` options |
|
|
9
|
+
| **Bugfixes** | None |
|
|
10
|
+
| **Migration Effort** | 0 minutes (automatic) — the health check exposes the build identity on update. ~5 minutes optional to bake the real commit SHA into your image so it stops reporting `unknown` |
|
|
11
|
+
|
|
12
|
+
This release makes the **running build identifiable at runtime**. App and API are
|
|
13
|
+
typically deployed together but versioned independently, so a partial / stale
|
|
14
|
+
rollout (one container older than the other) is otherwise hard to spot. The build
|
|
15
|
+
**commit SHA** is the drift detector: bake the same CI commit into both images and
|
|
16
|
+
compare them.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Quick Migration
|
|
21
|
+
|
|
22
|
+
No code changes required. The build indicator is added to `/health-check`
|
|
23
|
+
automatically — the commit just reports `'unknown'` until you bake it into the
|
|
24
|
+
image (see [Adopt the full drift detection](#adopt-the-full-drift-detection-optional)).
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Update package
|
|
28
|
+
pnpm add @lenne.tech/nest-server@11.27.0
|
|
29
|
+
|
|
30
|
+
# Verify build
|
|
31
|
+
pnpm run build
|
|
32
|
+
|
|
33
|
+
# Run tests
|
|
34
|
+
pnpm test
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## What's New in 11.27.0
|
|
40
|
+
|
|
41
|
+
### 1. Build-identity helpers: `getCommit()` / `getBuildInfo()`
|
|
42
|
+
|
|
43
|
+
Two pure helpers are now exported from `@lenne.tech/nest-server`. They give every
|
|
44
|
+
project ONE canonical way to resolve which build is running, instead of re-reading
|
|
45
|
+
`process.env` ad hoc.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { getBuildInfo, getCommit } from '@lenne.tech/nest-server';
|
|
49
|
+
|
|
50
|
+
// Commit SHA the build was produced from. Reads process.env.APP_VERSION_COMMIT
|
|
51
|
+
// (override the var name if you like), falling back to 'unknown' for local builds.
|
|
52
|
+
getCommit(); // → 'a1b2c3d…' or 'unknown'
|
|
53
|
+
getCommit('MY_COMMIT_ENV'); // → reads a custom env var
|
|
54
|
+
|
|
55
|
+
// Full build identity, ready to surface via a meta / info endpoint.
|
|
56
|
+
getBuildInfo({ env: 'production', version: '1.4.0' });
|
|
57
|
+
// → { commit: 'a1b2c3d…', env: 'production', version: '1.4.0' }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Also exported: `BuildInfo` (type), `DEFAULT_COMMIT_ENV` (`'APP_VERSION_COMMIT'`),
|
|
61
|
+
`UNKNOWN_COMMIT` (`'unknown'`).
|
|
62
|
+
|
|
63
|
+
### 2. Build identity in the `/health-check` response
|
|
64
|
+
|
|
65
|
+
The core health check now includes a `build` indicator. It is **always** reported
|
|
66
|
+
with status `up`, so it surfaces under `info`/`details` **without ever affecting
|
|
67
|
+
the overall health status**. Ops and monitoring can detect a drifted / stale
|
|
68
|
+
container, not just the admin UI.
|
|
69
|
+
|
|
70
|
+
```jsonc
|
|
71
|
+
// GET /health-check (and the GraphQL `healthCheck` query)
|
|
72
|
+
{
|
|
73
|
+
"status": "ok",
|
|
74
|
+
"info": {
|
|
75
|
+
"database": { "status": "up" },
|
|
76
|
+
"build": {
|
|
77
|
+
"status": "up",
|
|
78
|
+
"commit": "a1b2c3d4e5f6…", // process.env.APP_VERSION_COMMIT, or "unknown"
|
|
79
|
+
"env": "production", // from IServerOptions.env
|
|
80
|
+
"version": "1.4.0" // from IServerOptions.version (see #3), or "unknown"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"details": { "database": { "status": "up" }, "build": { /* same */ } }
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Opt out (e.g. if you prefer to keep build info out of an unauthenticated probe):
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// config.env.ts
|
|
91
|
+
healthCheck: {
|
|
92
|
+
configs: {
|
|
93
|
+
build: { enabled: false },
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3. New `IServerOptions.version` config field
|
|
99
|
+
|
|
100
|
+
So the health-check build indicator can report your app version, set it from your
|
|
101
|
+
`package.json` / `meta.json`:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// config.env.ts
|
|
105
|
+
import metaData = require('./meta.json');
|
|
106
|
+
|
|
107
|
+
const base: Partial<IServerOptions> = {
|
|
108
|
+
env: envName,
|
|
109
|
+
version: metaData.version, // ← surfaced in /health-check build identity
|
|
110
|
+
// …
|
|
111
|
+
};
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Without it, the indicator reports `version: 'unknown'` — harmless, but less useful.
|
|
115
|
+
|
|
116
|
+
### Adopt the full drift detection (optional)
|
|
117
|
+
|
|
118
|
+
For the end-to-end "is App on the same build as API?" check, the commit must be
|
|
119
|
+
baked into the image at build time and exposed publicly. The
|
|
120
|
+
[nest-server-starter](https://github.com/lenneTech/nest-server-starter) reference
|
|
121
|
+
implementation wires all three layers:
|
|
122
|
+
|
|
123
|
+
1. **Image** — bake the commit at build time:
|
|
124
|
+
```dockerfile
|
|
125
|
+
# In the runtime stage (the API reads it at runtime):
|
|
126
|
+
ARG APP_VERSION_COMMIT=unknown
|
|
127
|
+
ENV APP_VERSION_COMMIT=$APP_VERSION_COMMIT
|
|
128
|
+
```
|
|
129
|
+
2. **Build arg** — feed the CI commit SHA:
|
|
130
|
+
```yaml
|
|
131
|
+
# docker-compose.yml
|
|
132
|
+
build:
|
|
133
|
+
args:
|
|
134
|
+
APP_VERSION_COMMIT: ${IMAGE_TAG:-unknown} # IMAGE_TAG = CI_COMMIT_SHA
|
|
135
|
+
```
|
|
136
|
+
3. **Public endpoint** — the starter's `meta` module exposes `GET /meta`
|
|
137
|
+
(`S_EVERYONE`) returning `{ version, commit, environment, package, title }`,
|
|
138
|
+
so the frontend can read the API commit and compare it against its own.
|
|
139
|
+
|
|
140
|
+
The contract end to end:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
CI commit SHA → IMAGE_TAG (CI) → APP_VERSION_COMMIT build arg (compose)
|
|
144
|
+
→ ENV in the image (Dockerfile) → getCommit() → /health-check + /meta
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Versions (semver) are per-component and may legitimately differ — only the
|
|
148
|
+
**commit** is compared. Local builds without CI report `unknown`, which clients
|
|
149
|
+
use to suppress the drift warning.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Breaking Changes
|
|
154
|
+
|
|
155
|
+
None. All additions are backward compatible.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Compatibility Notes
|
|
160
|
+
|
|
161
|
+
- **Existing `/health-check` consumers:** The response gains one extra key
|
|
162
|
+
(`build`) under `info` and `details`. `status` is unchanged and the `build`
|
|
163
|
+
indicator can never flip the overall status to `error` (it always reports `up`).
|
|
164
|
+
Only consumers that assert the *exact* set of keys need updating; disable it via
|
|
165
|
+
`healthCheck.configs.build.enabled: false` if you must keep the old shape.
|
|
166
|
+
- **GraphQL `healthCheck` query:** `info`/`details` are `JSON` scalars, so the new
|
|
167
|
+
`build` key flows through without any schema change.
|
|
168
|
+
- **`IServerOptions`:** `version` and `healthCheck.configs.build` are new optional
|
|
169
|
+
fields. Existing configs compile unchanged.
|
|
170
|
+
- **Commit resolution:** If you previously read `process.env.APP_VERSION_COMMIT`
|
|
171
|
+
yourself, you can switch to `getCommit()` for the identical result (with the
|
|
172
|
+
`'unknown'` fallback) — optional, not required.
|
|
173
|
+
- **Vendor-mode consumers:** The same additions land in
|
|
174
|
+
`src/core/common/helpers/meta.helper.ts` and
|
|
175
|
+
`src/core/modules/health-check/core-health-check.service.ts`. Sync via the
|
|
176
|
+
vendored-core updater. No flatten-fix change required.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Verifying
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Boot the API and read the health check
|
|
184
|
+
pnpm start &
|
|
185
|
+
curl -s http://localhost:3000/health-check | jq '.info.build'
|
|
186
|
+
# → { "status": "up", "commit": "unknown", "env": "local", "version": "1.4.0" }
|
|
187
|
+
|
|
188
|
+
# After a CI build that passes APP_VERSION_COMMIT, "commit" is the real SHA:
|
|
189
|
+
APP_VERSION_COMMIT=$(git rev-parse HEAD) pnpm start &
|
|
190
|
+
curl -s http://localhost:3000/health-check | jq '.info.build.commit'
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
A unit test for the helpers ships in `tests/unit/meta-helper.spec.ts`.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Troubleshooting
|
|
198
|
+
|
|
199
|
+
### `commit` is always `"unknown"`
|
|
200
|
+
|
|
201
|
+
The build arg never reached the process. Check, in order:
|
|
202
|
+
|
|
203
|
+
1. CI passes the commit SHA into the build (`IMAGE_TAG` / `APP_VERSION_COMMIT`).
|
|
204
|
+
2. `docker-compose.yml` forwards it as a `build.args.APP_VERSION_COMMIT`.
|
|
205
|
+
3. The **API** Dockerfile declares `ARG`/`ENV APP_VERSION_COMMIT` in the **runtime
|
|
206
|
+
stage** (the API reads it at runtime, not build time).
|
|
207
|
+
4. For a frontend, the commit must be set **before** the bundler runs (e.g. Nuxt
|
|
208
|
+
freezes `runtimeConfig.public` at build time) — there the `ARG`/`ENV` belongs in
|
|
209
|
+
the **build stage**, not the runtime stage.
|
|
210
|
+
|
|
211
|
+
### `version` is `"unknown"`
|
|
212
|
+
|
|
213
|
+
Set `IServerOptions.version` (see [#3](#3-new-iserveroptionsversion-config-field)).
|
|
214
|
+
The health check reads `config.version`; nothing else populates it.
|
|
215
|
+
|
|
216
|
+
### I don't want build info on an unauthenticated endpoint
|
|
217
|
+
|
|
218
|
+
`/health-check` is `S_EVERYONE` by design (probes need it). Disable just the build
|
|
219
|
+
indicator with `healthCheck.configs.build.enabled: false`, or restrict the route
|
|
220
|
+
in your project.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Module Documentation
|
|
225
|
+
|
|
226
|
+
### Core Common — build-identity helpers
|
|
227
|
+
|
|
228
|
+
- **Helpers:** `src/core/common/helpers/meta.helper.ts` (`getCommit`, `getBuildInfo`, `BuildInfo`, `DEFAULT_COMMIT_ENV`, `UNKNOWN_COMMIT`)
|
|
229
|
+
- **Unit tests:** `tests/unit/meta-helper.spec.ts`
|
|
230
|
+
|
|
231
|
+
### Core Health Check
|
|
232
|
+
|
|
233
|
+
- **Service:** `src/core/modules/health-check/core-health-check.service.ts` (build indicator)
|
|
234
|
+
- **Controller / Resolver:** `src/core/modules/health-check/core-health-check.controller.ts`, `core-health-check.resolver.ts`
|
|
235
|
+
- **Config:** `IServerOptions.healthCheck.configs.build` + `IServerOptions.version` in `src/core/common/interfaces/server-options.interface.ts`
|
|
236
|
+
|
|
237
|
+
### Reference implementation (full drift detection)
|
|
238
|
+
|
|
239
|
+
- **API meta module + Dockerfile build arg:** [nest-server-starter](https://github.com/lenneTech/nest-server-starter) — `src/server/modules/meta/` exposes `GET /meta` with `commit`
|
|
240
|
+
- **Frontend system page:** [nuxt-base-starter](https://github.com/lenneTech/nuxt-base-starter) — `/app/admin/system` compares App vs. API builds
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## References
|
|
245
|
+
|
|
246
|
+
- [Migration Guide 11.26.2 → 11.26.3](./11.26.2-to-11.26.3.md) — Previous release (OpenAPI enum `$ref` fix)
|
|
247
|
+
- [nest-server-starter](https://github.com/lenneTech/nest-server-starter) (reference implementation)
|
|
248
|
+
- [nuxt-base-starter](https://github.com/lenneTech/nuxt-base-starter) (frontend drift detection)
|
|
249
|
+
- [lt-monorepo](https://github.com/lenneTech/lt-monorepo) — `docker-compose.yml` + CI wiring for the `APP_VERSION_COMMIT` contract
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Migration Guide: 11.27.0 → 11.27.1
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
| Category | Details |
|
|
6
|
+
|----------|---------|
|
|
7
|
+
| **Breaking Changes** | None |
|
|
8
|
+
| **New Features** | None |
|
|
9
|
+
| **Bugfixes** | None |
|
|
10
|
+
| **Security** | Security maintenance pass: 7 new / refreshed `pnpm.overrides` entries forcing transitive dependencies onto CVE-patched versions — `ws`, `form-data`, `vite`, `hono`, `nodemailer`, `multer`, `js-yaml`. All framework-internal; consumer projects only need to mirror the entries if their own `pnpm audit` flags the same advisories. |
|
|
11
|
+
| **Tooling** | New `scripts/check.mjs` — a quiet, report-driven wrapper around the `check` pipeline (audit + format + lint + test + build + server-start). Replaces the inline shell chain in `pnpm run check`; the original chain is preserved as `pnpm run check:raw`. Repo-internal only — not shipped via npm. |
|
|
12
|
+
| **Migration Effort** | 0 minutes (automatic) — `pnpm update` is enough. ~5 minutes optional to mirror the security overrides into your own project's `package.json`. |
|
|
13
|
+
|
|
14
|
+
This is a **maintenance release**. No source-code or config changes are required.
|
|
15
|
+
The bulk of the work hardens transitive-dependency advisories that `pnpm audit`
|
|
16
|
+
flagged on the framework after `npm`/`pnpm` resolved newer CVEs against 11.27.0's
|
|
17
|
+
lockfile. A new in-repo wrapper around the `check` script trims runtime noise and
|
|
18
|
+
auto-fixes every fixable format/lint finding.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick Migration
|
|
23
|
+
|
|
24
|
+
No code changes required.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Update package
|
|
28
|
+
pnpm add @lenne.tech/nest-server@11.27.1
|
|
29
|
+
|
|
30
|
+
# Verify build
|
|
31
|
+
pnpm run build
|
|
32
|
+
|
|
33
|
+
# Run tests
|
|
34
|
+
pnpm test
|
|
35
|
+
|
|
36
|
+
# Re-run audit to confirm advisories cleared
|
|
37
|
+
pnpm audit
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## What's New in 11.27.1
|
|
43
|
+
|
|
44
|
+
### 1. Security overrides refreshed
|
|
45
|
+
|
|
46
|
+
`pnpm.overrides` in this repo's `package.json` gained / refreshed seven entries.
|
|
47
|
+
Every override targets a **fixed version** (per `.claude/rules/package-management.md`
|
|
48
|
+
override rules — no `>=` / `^` / `~`):
|
|
49
|
+
|
|
50
|
+
| Package | Override | Advisory | Pulled in via |
|
|
51
|
+
|---------|----------|----------|---------------|
|
|
52
|
+
| `ws` (8.x) | `8.21.0` (was `8.20.1`) | Memory exhaustion DoS + uninitialized memory disclosure (`GHSA-96hv-2xvq-fx4p`) | `@nestjs/graphql` |
|
|
53
|
+
| `ws` (7.x) | `7.5.11` *(new)* | Memory exhaustion DoS in `ws@7.x` (`GHSA-96hv-2xvq-fx4p`) | `@nestjs/graphql > subscriptions-transport-ws` |
|
|
54
|
+
| `form-data` | `4.0.6` *(new)* | CRLF injection via unescaped multipart field names / filenames (`GHSA-hmw2-7cc7-3qxx`) | `@getbrevo/brevo > axios`, `node-mailjet > axios` |
|
|
55
|
+
| `vite` | `8.0.16` *(new)* | `fs.deny` bypass on Windows alternate paths + file-read CVEs | `better-auth > vitest` |
|
|
56
|
+
| `hono` | `4.12.25` *(new)* | Prototype pollution, `bodyLimit` / `Vary` bypass, JWT `NumericDate` (multiple CVEs `<4.12.25`) | `@nestjs/terminus > prisma > @prisma/dev` |
|
|
57
|
+
| `nodemailer` | `9.0.1` *(new)* | Email / header-injection CVEs `<9.0.1` | direct dependency (forced major bump for transitive consumers — see note) |
|
|
58
|
+
| `multer` | `2.2.0` *(new)* | Unhandled multipart errors / DoS `<2.2.0` | `@nestjs/platform-express` |
|
|
59
|
+
| `js-yaml` | `4.2.0` *(new)* | Special-character handling / prototype pollution (patched in `4.2.0`; `4.1.2` was never published) | `@nestjs/swagger` |
|
|
60
|
+
|
|
61
|
+
> **Why an override per package and not a direct upgrade?**
|
|
62
|
+
> `pnpm.overrides` is the safest single-knob fix when the vulnerable copy comes
|
|
63
|
+
> in transitively. Every entry uses the same `Pkg@<patched>` → `<patched>` selector
|
|
64
|
+
> as the existing overrides, keeps the fix scoped to the vulnerable range, and is
|
|
65
|
+
> documented in the `//overrides` comment block above the actual entries.
|
|
66
|
+
|
|
67
|
+
#### Heads-up: `nodemailer` and `multer`
|
|
68
|
+
|
|
69
|
+
The framework's **direct** `dependencies` still pin `nodemailer@8.0.8` and
|
|
70
|
+
`multer@2.1.1` to preserve the historical lockfile reference. The overrides
|
|
71
|
+
above force these onto `9.0.1` / `2.2.0` at install time. The framework's own
|
|
72
|
+
`EmailService` and `multer*` file-helper usage was verified against the bumped
|
|
73
|
+
versions — no API surface changes affect framework code.
|
|
74
|
+
|
|
75
|
+
If your project uses `nodemailer` or `multer` directly:
|
|
76
|
+
|
|
77
|
+
- **`nodemailer 8 → 9`** is a major bump (Node.js `>=18`, dropped legacy
|
|
78
|
+
`OAuth2` client constructor, `customCustomHeaders` / `customHeaders` casing
|
|
79
|
+
cleanup, `BURL`/`stub-transport` removals). Skim the
|
|
80
|
+
[nodemailer 9 release notes](https://github.com/nodemailer/nodemailer/releases)
|
|
81
|
+
if you call `nodemailer.createTransport` / `sendMail` from project code.
|
|
82
|
+
- **`multer 1 → 2`** has been on `2.x` for two releases now; the `2.1 → 2.2`
|
|
83
|
+
jump is a patch-grade bump and needs no action.
|
|
84
|
+
|
|
85
|
+
#### Why your project may still see CVEs after upgrading
|
|
86
|
+
|
|
87
|
+
`pnpm.overrides` is **scoped to the package that declares it**. The framework's
|
|
88
|
+
overrides do **not** propagate into consumer projects' lockfiles. If your own
|
|
89
|
+
`pnpm audit` flags `ws / form-data / vite / hono / nodemailer / multer / js-yaml`,
|
|
90
|
+
mirror the entries into your project's `package.json`:
|
|
91
|
+
|
|
92
|
+
```jsonc
|
|
93
|
+
// projects/api/package.json (or your project's package.json)
|
|
94
|
+
"pnpm": {
|
|
95
|
+
"//overrides": {
|
|
96
|
+
"ws@>=8.0.0 <8.21.0": "Security: Memory exhaustion DoS + uninitialized memory disclosure (GHSA-96hv-2xvq-fx4p) - transitive via @nestjs/graphql",
|
|
97
|
+
"ws@>=7.0.0 <7.5.11": "Security: Memory exhaustion DoS in ws 7.x (GHSA-96hv-2xvq-fx4p) - transitive via @nestjs/graphql>subscriptions-transport-ws",
|
|
98
|
+
"form-data@<4.0.6": "Security: CRLF injection (GHSA-hmw2-7cc7-3qxx) - transitive via axios",
|
|
99
|
+
"vite@>=8.0.0 <8.0.16": "Security: fs.deny bypass on Windows + file-read CVEs - transitive via better-auth>vitest",
|
|
100
|
+
"hono@<4.12.25": "Security: multiple CVEs <4.12.25 - transitive via @nestjs/terminus>prisma>@prisma/dev",
|
|
101
|
+
"nodemailer@<9.0.1": "Security: email/header injection CVEs <9.0.1",
|
|
102
|
+
"multer@<2.2.0": "Security: unhandled multipart errors / DoS <2.2.0 - transitive via @nestjs/platform-express",
|
|
103
|
+
"js-yaml@<4.2.0": "Security: special-character handling / prototype pollution (patched 4.2.0; 4.1.2 unpublished) - transitive via @nestjs/swagger"
|
|
104
|
+
},
|
|
105
|
+
"overrides": {
|
|
106
|
+
"ws@>=8.0.0 <8.21.0": "8.21.0",
|
|
107
|
+
"ws@>=7.0.0 <7.5.11": "7.5.11",
|
|
108
|
+
"form-data@<4.0.6": "4.0.6",
|
|
109
|
+
"vite@>=8.0.0 <8.0.16": "8.0.16",
|
|
110
|
+
"hono@<4.12.25": "4.12.25",
|
|
111
|
+
"nodemailer@<9.0.1": "9.0.1",
|
|
112
|
+
"multer@<2.2.0": "2.2.0",
|
|
113
|
+
"js-yaml@<4.2.0": "4.2.0"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
After adding, run `pnpm install && pnpm audit && pnpm test`.
|
|
119
|
+
|
|
120
|
+
### 2. New `scripts/check.mjs` wrapper (repo-internal)
|
|
121
|
+
|
|
122
|
+
The `check` script now points at a Node-based wrapper:
|
|
123
|
+
|
|
124
|
+
```diff
|
|
125
|
+
- "check": "pnpm audit && pnpm run format:check && pnpm run lint && pnpm test && pnpm run build && bash scripts/check-server-start.sh",
|
|
126
|
+
+ "check": "node scripts/check.mjs",
|
|
127
|
+
+ "check:raw": "pnpm audit && pnpm run format:check && pnpm run lint && pnpm test && pnpm run build && bash scripts/check-server-start.sh",
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
What changes when you run `pnpm run check`:
|
|
131
|
+
|
|
132
|
+
- **One status line per running step** instead of streaming every tool's output
|
|
133
|
+
— the spinner shows the currently running step and elapsed time.
|
|
134
|
+
- **Aborts on the first failing step** and prints the captured reason instead
|
|
135
|
+
of letting later steps spam the log.
|
|
136
|
+
- **Auto-fixes every fixable finding** — `oxfmt` writes, `oxlint --fix` runs in
|
|
137
|
+
place. Only non-fixable lint errors remain and fail the run. Bypass with
|
|
138
|
+
`--no-fix` for a read-only gate.
|
|
139
|
+
- **Final report** lists every executed step with key metrics (audit
|
|
140
|
+
vulnerabilities per severity, Vitest passed/failed/files, lint
|
|
141
|
+
errors/warnings, etc.).
|
|
142
|
+
|
|
143
|
+
Available flags:
|
|
144
|
+
|
|
145
|
+
| Flag | Purpose |
|
|
146
|
+
|------|---------|
|
|
147
|
+
| `--verbose` / `-v` | Stream the full tool output live (deep debugging) |
|
|
148
|
+
| `--sequential` / `--seq` | Run projects one after another (default: parallel) |
|
|
149
|
+
| `--no-fix` | Read-only gate — do not auto-fix format / lint |
|
|
150
|
+
| `--project=<substr>` | Restrict to matching workspace projects (repeatable) |
|
|
151
|
+
|
|
152
|
+
The original raw command remains available as `pnpm run check:raw` if you
|
|
153
|
+
need the previous behaviour (CI logs, exact ordering, no auto-fix).
|
|
154
|
+
|
|
155
|
+
> **Consumer impact:** None. `scripts/` is **not** part of the npm package's
|
|
156
|
+
> `files` list (see `package.json` `files`: `dist`, `src`, `bin`, `CLAUDE.md`,
|
|
157
|
+
> `FRAMEWORK-API.md`, `.claude/rules`, `docs`, `migration-guides`). The wrapper
|
|
158
|
+
> is repo-internal tooling for framework development — but you may copy it
|
|
159
|
+
> verbatim into your own project's `scripts/` directory if you want the same
|
|
160
|
+
> behaviour for your `check` pipeline. It auto-discovers each workspace
|
|
161
|
+
> project's `check` chain via `package.json`, so no further adaptation is
|
|
162
|
+
> needed.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Breaking Changes
|
|
167
|
+
|
|
168
|
+
None.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Compatibility Notes
|
|
173
|
+
|
|
174
|
+
- **`IServerOptions` / `CoreModule.forRoot()`:** unchanged.
|
|
175
|
+
- **`FRAMEWORK-API.md`:** regenerated for the new version stamp only — no API
|
|
176
|
+
surface differences vs. 11.27.0.
|
|
177
|
+
- **`config.env.ts`:** no new fields, no deprecations.
|
|
178
|
+
- **Vendor-mode consumers:** nothing to sync. The override changes live in
|
|
179
|
+
`package.json` at the **repo root**, which is excluded from
|
|
180
|
+
`convertCloneToVendored`. The `scripts/check.mjs` wrapper also lives outside
|
|
181
|
+
`src/core/`, so vendor projects keep their existing `check` setup.
|
|
182
|
+
- **Custom controllers / resolvers extending Core* classes:** no impact —
|
|
183
|
+
no Core method signatures changed.
|
|
184
|
+
- **Tests:** all 1751 framework tests pass against the new overrides.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Verifying
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# 1. Update + install
|
|
192
|
+
pnpm add @lenne.tech/nest-server@11.27.1
|
|
193
|
+
pnpm install
|
|
194
|
+
|
|
195
|
+
# 2. Confirm advisories cleared (or only show unaffected residuals)
|
|
196
|
+
pnpm audit
|
|
197
|
+
|
|
198
|
+
# 3. Smoke-test the new check wrapper (only relevant in this repo)
|
|
199
|
+
pnpm run check # quiet, report-driven
|
|
200
|
+
pnpm run check:raw # original chain, full noise
|
|
201
|
+
|
|
202
|
+
# 4. Tests + build
|
|
203
|
+
pnpm test
|
|
204
|
+
pnpm run build
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Troubleshooting
|
|
210
|
+
|
|
211
|
+
### `pnpm audit` in my consumer project still reports `ws` / `vite` / `nodemailer` ...
|
|
212
|
+
|
|
213
|
+
Expected — `pnpm.overrides` is scoped to the declaring package. Mirror the
|
|
214
|
+
entries listed under [Why your project may still see CVEs after upgrading](#why-your-project-may-still-see-cves-after-upgrading).
|
|
215
|
+
|
|
216
|
+
### Tests fail with `nodemailer.createTransport is not a function` or similar
|
|
217
|
+
|
|
218
|
+
You're calling a `nodemailer` API removed in v9 (the override forces `9.0.1`).
|
|
219
|
+
Check the [v9 release notes](https://github.com/nodemailer/nodemailer/releases)
|
|
220
|
+
and update the call site, or pin your project to `nodemailer@8.x` explicitly
|
|
221
|
+
(*not* recommended — keeps the CVE open).
|
|
222
|
+
|
|
223
|
+
### `pnpm run check` hangs or doesn't show output
|
|
224
|
+
|
|
225
|
+
The wrapper hides per-step output by design. Re-run with `--verbose`:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
pnpm run check -- --verbose
|
|
229
|
+
# or
|
|
230
|
+
node scripts/check.mjs --verbose
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
To restore the previous behaviour entirely, use `pnpm run check:raw`.
|
|
234
|
+
|
|
235
|
+
### I want the old `check` behaviour back in CI
|
|
236
|
+
|
|
237
|
+
Switch your CI job to invoke `pnpm run check:raw` — it is an exact preservation
|
|
238
|
+
of the inline chain that was on `check` in 11.27.0.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Module Documentation
|
|
243
|
+
|
|
244
|
+
No module documentation changes in this release. Reference documentation:
|
|
245
|
+
|
|
246
|
+
- **Package management rules:** [`.claude/rules/package-management.md`](../.claude/rules/package-management.md) — fixed-version overrides only, never ranges
|
|
247
|
+
- **Framework compatibility:** [`.claude/rules/framework-compatibility.md`](../.claude/rules/framework-compatibility.md) — what ships in the npm package
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## References
|
|
252
|
+
|
|
253
|
+
- [Migration Guide 11.26.3 → 11.27.0](./11.26.3-to-11.27.0.md) — Previous release (build identity in health check)
|
|
254
|
+
- [nest-server-starter](https://github.com/lenneTech/nest-server-starter) — reference implementation
|
|
255
|
+
- [nodemailer v9 release notes](https://github.com/nodemailer/nodemailer/releases) — for projects calling `nodemailer` directly
|
|
256
|
+
- [multer v2 changelog](https://github.com/expressjs/multer/releases) — for projects calling `multer` directly
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.27.1",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"build:pack": "pnpm pack && echo 'use file:/ROOT_PATH_TO_TGZ_FILE to integrate the package'",
|
|
23
23
|
"build:dev": "pnpm run build",
|
|
24
24
|
"c": "pnpm run check",
|
|
25
|
-
"check": "
|
|
25
|
+
"check": "node scripts/check.mjs",
|
|
26
|
+
"check:raw": "pnpm audit && pnpm run format:check && pnpm run lint && pnpm test && pnpm run build && bash scripts/check-server-start.sh",
|
|
26
27
|
"check:fix": "pnpm install && pnpm audit --fix && pnpm run format && pnpm run lint:fix && pnpm test && pnpm run build && bash scripts/check-server-start.sh",
|
|
27
28
|
"check:naf": "pnpm install && pnpm run format && pnpm run lint:fix && pnpm test && pnpm run build && bash scripts/check-server-start.sh",
|
|
28
29
|
"cf": "pnpm run check:fix",
|
|
@@ -200,13 +201,20 @@
|
|
|
200
201
|
"path-to-regexp@>=8.0.0 <8.4.2": "Security: ReDoS (GHSA-rhx6-c78j-4q9w) - transitive via express>router",
|
|
201
202
|
"kysely@>=0.26.0 <0.28.17": "Security: JSON-path traversal injection via unsanitized input (SQL injection) - transitive via better-auth>@better-auth/passkey>@better-auth/core",
|
|
202
203
|
"@protobufjs/utf8@<=1.1.0": "Security: overlong UTF-8 decoding - transitive via @apollo/server>@apollo/usage-reporting-protobuf",
|
|
203
|
-
"ws@>=8.0.0 <8.
|
|
204
|
+
"ws@>=8.0.0 <8.21.0": "Security: Memory exhaustion DoS + uninitialized memory disclosure (GHSA-96hv-2xvq-fx4p) - transitive via @nestjs/graphql",
|
|
205
|
+
"ws@>=7.0.0 <7.5.11": "Security: Memory exhaustion DoS in ws 7.x (GHSA-96hv-2xvq-fx4p) - transitive via @nestjs/graphql>subscriptions-transport-ws",
|
|
204
206
|
"qs@>=6.11.1 <=6.15.1": "Security: remotely triggerable DoS in qs.stringify with comma-format arrays (GHSA-q8mj-m7cp-5q26) - transitive via @compodoc/compodoc>body-parser",
|
|
205
207
|
"lodash@>=4.0.0 <4.18.0": "Security: CVE in lodash@4.17.x - transitive via @nestjs/graphql. 4.18.1 is the latest patched version",
|
|
206
208
|
"defu@<=6.1.6": "Security: prototype pollution via __proto__ key - transitive via better-auth",
|
|
207
209
|
"follow-redirects@<=1.15.11": "Security: Custom Authentication Headers leak on cross-domain redirect (GHSA-r4q5-vmmm-2653) - transitive via axios>@getbrevo/brevo and axios>node-mailjet",
|
|
208
210
|
"uuid@<14.0.0": "Security: Missing buffer bounds check in v3/v5/v6 (GHSA-w5hq-g745-h8pq) - transitive via @compodoc/compodoc and @compodoc/compodoc>@compodoc/live-server>http-auth",
|
|
209
|
-
"postcss@<8.5.10": "Security: XSS via Unescaped </style> in CSS Stringify Output (GHSA-qx2v-qp2m-jg93) - transitive via vite. Remove when vite ships with postcss>=8.5.10"
|
|
211
|
+
"postcss@<8.5.10": "Security: XSS via Unescaped </style> in CSS Stringify Output (GHSA-qx2v-qp2m-jg93) - transitive via vite. Remove when vite ships with postcss>=8.5.10",
|
|
212
|
+
"form-data@<4.0.6": "Security: CRLF injection via unescaped multipart field names/filenames (GHSA-hmw2-7cc7-3qxx) - transitive via @getbrevo/brevo>axios and node-mailjet>axios",
|
|
213
|
+
"vite@>=8.0.0 <8.0.16": "Security: fs.deny bypass on Windows alternate paths + file read CVEs - transitive via better-auth>vitest",
|
|
214
|
+
"hono@<4.12.25": "Security: multiple CVEs <4.12.25 (prototype pollution, bodyLimit/Vary bypass, JWT NumericDate) - transitive via @nestjs/terminus>prisma>@prisma/dev",
|
|
215
|
+
"nodemailer@<9.0.1": "Security: email/header injection CVEs <9.0.1 - direct dependency",
|
|
216
|
+
"multer@<2.2.0": "Security: unhandled multipart errors / DoS <2.2.0 - transitive via @nestjs/platform-express",
|
|
217
|
+
"js-yaml@<4.2.0": "Security: special-character handling / prototype pollution (patched in 4.2.0; 4.1.2 was never published) - transitive via @nestjs/swagger"
|
|
210
218
|
},
|
|
211
219
|
"overrides": {
|
|
212
220
|
"axios@<1.16.0": "1.16.0",
|
|
@@ -226,13 +234,21 @@
|
|
|
226
234
|
"path-to-regexp@>=8.0.0 <8.4.2": "8.4.2",
|
|
227
235
|
"kysely@>=0.26.0 <0.28.17": "0.28.17",
|
|
228
236
|
"@protobufjs/utf8@<=1.1.0": "1.1.1",
|
|
229
|
-
"ws@>=8.0.0 <8.
|
|
237
|
+
"ws@>=8.0.0 <8.21.0": "8.21.0",
|
|
238
|
+
"ws@>=7.0.0 <7.5.11": "7.5.11",
|
|
230
239
|
"qs@>=6.11.1 <=6.15.1": "6.15.2",
|
|
231
240
|
"lodash@>=4.0.0 <4.18.0": "4.18.1",
|
|
232
241
|
"defu@<=6.1.6": "6.1.7",
|
|
233
242
|
"follow-redirects@<=1.15.11": "1.16.0",
|
|
234
243
|
"uuid@<14.0.0": "14.0.0",
|
|
235
|
-
"postcss@<8.5.10": "8.5.12"
|
|
244
|
+
"postcss@<8.5.10": "8.5.12",
|
|
245
|
+
"esbuild@>=0.17.0 <0.28.1": "0.28.1",
|
|
246
|
+
"form-data@<4.0.6": "4.0.6",
|
|
247
|
+
"vite@>=8.0.0 <8.0.16": "8.0.16",
|
|
248
|
+
"hono@<4.12.25": "4.12.25",
|
|
249
|
+
"nodemailer@<9.0.1": "9.0.1",
|
|
250
|
+
"multer@<2.2.0": "2.2.0",
|
|
251
|
+
"js-yaml@<4.2.0": "4.2.0"
|
|
236
252
|
},
|
|
237
253
|
"//peerDependencyRules": "allowedVersions: deps lag behind our newer majors (graphql-upload wants @types/express@^4, the deprecated apollo playground plugin wants @apollo/server@^4) — both work with our v5. ignoreMissing: browser-only vis-network peers pulled in transitively via yuml-diagram (server-side UML generation never renders, so these are not needed).",
|
|
238
254
|
"peerDependencyRules": {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build identity helpers.
|
|
3
|
+
*
|
|
4
|
+
* A deployed image's exact build is identified by its git commit SHA, baked in
|
|
5
|
+
* at build time via an environment variable (default `APP_VERSION_COMMIT`, fed
|
|
6
|
+
* from the CI commit SHA — the same value typically used as the image tag).
|
|
7
|
+
*
|
|
8
|
+
* Unlike the semantic `version` (a rarely-bumped semver that may legitimately
|
|
9
|
+
* differ between an API and its frontend, since each is versioned independently)
|
|
10
|
+
* the commit SHA uniquely pins the exact running build. A frontend and backend
|
|
11
|
+
* deployed together bake the SAME commit, but each reads its own at runtime — so
|
|
12
|
+
* comparing them detects a drifted / stale container after a partial rollout.
|
|
13
|
+
*
|
|
14
|
+
* @see getCommit
|
|
15
|
+
* @see getBuildInfo
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Default environment variable the build commit SHA is baked into. */
|
|
19
|
+
export const DEFAULT_COMMIT_ENV = 'APP_VERSION_COMMIT';
|
|
20
|
+
|
|
21
|
+
/** Defined value returned when no commit could be resolved. */
|
|
22
|
+
export const UNKNOWN_COMMIT = 'unknown';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build identity of the running process.
|
|
26
|
+
*/
|
|
27
|
+
export interface BuildInfo {
|
|
28
|
+
/** Git commit SHA the build was produced from, or `'unknown'`. */
|
|
29
|
+
commit: string;
|
|
30
|
+
|
|
31
|
+
/** Environment the process runs in (e.g. `'production'`), if provided. */
|
|
32
|
+
env?: string;
|
|
33
|
+
|
|
34
|
+
/** Semantic version of the build, or `'unknown'`. */
|
|
35
|
+
version?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the git commit SHA the running build was produced from.
|
|
40
|
+
*
|
|
41
|
+
* Reads `process.env[envName]` (default `APP_VERSION_COMMIT`). Falls back to
|
|
42
|
+
* `'unknown'` so local / un-tagged builds still return a defined value — clients
|
|
43
|
+
* use `'unknown'` to suppress the "builds drifted" warning instead of comparing
|
|
44
|
+
* against an empty string.
|
|
45
|
+
*
|
|
46
|
+
* @param envName Name of the environment variable holding the commit SHA.
|
|
47
|
+
*/
|
|
48
|
+
export function getCommit(envName: string = DEFAULT_COMMIT_ENV): string {
|
|
49
|
+
return process.env[envName] || UNKNOWN_COMMIT;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Assemble the build identity of the running process.
|
|
54
|
+
*
|
|
55
|
+
* Combines the commit SHA (from the environment) with an optionally supplied
|
|
56
|
+
* `version` and `env`. Designed to be surfaced via a public meta / info endpoint
|
|
57
|
+
* and the health check so deployments can be compared at a glance.
|
|
58
|
+
*
|
|
59
|
+
* @param options.commitEnvName Override the env var the commit SHA is read from.
|
|
60
|
+
* @param options.env Environment label to include (e.g. from the config).
|
|
61
|
+
* @param options.version Semantic version to include (e.g. from package.json).
|
|
62
|
+
*/
|
|
63
|
+
export function getBuildInfo(options: { commitEnvName?: string; env?: string; version?: string } = {}): BuildInfo {
|
|
64
|
+
return {
|
|
65
|
+
commit: getCommit(options.commitEnvName),
|
|
66
|
+
env: options.env,
|
|
67
|
+
version: options.version || UNKNOWN_COMMIT,
|
|
68
|
+
};
|
|
69
|
+
}
|