Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v26.5.0
v26.5.1
31 changes: 16 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1

ARG NODE_VERSION=26.5.0
ARG ALPINE_VERSION=3.23
ARG NODE_VERSION=26.5.1
ARG ALPINE_VERSION=3.24

FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS build

Expand All @@ -28,8 +28,9 @@ RUN pnpm lint \
&& pnpm build \
&& pnpm prune --prod --ignore-scripts

FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS production
FROM alpine:${ALPINE_VERSION} AS production

ARG NODE_VERSION
ARG RESET_DB_ARG=false
ARG SEED_DATA_ARG=""

Expand All @@ -40,18 +41,18 @@ ENV SEED_DATA=$SEED_DATA_ARG
WORKDIR /app

RUN apk upgrade --no-cache \
&& apk add --no-cache bash openssl \
&& rm -rf /usr/local/lib/node_modules/npm \
&& rm -f /usr/local/bin/npm /usr/local/bin/npx

COPY --from=build --chown=node:node /app/dist ./dist
COPY --from=build --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/package.json ./package.json
COPY --from=build --chown=node:node /app/prisma ./prisma
COPY --from=build --chown=node:node /app/prisma.config.ts ./prisma.config.ts
COPY --from=build --chown=node:node --chmod=755 /app/appStartUp.sh ./appStartUp.sh

USER node
&& apk add --no-cache bash nodejs-current="${NODE_VERSION}-r0" openssl \
&& addgroup --system --gid 10001 app \
&& adduser --system --disabled-password --no-create-home --uid 10001 --ingroup app app

COPY --from=build --chown=app:app /app/dist ./dist
COPY --from=build --chown=app:app /app/node_modules ./node_modules
COPY --from=build --chown=app:app /app/package.json ./package.json
COPY --from=build --chown=app:app /app/prisma ./prisma
COPY --from=build --chown=app:app /app/prisma.config.ts ./prisma.config.ts
COPY --from=build --chown=app:app --chmod=755 /app/appStartUp.sh ./appStartUp.sh

USER app
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
NestJS drop-in replacement for `tc-project-service`, serving the Topcoder platform at `/v6/projects`.

[![CircleCI](https://img.shields.io/badge/CircleCI-build%20status-informational?logo=circleci)](https://circleci.com/)
![Node](https://img.shields.io/badge/node-v26.5.0-339933?logo=node.js&logoColor=white)
![Node](https://img.shields.io/badge/node-v26.5.1-339933?logo=node.js&logoColor=white)
![pnpm](https://img.shields.io/badge/pnpm-10.28.2-F69220?logo=pnpm&logoColor=white)
![Audit](https://img.shields.io/badge/production%20audit-0%20findings-brightgreen)

Expand Down Expand Up @@ -370,7 +370,7 @@ Reference source: `.env.example`.

### Prerequisites

- Node.js `v26.5.0` (`nvm use` in this project folder)
- Node.js `v26.5.1` (`nvm use` in this project folder)
- pnpm `10.28.2`
- PostgreSQL

Expand Down Expand Up @@ -437,8 +437,10 @@ Must pass before every commit per `AGENTS.md`.
## Deployment

- CI/CD: CircleCI -> AWS ECS Fargate.
- The multi-stage Docker image builds with Node 26.5.0 and copies only compiled
output, production dependencies, and Prisma migration assets into its runtime.
- The multi-stage Docker image builds with Node 26.5.1 and copies only compiled
output, production dependencies, and Prisma migration assets into its Alpine
3.24 runtime. The runtime installs the dynamically linked Alpine Node package
and does not contain npm or other package tooling.
- Container startup invokes the local Prisma CLI to deploy migrations before
replacing the shell process with `node dist/src/main`.
- Blue-green rollout strategy is documented in `docs/MIGRATION_RUNBOOK.md`.
Expand All @@ -458,14 +460,15 @@ Open findings are tracked inline with `TODO (security)` comments in source.
| `src/main.ts` | CORS returns `'*'` for requests with no `Origin` header | Low | Open - consider returning `false` for server-to-server calls |
| `src/main.ts` | Swagger UI publicly accessible with no auth in production | Medium | Open - restrict by IP or add HTTP Basic auth, or gate behind env flag |
| `src/main.ts` | Duplicate Swagger mount at `/v6/projects-api-docs` | Low (quality) | Open - consolidate to single path |
| Event publication logging | Environment-derived Kafka topics and raw client errors could reach clear-text logs | High | Resolved - log fixed operation markers and allowlisted error categories only |
| `docs/DEPENDENCIES.md` | GitHub-sourced Topcoder packages do not have a registry release stream | Low | Mitigated with immutable commit pins; external API dependencies install only their generated Prisma-client subdirectories |

## Dependency Status

Summary from `docs/DEPENDENCIES.md`:

- Production audit: no known vulnerabilities.
- Node 26.5.0, NestJS 11.1.28, Prisma 7.9.0, Axios 1.18.1,
- Node 26.5.1, NestJS 11.1.28, Prisma 7.9.0, Axios 1.18.1,
Lodash 4.18.1, qs 6.15.3, and UUID 14.0.1 are locked in the
security candidate.
- Security overrides for affected transitives are maintained in
Expand Down
28 changes: 17 additions & 11 deletions docs/DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ lineage.

Toolchain used for this verification cycle:

- Node: `v26.5.0`
- Node: `v26.5.1`
- pnpm: `10.28.2`
- Prisma CLI, client, and PostgreSQL adapter: `7.9.0`
- Verification date: `2026-07-22`
- Verification date: `2026-09-01`

Run `nvm use` from this project directory before each Node or pnpm command.
The standard verification commands are:
Expand All @@ -35,7 +35,7 @@ The remediated direct dependency set includes:

| Package group | Version |
| --- | --- |
| Node.js | 26.5.0 |
| Node.js | 26.5.1 |
| NestJS common, core, platform, and testing | 11.1.28 |
| NestJS Swagger | 11.4.6 |
| Prisma CLI, client, and PostgreSQL adapter | 7.9.0 |
Expand All @@ -49,13 +49,16 @@ The remediated direct dependency set includes:
Body Parser, Fast URI, Fast XML Parser, Hono's Node server, Multer,
Path-to-RegExp, file-type, form-data, js-yaml, brace-expansion, Handlebars, Joi,
Piscina, UUID, archive utilities, and related packages. The generated lockfile
is the authoritative record of their resolved versions.
is the authoritative record of their resolved versions. The September 2026
security refresh resolves `brace-expansion` 5.0.9, `deepmerge-ts` 8.0.0,
`fast-uri` 4.1.2, `find-my-way` 9.7.0, `js-yaml` 3.15.1/4.3.1/5.2.2, and
`valibot` 1.4.2.

Prisma 7.9.0 currently prints an upstream support-list warning under Node 26.
The four committed external generated clients also retain their existing Prisma
6.19.x runtimes. Client generation, lint, build, migrations, the primary health
query, and explicit connection queries through all four external clients are
verified with Node 26.5.0. Keep this compatibility point in deployment QA until
verified with Node 26.5.1. Keep this compatibility point in deployment QA until
the applicable Prisma support messages explicitly include Node 26.

## External Prisma clients
Expand Down Expand Up @@ -105,8 +108,9 @@ package registry would further reduce reliance on Git-hosted installation.

## Production image

The Dockerfile uses separate build and production stages on Node 26.5.0 with
Alpine 3.23. The production stage contains only:
The Dockerfile uses Node 26.5.1 for the build stage and installs Alpine's
dynamically linked Node 26.5.1 package into an Alpine 3.24 production stage.
The production stage contains only:

- compiled application output;
- production dependencies;
Expand All @@ -123,11 +127,13 @@ Update this table whenever dependency or image contents change.

| Command | Result |
| --- | --- |
| `pnpm install --frozen-lockfile` | Passed; Prisma 7.9.0 client generated |
| `pnpm install --frozen-lockfile` | Passed in the production-image build; Prisma 7.9.0 client generated |
| `pnpm audit` | Passed: 0 critical, high, moderate, low, or informational advisories |
| `pnpm lint` | Passed |
| `pnpm build` | Passed |
| `pnpm test --runInBand` | 46 of 57 suites and 360 of 375 tests passed; 10 existing event-publish mock expectations and 5 JWT fixture expectations remain stale on `dev` |
| Docker migration and health smoke test | Passed: 3 migrations applied, server remained running, and `/v6/projects/health` returned `{"checksRun":1}` |
| External generated-client query smoke | Passed for challenge, member, resource, and skills clients under Node 26.5.0 |
| Targeted project/logger tests | Passed: 2 suites and 41 tests |
| `pnpm test --runInBand` | 49 of 60 suites and 380 of 395 tests passed; the same 10 existing event-publish mock expectations and 5 JWT fixture expectations remain stale on `dev` |
| Docker build and runtime inspection | Passed: non-root UID/GID 10001, Node 26.5.1, OpenSSL 3.5.8-r0, dynamic system SSL linkage, and no npm executable |
| Docker migration and health smoke test | Not repeated locally because it requires deployment database configuration; the migration entrypoint is unchanged |
| External generated-client query smoke | Not repeated because it requires external database configuration; the generated-client pins are unchanged from the previous passing cycle |
| Trivy 0.72.0 Critical/High/Medium image scan | Passed: 0 / 0 / 0 |
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,6 @@
"node": "26.x"
},
"volta": {
"node": "26.5.0"
"node": "26.5.1"
}
}
Loading
Loading