Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c431eef
Trivy update
jmgasper Aug 5, 2026
06cc5ec
Trivy update
jmgasper Aug 5, 2026
d3b1643
fix(security): remediate September 2026 findings
jmgasper Aug 31, 2026
1661c9d
refactor: adopt shared v6 JWT and bus clients
jmgasper Oct 26, 2026
b159968
Merge pull request #14 from topcoder-platform/september2026_security
jmgasper Oct 30, 2026
e51145f
Merge pull request #15 from topcoder-platform/v6-refresh
jmgasper Oct 30, 2026
640e682
fix: allow Alpine package updates in Docker builds
jmgasper Oct 30, 2026
fb01370
Merge pull request #16 from topcoder-platform/fix/circleci-alpine-pac…
jmgasper Oct 30, 2026
9977047
fix: remediate dependency and container security findings
jmgasper Nov 2, 2026
0eab23b
Merge pull request #17 from topcoder-platform/fix/security-findings-2…
jmgasper Nov 2, 2026
b78f7cc
chore: adopt core v4.0.0-rc.2 identity denylists
jmgasper Nov 2, 2026
fe9f8da
Merge pull request #18 from topcoder-platform/chore/core-jwt-denylist…
jmgasper Nov 2, 2026
c529b93
Apply scoped OIDC deployment migration to current develop
jmgasper Nov 4, 2026
783311a
Refresh deployment suite v2.0.5 and dev review prerequisites
jmgasper Nov 4, 2026
82e71a1
Refresh deployment suite v2.0.5 and dev review prerequisites
jmgasper Nov 4, 2026
b5c9a63
Record installed dev prerequisites and production cutover readiness
jmgasper Nov 4, 2026
36bc038
Pin deployment suite v2.0.6 and enable reviewed health-check bootstrap
jmgasper Nov 4, 2026
44672e5
Merge pull request #19 from topcoder-platform/security/ecs-oidc-deplo…
jmgasper Nov 4, 2026
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
174 changes: 103 additions & 71 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,80 +1,112 @@
# Deployment migration: see deploy/MIGRATION.md before enabling either environment.
version: 2.1

parameters:
reset-db:
type: boolean
default: false
defaults: &defaults
docker:
- image: cimg/python:3.13.2-browsers
install_dependency: &install_dependency
name: Installation of build and deployment dependencies.
command: |
sudo apt update
sudo apt install -y jq python3-pip
sudo pip3 install awscli --upgrade
install_deploysuite: &install_deploysuite
name: Installation of install_deploysuite.
command: |
git clone --branch v1.4.19 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript
cp ./../buildscript/master_deploy.sh .
cp ./../buildscript/buildenv.sh .
cp ./../buildscript/awsconfiguration.sh .
cp ./../buildscript/psvar-processor.sh .

builddeploy_steps: &builddeploy_steps
- checkout
- setup_remote_docker
- run: *install_dependency
- run: *install_deploysuite
- run: docker buildx build --no-cache=true --build-arg RESET_DB_ARG=<<pipeline.parameters.reset-db>> --build-arg SEED_DATA_ARG=${DEPLOYMENT_ENVIRONMENT} -t ${APPNAME}:latest .
- run:
name: Running MasterScript.
command: |
./awsconfiguration.sh $DEPLOY_ENV
source awsenvconf
./psvar-processor.sh -t appenv -p /config/${APPNAME}/deployvar
source deployvar_env
./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -j /config/${APPNAME}/appvar,/config/common/global-appvar -i ${APPNAME} -p FARGATE

executors:
reviewed:
docker:
- image: cimg/aws@sha256:4cf3768db00ddf9bc439b8c84e8a60c11a14edf81c8baf76f74132144f8340d5
commands:
checkout-source:
steps:
- run:
name: Check out the exact public source commit over HTTPS
command: |
set -euo pipefail
[[ "$CIRCLE_SHA1" =~ ^[0-9a-f]{40}$ ]]
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null GIT_TERMINAL_PROMPT=0
git init --quiet .
git remote add origin https://github.com/topcoder-platform/groups-api-v6.git
git -c credential.helper= fetch --quiet --depth 1 origin "$CIRCLE_SHA1"
git checkout --quiet --detach FETCH_HEAD
test "$(git rev-parse HEAD)" = "$CIRCLE_SHA1"
checkout-suite:
steps:
- run:
name: Verify deployment suite v2.0.6
command: |
set -euo pipefail
git init --quiet /tmp/tc-deploy-scripts
git -C /tmp/tc-deploy-scripts remote add origin https://github.com/topcoder-platform/tc-deploy-scripts.git
git -C /tmp/tc-deploy-scripts fetch --quiet --depth 1 origin refs/tags/v2.0.6
git -C /tmp/tc-deploy-scripts checkout --quiet --detach FETCH_HEAD
test "$(git -C /tmp/tc-deploy-scripts rev-parse HEAD)" = 26aaf607463d4a271c0099854c1731214215a9c5
jobs:
# Build & Deploy against development backend
"build-dev":
!!merge <<: *defaults
environment:
DEPLOY_ENV: "DEV"
LOGICAL_ENV: "dev"
APPNAME: "groups-api-v6"
DEPLOYMENT_ENVIRONMENT: 'dev'
steps: *builddeploy_steps

"build-prod":
!!merge <<: *defaults
build:
executor: reviewed
steps:
- checkout-source
- setup_remote_docker
- checkout-suite
- run:
name: Build committed source without AWS or broker credentials
command: |
set -euo pipefail
python3 -I /tmp/tc-deploy-scripts/build_image.py --dockerfile Dockerfile --image groups-api-v6:candidate
mkdir -p /tmp/release
docker save --output /tmp/release/image.tar groups-api-v6:candidate
no_output_timeout: 30m
- persist_to_workspace:
root: /tmp/release
paths:
- image.tar
deploy:
executor: reviewed
parameters:
environment:
type: enum
enum:
- dev
- prod
environment:
DEPLOY_ENV: "PROD"
LOGICAL_ENV: "prod"
APPNAME: "groups-api-v6"
DEPLOYMENT_ENVIRONMENT: 'prod'
steps: *builddeploy_steps

DEPLOY_ENV: << parameters.environment >>
steps:
- checkout-source
- setup_remote_docker
- checkout-suite
- attach_workspace:
at: /tmp/release
- run:
name: Promote a scanned digest with repository-bound OIDC
command: |
set +x
set -euo pipefail
test -f "deploy/${DEPLOY_ENV}.json"
docker load --input /tmp/release/image.tar
python3 -I deploy/release.py "deploy/${DEPLOY_ENV}.json"
no_output_timeout: 45m
workflows:
version: 2
build:
release:
jobs:
# Development builds are executed on "develop" branch only.
- "build-dev":
context: org-global
- build
- deploy:
name: deploy-dev
environment: dev
requires:
- build
context: groups-api-v6-dev-deploy
serial-group: << pipeline.project.slug >>/deploy-dev
filters:
branches:
only: develop
tags:
ignore: /.*/
- approve-prod:
type: approval
requires:
- build
filters:
branches:
only:
- develop
- security_july_2026

# Production builds are exectuted only on tagged commits to the
# master branch.
- "build-prod":
context: org-global
only: master
tags:
ignore: /.*/
- deploy:
name: deploy-prod
environment: prod
requires:
- approve-prod
context: groups-api-v6-prod-deploy
serial-group: << pipeline.project.slug >>/deploy-prod
filters:
branches:
only:
- master
only: master
tags:
ignore: /.*/
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,17 @@
coverage
dist
node_modules

.aws
.ssh
awsenvconf
*_env
buildenvvar
.env
.env.*
!.env.example
!.env.sample
.npmrc
fetched_parameters.json
paramwithvalue.json
cli-input.json
18 changes: 14 additions & 4 deletions .github/workflows/trivy.yaml
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
name: Trivy Scanner

permissions:
actions: read
contents: read
security-events: write

on:
push:
branches:
- main
- master
- dev
- develop
pull_request:
workflow_dispatch:

jobs:
trivy-scan:
name: Use Trivy
name: Trivy SAST and SCA
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run Trivy scanner in repo mode
uses: aquasecurity/trivy-action@0.35.0
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
version: "v0.73.0"
scan-type: "fs"
scan-ref: "."
ignore-unfixed: true
format: "sarif"
output: "trivy-results.sarif"
severity: "CRITICAL,HIGH,UNKNOWN"
scanners: vuln,secret,misconfig,license
limit-severities-for-sarif: true
scanners: "vuln,secret,misconfig,license"
github-pat: ${{ secrets.GITHUB_TOKEN }}

- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: "trivy-results.sarif"
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ pids

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Infrastructure definitions and detailed AWS inventories are maintained privately.
/deploy/iam/
/deploy/*-baseline.json
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
42 changes: 28 additions & 14 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# syntax=docker/dockerfile:1.7

ARG NODE_VERSION=26.5.0
ARG NODE_VERSION=26.5.1
ARG PNPM_VERSION=11.15.1

FROM node:${NODE_VERSION}-alpine AS build
FROM node:${NODE_VERSION}-alpine3.24 AS build

ARG PNPM_VERSION

RUN apk upgrade --no-cache \
&& apk add --no-cache bash
Expand All @@ -12,30 +14,42 @@ WORKDIR /app
COPY . .
RUN npm install --global pnpm@${PNPM_VERSION}
RUN pnpm install --frozen-lockfile
RUN pnpm run test:dependency-compat
RUN pnpm run lint
RUN pnpm run build
RUN pnpm prune --prod
RUN node node_modules/prisma/build/index.js generate

FROM node:${NODE_VERSION}-alpine AS runtime
FROM alpine:3.24 AS runtime

ARG ALPINE_NODE_VERSION=26.5.1-r0
ARG OPENSSL_VERSION=3.5.8-r0

# Use Alpine's dynamically linked Node.js package so the runtime receives the
# patched system OpenSSL libraries without carrying npm or Node.js headers.
# Keep minimum patched versions while allowing Alpine repository updates.
RUN apk upgrade --no-cache \
&& apk add --no-cache bash \
&& rm -rf /usr/local/lib/node_modules/npm \
&& rm -f /usr/local/bin/npm /usr/local/bin/npx
&& apk add --no-cache \
bash \
"libcrypto3>=${OPENSSL_VERSION}" \
"libssl3>=${OPENSSL_VERSION}" \
"nodejs-current>=${ALPINE_NODE_VERSION}" \
&& addgroup -S -g 10001 app \
&& adduser -S -D -H -h /app -u 10001 -G app app

ARG RESET_DB_ARG=false
ENV RESET_DB=$RESET_DB_ARG
ARG SEED_DATA_ARG=""
ENV SEED_DATA=$SEED_DATA_ARG
ENV PRISMA_CLI_BINARY_TARGETS=linux-musl-openssl-3.0.x
ENV NODE_ENV=production

WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/prisma ./prisma
COPY --from=build /app/package.json ./package.json
COPY --from=build /app/appStartUp.sh ./appStartUp.sh
RUN chmod +x appStartUp.sh
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/prisma ./prisma
COPY --from=build --chown=app:app /app/package.json ./package.json
COPY --from=build --chown=app:app /app/appStartUp.sh ./appStartUp.sh
RUN chmod 0555 appStartUp.sh

USER app

CMD ["./appStartUp.sh"]
40 changes: 32 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

Group API built on modern frameworks for managing all group-related Topcoder needs.

Use Node.js 26.5.0 and pnpm 11.15.1. Run `nvm use` in this project before running pnpm commands.
Use Node.js 26.5.1 and pnpm 11.15.1. Run `nvm use` in this project before running pnpm commands.

The production image runs as the unprivileged `app` user. Its Alpine 3.24
runtime installs Node.js >=26.5.1 and system OpenSSL >=3.5.8 from the Alpine
repositories, allowing package updates while retaining the minimum patched
versions. The Node.js build toolchain and npm are not copied into the runtime image.

## Project setup

Expand Down Expand Up @@ -73,15 +78,11 @@ pnpm exec prisma migrate reset
curl --request POST \
--url https://auth0proxy.topcoder-dev.com/token \
--header 'content-type: application/json' \
--data '{"auth0_url": "https://topcoder-dev.auth0.com/oauth/token", "client_id":"8uHVTW2WHp8BbBPX7J0YTAwgYbYTfjsM","client_secret":"hQXGeKO-cSZ15CLBNRDGZAGRcHWay6PAR_zTQQz4YjdX7QNU7NwGoaa3YuuUYvUv","audience":"https://m2m.topcoder-dev.com/","grant_type":"client_credentials"}'
--data '{"auth0_url": "https://topcoder-dev.auth0.com/oauth/token", "client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"https://m2m.topcoder-dev.com/","grant_type":"client_credentials"}'
```

For a read-only scope M2M token, use:

```
"client_id":"dgrh9mkk8N6sWsVPFf6JqdVmjjuibowf"
"client_secret":"_6jFqIppsA3u87Tm7mRDXhX_yf8-DC2ooc5f0affjuWoRiLG1ZriHtUsMQgo61qp"
```
Obtain M2M credentials with the required scope from the approved secret store;
never commit client credentials to this repository.

- then you can use Postman to test all apis
- Swagger docs are accessible at `http://localhost:3000/api-docs`
Expand Down Expand Up @@ -116,3 +117,26 @@ For a read-only scope M2M token, use:
- API base configuration points to v6 in dev/local and v5 in prod (for backward compatibility):
- Dev: work-manager/config/constants/development.js.
- Local: work-manager/config/constants/local.js and work-manager/config/constants/local.js.

## Shared authentication and bus client (v6 refresh)

This branch uses `tc-core-library-js` **4.0.0-rc.1**. Use its named
`createJwtVerifier` / `createJwtAuthenticator`, `createM2MClient`, and
`createBusApiClient` exports for shared authentication and bus API publishing.
Service-specific roles, scopes, sessions and ownership checks remain in this service.
The former bus wrapper dependency and local JWT cryptography must not be reintroduced.

RSA verification requires an exact configured issuer and audience (`JWT_AUDIENCE`
for client tokens, `AUTH0_AUDIENCE` for machine/API tokens, or this service's explicit
issuer-policy settings). HMAC secrets must be at least 32 bytes; no default secret
is supplied. Expiry is enforced. Machine identity comes from the shared verifier,
not the presence of scopes. Supply real development credentials through the service's
existing environment configuration before deployment.

Bus publishers use `createBusApiClient(config).postEvent(event)` with the existing
event envelope and optional key. Configure `BUSAPI_URL` for v6 and the existing
OAuth credentials/token provider. The client uses bounded HTTPS requests and does
not retry POSTs automatically. Application retry/outbox behavior remains local.

See the [core migration guide](https://github.com/topcoder-platform/tc-core-library-js/blob/v4.0.0-rc.1/MIGRATION.md)
for the API mapping, compatibility requirements, and rollout scope.
Loading
Loading