Skip to content
Open
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
75 changes: 75 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Issue #34 — Dependabot configuration.
# Covers every workspace in this monorepo: Backend, Frontend, analytics (npm),
# contracts (cargo), and GitHub Actions (when workflows are added).
# Weekly cadence + grouped minor/patch PRs keeps churn low.
# All opened PRs are tagged with 'dependencies' + 'automation' per spec.
version: 2
updates:
- package-ecosystem: "npm"
directory: "/Backend"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "automation"
groups:
backend-minor-and-patch:
applies-to: version-updates
patterns: ["*"]
update-types: ["minor", "patch"]

- package-ecosystem: "npm"
directory: "/Frontend"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "automation"
groups:
frontend-minor-and-patch:
applies-to: version-updates
patterns: ["*"]
update-types: ["minor", "patch"]

- package-ecosystem: "npm"
directory: "/analytics"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "automation"
groups:
analytics-minor-and-patch:
applies-to: version-updates
patterns: ["*"]
update-types: ["minor", "patch"]

- package-ecosystem: "cargo"
directory: "/contracts"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "automation"
groups:
contracts-minor-and-patch:
applies-to: version-updates
patterns: ["*"]
update-types: ["minor", "patch"]

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
labels:
- "dependencies"
- "automation"
41 changes: 22 additions & 19 deletions Backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
"cookie-parser": "^1.4.7",
"csrf": "^3.1.0",
"ethers": "^6.15.0",
"helmet": "^8.2.0",
"pg": "^8.13.3",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"sanitize-html": "^2.13.1",
"typeorm": "^0.3.28"
},
"devDependencies": {
Expand Down
5 changes: 5 additions & 0 deletions Backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ import { AppService } from './app.service';
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
// Issue #16: NestJS ThrottlerModule tracks by `req.ip` by default,
// giving us per-IP rate limiting out of the box. Global ThrottlerGuard
// (APP_GUARD below) applies the default. Per-route differentiation
// is handled by controllers using @Throttle / @SkipThrottle
// (e.g., GistsController).
useFactory: (config: ConfigService) => [
{
ttl: config.get<number>('THROTTLE_TTL_MS', 60000),
Expand Down
16 changes: 13 additions & 3 deletions Backend/src/config/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@ export default () => ({
port: parseInt(process.env.PORT ?? '3000', 10),
nodeEnv: process.env.NODE_ENV ?? 'development',

// Issue #2: do NOT default credentials. They must be provided via env.
// Failing loud here prevents secret leakage via a hardcoded fallback.
database: {
host: process.env.DATABASE_HOST ?? 'localhost',
port: parseInt(process.env.DATABASE_PORT ?? '5432', 10),
user: process.env.DATABASE_USER ?? 'gist',
password: process.env.DATABASE_PASSWORD ?? 'gist',
name: process.env.DATABASE_NAME ?? 'gist',
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
name: process.env.DATABASE_NAME,
},

// Issue #16: per-IP rate limiting differentiation.
// THROTTLE_TTL_MS / THROTTLE_LIMIT are consumed by AppModule's
// ThrottlerModule.forRootAsync — keep keys flat (process.env flood).
throttle: {
ttlMs: parseInt(process.env.THROTTLE_TTL_MS ?? '60000', 10),
limit: parseInt(process.env.THROTTLE_LIMIT ?? '10', 10),
},

soroban: {
Expand Down
8 changes: 5 additions & 3 deletions Backend/src/database/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import 'dotenv/config';
import { DataSource } from 'typeorm';
import { Gist } from '../gists/entities/gist.entity';

// Issue #2: removed hardcoded 'gist' default for credentials.
// TypeORM CLI commands will fail loud if these env vars are missing.
const AppDataSource = new DataSource({
type: 'postgres',
host: process.env.DATABASE_HOST ?? 'localhost',
port: Number(process.env.DATABASE_PORT ?? 5432),
username: process.env.DATABASE_USER ?? 'gist',
password: process.env.DATABASE_PASSWORD ?? 'gist',
database: process.env.DATABASE_NAME ?? 'gist',
username: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
entities: [Gist],
migrations: [__dirname + '/migrations/*{.ts,.js}'],
synchronize: false,
Expand Down
8 changes: 5 additions & 3 deletions Backend/src/database/database.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import { Gist } from '../gists/entities/gist.entity';
type: 'postgres',
host: config.get<string>('DATABASE_HOST', 'localhost'),
port: config.get<number>('DATABASE_PORT', 5432),
username: config.get<string>('DATABASE_USER', 'gist'),
password: config.get<string>('DATABASE_PASSWORD', 'gist'),
database: config.get<string>('DATABASE_NAME', 'gist'),
// Issue #2: no hardcoded credentials. Missing env fails
// loud at boot via the underlying pg driver.
username: config.get<string>('DATABASE_USER'),
password: config.get<string>('DATABASE_PASSWORD'),
database: config.get<string>('DATABASE_NAME'),
entities: [Gist],
migrations: [__dirname + '/migrations/*{.ts,.js}'],
migrationsRun: false,
Expand Down
34 changes: 33 additions & 1 deletion Backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { NestExpressApplication } from '@nestjs/platform-express';
import helmet from 'helmet';
import { AppModule } from './app.module';
import { LoggingInterceptor } from './common/interceptors/logging.interceptor';
import {
Expand All @@ -12,7 +14,37 @@ import {
import { compressionMiddleware } from './common/middleware/compression.middleware';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Issue #2: preflight — required DB env vars must be set; no silent
// hardcoded fallback. Fails loud at boot with an actionable message.
const requiredDbEnvVars = ['DATABASE_USER', 'DATABASE_PASSWORD', 'DATABASE_NAME'];
for (const key of requiredDbEnvVars) {
if (!process.env[key]) {
throw new Error(
`Missing required environment variable: ${key}. ` +
`Set it in Backend/.env or your environment (see Backend/.env.example).`,
);
}
}

const app = await NestFactory.create<NestExpressApplication>(AppModule);

// Issue #16 — Trust X-Forwarded-For so per-IP rate limiting works
// behind reverse proxies (ALB, nginx, Cloudflare). Defaults to
// 'loopback' for local/dev; override via TRUST_PROXY env var
// (e.g. 'true', 'false', or a comma-separated list of CIDRs).
// MUST be set before the ThrottlerGuard binds `req.ip`.
const trustProxy = process.env.TRUST_PROXY ?? 'loopback';
app.set('trust proxy', trustProxy);

// Issue #11 — Helmet HTTP security headers.
// Applied before any other middleware so every response carries them.
app.use(helmet());

// Issue #15 — Request body size limit (default 100kb).
// Override with MAX_BODY_SIZE env var if needed.
const bodyLimit = process.env.MAX_BODY_SIZE ?? '100kb';
app.useBodyParser('json', { limit: bodyLimit });
app.useBodyParser('urlencoded', { limit: bodyLimit, extended: true });

// Issue 43 — Response compression.
// Registered first so the middleware wraps `res.write` / `res.end`
Expand Down
15 changes: 10 additions & 5 deletions Backend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
// Issue #22: enable strict TS checks (low-risk subset to avoid
// breaking NestJS DI bootstrapping in a single batch PR).
// strictPropertyInitialization stays off for now — many NestJS
// services rely on constructor injection without explicit `!`.
"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"strictPropertyInitialization": false
},
"ts-node": {
"require": ["tsconfig-paths/register"],
Expand Down
9 changes: 6 additions & 3 deletions infrastructure/ci/dependency-updates.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
name: Dependency Update Automation
name: Dependency Update Automation (deprecated)

# Issue #34: This workflow is superseded by Dependabot at `.github/dependabot.yml`.
# Both would run on the same weekly cadence, producing duplicate PRs.
# Disabled by default; manual `workflow_dispatch` is retained for emergencies
# (e.g. when Dependabot is paused or fails for a given ecosystem).
on:
schedule:
- cron: "0 6 * * 1"
schedule: []
workflow_dispatch:

permissions:
Expand Down
Loading