Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/actions/build-docker-images/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ runs:
SHA_CLIENT=$(git rev-parse HEAD:packages/client)
SHA_RAILS=$(git rev-parse HEAD:packages/rails)
SHORT_SHA=$(echo "${SHA_CLIENT}_${SHA_RAILS}" | sha1sum | cut -c1-7)
elif [ "${{ inputs.package }}" == "nginx" ]; then
SHA_CLIENT=$(git rev-parse HEAD:packages/client)
SHA_NGINX=$(git rev-parse HEAD:packages/nginx)
SHORT_SHA=$(echo "${SHA_CLIENT}_${SHA_NGINX}" | sha1sum | cut -c1-7)
else
SHORT_SHA=$(git rev-parse --short HEAD:packages/${{ inputs.package }})
fi
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,7 @@ vendor/assets/bower_components/
.cursor/
.specify/
.playwright-cli

# GSRS seed data (downloaded via `make gsrs-seed-data`)
packages/gsrs/seed-data/
docker/misc/gsrs-db-init/02-gsrsdb-data.sql
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ check-unpublished-env-variables:
# β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

PFDA_SHOULD_RUN_GSRS ?= 0
GSRS_FRONTEND_DEV ?= false

# β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
# β”‚ β”‚
Expand Down Expand Up @@ -67,9 +68,12 @@ DB_WIPE_VOLUMES := db-pfda-mysql-volume
# Conditionally defined if gsrs should be included in the stack
ifneq (,$(filter-out 0,$(PFDA_SHOULD_RUN_GSRS)))
DOCKER_COMPOSE_FILE_FLAGS := $(DOCKER_COMPOSE_FILE_FLAGS) -f $(EXTERNAL_DOCKER_COMPOSE_FILE)
SERVICES := $(SERVICES) gsrs gsrsdb
SERVICES := $(SERVICES) gsrs gsrs-nginx gsrsdb
DB_WIPE_SERVICES := $(DB_WIPE_SERVICES) gsrsdb
DB_WIPE_VOLUMES := $(DB_WIPE_VOLUMES) db-gsrs-mariadb-volume
ifeq (true,$(GSRS_FRONTEND_DEV))
DOCKER_COMPOSE_FILE_FLAGS := $(DOCKER_COMPOSE_FILE_FLAGS) --profile frontend-dev
endif
endif

# Recursive `=` so DOCKER_COMPOSE_FILE_FLAGS is re-expanded at every call
Expand All @@ -90,7 +94,14 @@ prepare-db:
$(COMPOSE) run -T --rm --no-deps --build -e PFDA_DB_INIT_ONLY=1 web
prepare-db-test:
$(COMPOSE) up --build $(PREPARE_DB_TEST_SERVICES)
gsrs-seed-data:
./packages/gsrs/scripts/fetch-seed-data.sh
run:
ifneq (0,$(PFDA_SHOULD_RUN_GSRS))
ifneq (,$(PFDA_SHOULD_RUN_GSRS))
@mkdir -p packages/gsrs/seed-data/ginas.ix
endif
endif
$(COMPOSE) up --build
stop:
$(COMPOSE) down
Expand Down
39 changes: 39 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Security Policy

## Reporting Security Vulnerabilities

The U.S. Food and Drug Administration (FDA) takes security vulnerabilities seriously. If you believe you have found a security vulnerability in this repository, please report it to us through coordinated disclosure.

**Please do NOT report security vulnerabilities through public GitHub issues, discussions, or pull requests.**

---

## How to Report

FDA follows the HHS Vulnerability Disclosure Policy. Submit your report through the official HHS reporting portal:

- **HHS Vulnerability Disclosure Policy:** [https://www.hhs.gov/vulnerability-disclosure-policy/index.html]
- **Submit a Report:** [https://hhs.responsibledisclosure.com]

### Contact

For general security questions or concerns about FDA systems, contact:
- **Repository Maintainer:** precisionfda@fda.hhs.gov

---
## Security Best Practices for Contributors

When contributing to this repository:

- Follow the principle of least privilege
- Validate and sanitize all inputs
- Use parameterized queries for database access
- Keep dependencies up to date
- Never commit secrets, API keys, or credentials
- Review security advisories for dependencies

---

**Disclaimer:** This repository contains code developed for research, regulatory science, or public health purposes. The code is provided "as-is" without warranty. Use in production systems should follow your organization's security assessment processes.

**Last Updated:** June 09, 2026
20 changes: 13 additions & 7 deletions docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ SKIP_DB_SETUP=0
NODEJS_DB_POLLING_INTERVAL=5

# When 0, Nest dev runs without --watch (faster container stops). Default 1 (watch enabled).
NODE_DEV_WATCH=1
NODE_DEV_WATCH=0

# URL - nodejs API url
NODE_API_URL=https://host.docker.internal:3001
# URL - ruby API url
RUBY_API_URL=https://host.docker.internal:5012
DOCS_URL=http://host.docker.internal:4040
# for native node
# Upstream URLs for the nginx container (Docker Compose service names, not host ports).
# Do NOT use host.docker.internal here β€” host port 3001 is often occupied by a local
# Node/Vite process speaking plain HTTP, which causes SSL handshake failures (502).
NODE_API_URL=https://nodejs-api:3001
RUBY_API_URL=https://web:3000
DOCS_URL=http://docs:4040

RECAPTCHA_SITE_KEY=NEED_A_KEY_4_TEST

# VITE_OUT_DIR=dist
# Only when running Node/Rails natively on the host (outside Docker):
# NODE_API_URL=https://host.docker.internal:3001
# RUBY_API_URL=https://host.docker.internal:3005
6 changes: 3 additions & 3 deletions docker/base.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ services:
- ../key.pem:/key.pem
working_dir: /precision-fda
ports:
- "5012:3000"
- "3005:3000"
extra_hosts:
- "host.docker.internal:host-gateway"
entrypoint: ./docker/entrypoint/dev.entrypoint.sh
Expand All @@ -45,11 +45,10 @@ services:
args:
- FRONTEND_IMAGE_TAG=24.15.0-slim
environment:
- VITE_OUT_DIR=dist
- SKIP_FRONTEND_DEPS_SETUP=${SKIP_FRONTEND_DEPS_SETUP}
volumes:
- type: bind
source: ../packages/rails/public/packs
source: ../packages/client/dist
target: /precision-fda/dist
working_dir: /precision-fda
command: pnpm run build
Expand Down Expand Up @@ -121,5 +120,6 @@ services:
- ../cert.pem:/keys/cert.pem
- ../key.pem:/keys/key.pem
- ../packages/nginx:/etc/nginx/templates
- ../packages/client/dist:/usr/share/nginx/html:ro
ports:
- "3000:443"
8 changes: 8 additions & 0 deletions docker/dev.docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ services:
dockerfile: ./docker/images/dev.Dockerfile
environment:
- SKIP_FRONTEND_DEPS_SETUP=${SKIP_FRONTEND_DEPS_SETUP}
- VITE_OUT_DIR=dist
volumes:
- type: volume
source: vite-cache-client
Expand Down Expand Up @@ -141,3 +142,10 @@ services:
extends:
file: ./base.services.yml
service: nginx
depends_on:
nodejs-api:
condition: service_started
web:
condition: service_started
docs:
condition: service_started
20 changes: 17 additions & 3 deletions docker/external.docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
volumes:
db-gsrs-mariadb-volume:
gsrs-frontend-node-modules:

services:
web:
depends_on:
- gsrs
- gsrs-nginx
environment:
- GSRS_URL=http://gsrs:8080
- GSRS_URL=http://gsrs-nginx:80
- GSRS_ENABLED=true
nginx:
depends_on:
- gsrs-nginx
gsrs:
depends_on:
gsrsdb:
condition: service_healthy
extends:
file: ./external.services.yml
service: gsrs
gsrs-nginx:
depends_on:
- gsrs
extends:
file: ./external.services.yml
service: gsrs-nginx
gsrs-frontend-dev:
extends:
file: ./external.services.yml
service: gsrs-frontend-dev
gsrsdb:
extends:
file: ./external.services.yml
service: gsrsdb
volumes:
- db-gsrs-mariadb-volume:/var/lib/mariadb
- db-gsrs-mariadb-volume:/var/lib/mysql
62 changes: 51 additions & 11 deletions docker/external.services.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
services:
gsrs:
build:
context: ../packages/rails
dockerfile: docker/images/gsrs.Dockerfile
ports:
- "8080:8080"
context: ../packages/gsrs/web
dockerfile: Dockerfile
args:
GSRS3_MAIN_BRANCH: ${GSRS3_MAIN_BRANCH:-GSRSv3.1.2PUB}
FRONTEND_TAG: ${GSRS_FRONTEND_TAG:-pfda}
# Alias as gsrs-web so gsrs-nginx config works unchanged (matches cloud service name)
networks:
default:
aliases:
- gsrs-web
environment:
- HOST=${GSRS_HOST:-https://localhost:3000}
- GSRS_DATABASE_HOST=${GSRS_DATABASE_HOST:-gsrsdb:3306}
- GSRS_DATABASE_NAME=${GSRS_DATABASE_NAME:-ixginas_local}
- GSRS_DATABASE_USERNAME=${GSRS_DATABASE_USERNAME:-root}
- GSRS_DATABASE_PASSWORD=${GSRS_DATABASE_PASSWORD:-${GSRS_DB_ROOT_PASSWORD:-password}}
- GSRS_LOCAL_MODE=${GSRS_LOCAL_MODE:-true}
volumes:
# Lucene index; entrypoint symlinks this to /opt/gsrs/ginas.ix
- type: bind
source: ${GSRS_FRONTEND_PATH:-/dev/null}
target: /usr/local/GSRSFrontend
- type: bind
source: ${GSRS_INDEX_PATH:-/dev/null}
target: /ginas.ix
source: ${GSRS_INDEX_PATH:-../packages/gsrs/seed-data/ginas.ix}
target: /tmp/read-only-base

gsrs-nginx:
build:
context: ../packages/gsrs/nginx
depends_on:
- gsrs
environment:
- GSRS_FRONTEND_DEV=${GSRS_FRONTEND_DEV:-false}
ports:
- 8081:80

gsrsdb:
image: "mariadb:10.6.15"
tmpfs:
- /tmp
environment:
MYSQL_DATABASE: ixginas
MYSQL_DATABASE: ixginas_local
MYSQL_ROOT_PASSWORD: ${GSRS_DB_ROOT_PASSWORD:-password}
ports:
- "32900:3306"
Expand All @@ -30,4 +51,23 @@ services:
start_period: 20s
volumes:
# Script for the DB initialization (creating the tables)
- ../packages/rails/docker/misc/gsrs-db-init:/docker-entrypoint-initdb.d
- ./misc/gsrs-db-init:/docker-entrypoint-initdb.d
gsrsdb_emulated:
extends:
service: gsrsdb
image: amd64/mariadb:10.6.15

gsrs-frontend-dev:
profiles:
- frontend-dev
build:
context: ../packages/gsrs/frontend-dev
mem_limit: 6g
volumes:
- type: bind
source: ${GSRS_FRONTEND_PATH:-.}
target: /app
# Separate node_modules to avoid overwriting host's (different platform)
- gsrs-frontend-node-modules:/app/node_modules
ports:
- 4200:4200
Loading
Loading