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 @@
26.5.1
26.12.1
29 changes: 21 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
# syntax=docker/dockerfile:1.7

ARG NODE_VERSION=26.5.1
ARG NODE_VERSION=26.12.1
ARG PNPM_VERSION=11.15.1

FROM node:${NODE_VERSION}-alpine AS external-clients
FROM node:${NODE_VERSION}-alpine3.24@sha256:40cd011b55415bc894e45b02fdd5a5dfde056921b7d23a64c74f80497af48797 AS external-clients

RUN apk upgrade --no-cache \
&& apk add --no-cache ca-certificates git openssh-client

RUN git clone --depth 1 https://github.com/topcoder-platform/challenge-api-v6.git /clients/challenge-api-v6 \
&& git clone --depth 1 https://github.com/topcoder-platform/identity-api-v6.git /clients/identity-api-v6 \
&& git clone --depth 1 https://github.com/topcoder-platform/member-api-v6.git /clients/member-api-v6 \
&& git clone --depth 1 https://github.com/topcoder-platform/resource-api-v6.git /clients/resource-api-v6 \
# Freeze each external generated client at the default-branch revision reviewed
# with this dependency refresh; builds must not silently follow moving HEADs.
RUN for client_spec in \
challenge-api-v6:61636c78e0703c36386838dc7b86876849fe79cf \
identity-api-v6:c7abbb671adbecbc13a969780364e9516e320faf \
member-api-v6:a8014c191e5bd2b7ce1d81620d63436628817ade \
resource-api-v6:f61b88f0f2dc90a9664136b740d8635faa0387fd; do \
client_repo="${client_spec%:*}"; client_revision="${client_spec#*:}"; \
git init -q "/clients/${client_repo}" \
&& git -C "/clients/${client_repo}" remote add origin "https://github.com/topcoder-platform/${client_repo}.git" \
&& git -C "/clients/${client_repo}" fetch --depth 1 origin "${client_revision}" \
&& git -C "/clients/${client_repo}" checkout --detach FETCH_HEAD || exit 1; \
done \
&& identity_client_version="$(node -p "require('/clients/identity-api-v6/packages/identity-prisma-client/package.json').version")" \
&& npm install --prefix /tmp/identity-engines --no-save "@prisma/engines@${identity_client_version}" \
&& cp /tmp/identity-engines/node_modules/@prisma/engines/libquery_engine-linux-musl-openssl-3.0.x.so.node \
/clients/identity-api-v6/packages/identity-prisma-client/

FROM node:${NODE_VERSION}-alpine AS build
FROM node:${NODE_VERSION}-alpine3.24@sha256:40cd011b55415bc894e45b02fdd5a5dfde056921b7d23a64c74f80497af48797 AS build
ARG PNPM_VERSION

RUN apk upgrade --no-cache
WORKDIR /usr/src/app
ENV NODE_PATH=/usr/src/app/node_modules
RUN npm install --global pnpm@${PNPM_VERSION}

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY tools ./tools
RUN pnpm install --frozen-lockfile

COPY . .
Expand All @@ -34,12 +45,14 @@ COPY --from=external-clients /clients/member-api-v6/packages/member-prisma-clien
COPY --from=external-clients /clients/resource-api-v6/packages/resources-prisma-client /usr/src/resource-api-v6/packages/resources-prisma-client
RUN DATABASE_URL="postgresql://user:password@localhost:5432/forums" pnpm prisma:generate \
&& pnpm lint \
&& pnpm test --runInBand \
&& pnpm test:dependency-compat \
&& pnpm build \
&& rm -rf node_modules \
&& pnpm install --prod --frozen-lockfile --ignore-scripts \
&& pnpm rebuild @prisma/engines

FROM alpine:3.24 AS production
FROM alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a AS production

ARG NODE_VERSION
# Alpine replaces old APK patch versions. Keep the configured Node major while
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ but the `/moderation` endpoints require administrator role access for humans or

## Development

The supported local and container runtime is Node.js 26.5.1 with pnpm 11.15.1.
The supported local and container runtime is Node.js 26.12.1 with pnpm 11.15.1.
The checked-in `.nvmrc` selects the required Node.js release.
The production image installs Alpine's dynamically linked Node.js package and
runs as an unprivileged application user so patched system libraries are used at
Expand Down Expand Up @@ -356,3 +356,16 @@ Node major. The runtime keeps Alpine's dynamically linked Node and system
libraries. Existing non-root users and application entrypoints are preserved.
Build stages using a versioned official Node image retain their configured
version, and pnpm build arguments are explicitly declared in the consuming stage.

## Security dependency checks

The November 2026 update pins the reviewed core library and external Prisma
client revisions, upgrades Prisma to 7.10.1, and patches vulnerable transitive
dependencies. Legacy glob tooling uses the tested adapter in
`tools/minimatch-compat`; run `pnpm test:dependency-compat` after updating it.
Docker builds run lint, unit tests, and compatibility checks.

Run the PostgreSQL integration suites with `TZ=UTC`, matching the container;
the importer compares timestamp-without-time-zone columns in UTC. Provide the
existing `options=-c%20search_path%3Dforums%2Cpublic` URL parameter when testing
raw forum queries against a database whose default search path is `public`.
65 changes: 33 additions & 32 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,48 @@
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"import:vanilla:public": "node dist/scripts/public-vanilla-import.js"
"import:vanilla:public": "node dist/scripts/public-vanilla-import.js",
"test:dependency-compat": "node --test tools/minimatch-compat/index.test.cjs"
},
"dependencies": {
"@nestjs/common": "^11.1.28",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.1.28",
"@nestjs/platform-express": "^11.1.28",
"@nestjs/swagger": "^11.4.6",
"@prisma/adapter-pg": "^7.9.0",
"@prisma/client": "^7.9.0",
"@prisma/client-runtime-utils": "^7.9.0",
"@nestjs/common": "^11.2.8",
"@nestjs/config": "^4.0.4",
"@nestjs/core": "^11.2.8",
"@nestjs/platform-express": "^11.2.8",
"@nestjs/swagger": "^11.4.7",
"@prisma/adapter-pg": "^7.10.1",
"@prisma/client": "^7.10.1",
"@prisma/client-runtime-utils": "^7.10.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.4",
"express": "^5.1.0",
"mysql2": "^3.14.3",
"pg": "^8.16.3",
"prisma": "^7.9.0",
"express": "^5.3.0",
"mysql2": "^3.24.6",
"pg": "^8.23.1",
"prisma": "^7.10.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2",
"tc-core-library-js": "github:topcoder-platform/tc-core-library-js#v4.0.0-rc.1"
"tc-core-library-js": "https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/a25576b8b038211d1ba910eca2d900271ba6659d"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.12",
"@nestjs/testing": "^11.1.28",
"@types/express": "^5.0.0",
"@types/jest": "^29.5.8",
"@types/node": "^22.10.7",
"@types/pg": "^8.15.5",
"@types/supertest": "^6.0.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^16.3.0",
"@eslint/eslintrc": "^3.3.7",
"@eslint/js": "^9.39.5",
"@nestjs/cli": "^11.0.24",
"@nestjs/testing": "^11.2.8",
"@types/express": "^5.0.6",
"@types/jest": "^29.5.14",
"@types/node": "^26.6.6",
"@types/pg": "^8.23.1",
"@types/supertest": "^6.0.3",
"eslint": "^9.39.5",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.7",
"globals": "^16.5.0",
"jest": "^29.7.0",
"prettier": "^3.4.2",
"supertest": "^7.0.0",
"ts-jest": "^29.1.1",
"prettier": "^3.9.10",
"supertest": "^7.3.1",
"ts-jest": "^29.4.15",
"ts-node": "^10.9.2",
"typescript": "^5.7.3",
"typescript-eslint": "^8.38.0"
"typescript": "^5.9.3",
"typescript-eslint": "^8.72.1"
}
}
2 changes: 1 addition & 1 deletion packages/forums-prisma-client/client.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
module.exports = { ...require('.') }
2 changes: 1 addition & 1 deletion packages/forums-prisma-client/default.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

/* !!! This is code generated by Prisma. Do not edit directly. !!!
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
module.exports = { ...require('#main-entry-point') }
Loading
Loading