diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 2cf00d5..5d20654 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -41,6 +41,7 @@ jobs: POSTGRES_USER: test POSTGRES_PASSWORD: test SECRET: test + STEAM_API_KEY: test HOST: localhost - name: Check site is available run: curl --fail --silent --show-error --max-time 5 --retry 5 --retry-delay 0 --retry-max-time 30 --retry-all-errors "http://localhost:3000/" || exit 1 diff --git a/Makefile b/Makefile deleted file mode 100644 index acac206..0000000 --- a/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -PORT?=80 -ifeq ($(CODESPACES), true) - HOST="$(CODESPACE_NAME)-$(PORT).$(GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN)" -else - HOST="localhost" -endif -POSTGRES_USER?="postgres" -POSTGRES_PASSWORD?="postgres" - -.PHONY: check -check: - @echo "HOST=$(HOST)" - @echo "PORT=$(PORT)" - @echo "POSTGRES_USER=$(POSTGRES_USER)" - @echo "POSTGRES_USER=$(POSTGRES_USER)" - @echo "STEAM_API_KEY=$(STEAM_API_KEY)" - @echo "SECRET=$(SECRET)" - -.PHONY: check_key -check_key: -ifeq ($(STEAM_API_KEY),) - @echo "MUST DECLARE STEAM_API_KEY" - exit 1 -else - exit 0 -endif - -.PHONY: check_secret -check_secret: -ifeq ($(SECRET),) - @echo "MUST DECLARE SECRET" - exit 1 -else - exit 0 -endif - -.PHONY: build -build: - docker-compose build - -.PHONY: run -run: check_key check_secret - HOST="$(HOST)" \ - PORT="$(PORT)" \ - POSTGRES_USER="$(POSTGRES_USER)" \ - POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" \ - STEAM_API_KEY="$(STEAM_API_KEY)" \ - SECRET="$(SECRET)" \ - docker-compose up --build diff --git a/README.md b/README.md index 61bcb9f..e3a0a32 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,11 @@ npm start To run with Docker Compose (automatically handles migrations and seeds): ```sh -make build -make run +npm run docker:build +npm run docker:run ``` -`make run` requires `STEAM_API_KEY` and `SECRET` to be set. Docker Compose reads `.env` automatically, so you can use the same file for both local and Compose workflows. +`npm run docker:run` requires `STEAM_API_KEY` and `SECRET` to be set. Docker Compose reads `.env` automatically, so you can use the same file for both local and Compose workflows. ## Database migrations @@ -113,9 +113,9 @@ src/ seed-cli.ts # CLI entry point for seeding seed-data.ts # Seed data definitions server.ts # Application entry point +scripts/ # Node.js helper scripts for npm run commands Dockerfile docker-compose.yml # Development-oriented quickstart compose file -Makefile # Docker Compose wrapper package.json package-lock.json ``` diff --git a/package.json b/package.json index b9fa6e8..c916c2b 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "start": "node dist/server.js", "build": "tsc", "migrate": "node dist/migrate-cli.js", - "seed": "node dist/seed-cli.js" + "seed": "node dist/seed-cli.js", + "docker:build": "docker compose build", + "docker:run": "node scripts/docker-run.js" }, "repository": { "type": "git", diff --git a/scripts/docker-run.js b/scripts/docker-run.js new file mode 100644 index 0000000..46fcfda --- /dev/null +++ b/scripts/docker-run.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +'use strict' + +const { spawnSync } = require('child_process') + +const port = process.env.PORT || '80' + +const host = process.env.CODESPACES === 'true' + ? `${process.env.CODESPACE_NAME}-${port}.${process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}` + : (process.env.HOST || 'localhost') + +const result = spawnSync('docker', ['compose', 'up', '--build'], { + env: { + ...process.env, + HOST: host, + PORT: port, + POSTGRES_USER: process.env.POSTGRES_USER || 'postgres', + POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD || 'postgres', + }, + stdio: 'inherit', + shell: false, +}) + +if (result.error) { + console.error('Failed to start docker compose:', result.error.message) + process.exit(1) +} + +process.exit(result.status ?? 1) diff --git a/src/config.ts b/src/config.ts index 196264e..c131969 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,15 +1,21 @@ /* eslint-disable no-process-env */ import type { Config } from './types/config' +function requireEnv(name: string): string { + const value = process.env[name] + if (!value) throw new Error(`Missing required environment variable: ${name}`) + return value +} + function config(): Config { return { server: { host: process.env.HOST || 'localhost', port: process.env.PORT || 80, https_port: process.env.HTTPS_PORT || 443, - steam_api_key: process.env.STEAM_API_KEY || false, + steam_api_key: requireEnv('STEAM_API_KEY'), website_url: (!process.env.WEBSITE_URL) ? false : ('//' + process.env.WEBSITE_URL), - secret: process.env.SECRET || false, + secret: requireEnv('SECRET'), }, db: { user: process.env.POSTGRES_USER || process.env.PGUSER || false, diff --git a/src/server.ts b/src/server.ts index 173567b..76c47a9 100644 --- a/src/server.ts +++ b/src/server.ts @@ -120,7 +120,7 @@ const teamPages = teamsFactory(templates, season, division, team, team_player, p const app = express() const { generateCsrfToken, doubleCsrfProtection } = doubleCsrf({ - getSecret: () => config.server.secret as string, + getSecret: () => config.server.secret, getSessionIdentifier: (req) => req.session.id, cookieName: '_csrf', cookieOptions: { @@ -147,7 +147,7 @@ const realm = 'http' + (config.server.host === 'localhost' ? '' : 's') + '://' + passport.use('steam', new passportSteam.Strategy({ returnURL: realm + '/auth/steam/return', realm: realm, - apiKey: config.server.steam_api_key as string + apiKey: config.server.steam_api_key }, (identifier, profile, done) => { auth.createUser(profile).then(() => { done(null, { id: identifier, profile: profile }) @@ -159,7 +159,7 @@ passport.use('steam', new passportSteam.Strategy({ app.set('trust proxy', true) app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })) -app.use(cookieParser(config.server.secret as string)) +app.use(cookieParser(config.server.secret)) app.use(session({ store: new PGStore({ pool: pool, @@ -169,7 +169,7 @@ app.use(session({ secure: true, maxAge: 1000 * 60 * 60 * 24 * 7 }, - secret: config.server.secret as string, + secret: config.server.secret, resave: true, saveUninitialized: true })) diff --git a/src/types/config.ts b/src/types/config.ts index adf6e57..cd8692c 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -6,9 +6,9 @@ export interface ServerConfig { host: string port: number | string https_port: number | string - steam_api_key: string | false + steam_api_key: string website_url: string | false - secret: string | false + secret: string } export interface DbConfig {