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
31 changes: 31 additions & 0 deletions docs/prod-railway-runtime-secrets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Production Railway Runtime Secrets

Production Railway connection secrets must be supplied by Railway environment variables, not committed config literals.

## Required variables

Primary database:

- `DB_DSN`
- `DB_USERNAME`
- `DB_PASSWORD`

Wallet database:

- `WALLET_DB_DSN`
- `WALLET_DB_USERNAME`
- `WALLET_DB_PASSWORD`

Redis:

- `REDIS_HOSTNAME`
- `REDIS_USERNAME` when the Redis service requires a username
- `REDIS_PASSWORD`
- `REDIS_PORT` optional, defaults to `6379`
- `REDIS_DATABASE` optional, defaults to `0`

Error reporting:

- `SENTRY_DSN`

Store the real values in Railway's secret/environment UI. Keep screenshots, support evidence, and PR comments limited to variable names only.
24 changes: 12 additions & 12 deletions environments/prod-railway/common/config/main-local.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=mysql.railway.internal;dbname=railway',
'username' => 'root',
'password' => 'JImnisvcRDpKLdWpoMECoHHoCbutPhQC',
'dsn' => getenv('DB_DSN'),
'username' => getenv('DB_USERNAME'),
'password' => getenv('DB_PASSWORD'),
'charset' => 'utf8mb4',
// Enable Caching of Schema to Reduce SQL Queries
'enableSchemaCache' => true,
Expand All @@ -16,9 +16,9 @@
],
'walletDb' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=mysql-5abl.railway.internal;dbname=railway',
'username' => 'root',
'password' => 'mECIXVloEolvFJXnDTcuLGUtvbwzoCgS',
'dsn' => getenv('WALLET_DB_DSN'),
'username' => getenv('WALLET_DB_USERNAME'),
'password' => getenv('WALLET_DB_PASSWORD'),

'charset' => 'utf8',
// Enable Caching of Schema to Reduce SQL Queries
Expand All @@ -34,11 +34,11 @@
],
'redis' => [
'class' => 'yii\redis\Connection',
'hostname' => 'redis.railway.internal',
'username' => 'default',
'password' => 'VjCTsdeqMTNwmzBidlzbciDRVceiFXYS',
'port' => 6379,
'database' => 0,
'hostname' => getenv('REDIS_HOSTNAME'),
'username' => getenv('REDIS_USERNAME') ?: null,
'password' => getenv('REDIS_PASSWORD'),
'port' => getenv('REDIS_PORT') ? (int)getenv('REDIS_PORT') : 6379,
'database' => getenv('REDIS_DATABASE') ? (int)getenv('REDIS_DATABASE') : 0,
],/*
'redis' => [
'class' => 'yii\redis\Connection',
Expand Down Expand Up @@ -191,7 +191,7 @@
'targets' => [
[
'class' => 'notamedia\sentry\SentryTarget',
'dsn' => 'https://6cbd2100e1ff41e7875352655ffbf50d:e18336b09d864b29aa12aca3fbc6706c@sentry.io/168200',
'dsn' => getenv('SENTRY_DSN') ?: null,
'levels' => ['error', 'warning'],
'except' => [
'yii\web\BadRequestHttpException',
Expand Down
64 changes: 64 additions & 0 deletions tests/check-prod-railway-runtime-secrets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import re
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
CONFIG = ROOT / "environments/prod-railway/common/config/main-local.php"
DOCS = ROOT / "docs/prod-railway-runtime-secrets.md"


def require(condition, message):
if not condition:
raise SystemExit(message)


def component_block(config, component):
marker = f"'{component}' => ["
start = config.find(marker)
require(start != -1, f"Component '{component}' must exist in config.")
next_component = re.search(r"\n\s{8}'[^']+'\s*=>\s*\[", config[start + len(marker):])
end = start + len(marker) + next_component.start() if next_component else len(config)
return config[start:end]


config = CONFIG.read_text(encoding="utf-8")
docs = DOCS.read_text(encoding="utf-8")

expected_vars = [
"DB_DSN",
"DB_USERNAME",
"DB_PASSWORD",
"WALLET_DB_DSN",
"WALLET_DB_USERNAME",
"WALLET_DB_PASSWORD",
"REDIS_HOSTNAME",
"REDIS_USERNAME",
"REDIS_PASSWORD",
"REDIS_PORT",
"REDIS_DATABASE",
"SENTRY_DSN",
]

for var in expected_vars:
require(f"getenv('{var}')" in config, f"{var} must be read from the environment.")
require(f"`{var}`" in docs, f"{var} must be documented.")

for component in ("db", "walletDb"):
block = component_block(config, component)
for key in ("dsn", "username", "password"):
require(
re.search(rf"'{key}'\s*=>\s*getenv\('[A-Z0-9_]+'\)", block),
f"{component}.{key} must be env-backed.",
)

redis = component_block(config, "redis")
for key in ("hostname", "password"):
require(
re.search(rf"'{key}'\s*=>\s*getenv\('[A-Z0-9_]+'\)", redis),
f"redis.{key} must be env-backed.",
)

log = component_block(config, "log")
require("'dsn' => getenv('SENTRY_DSN') ?: null" in log, "Sentry DSN must be env-backed.")

print("Production Railway runtime secret check passed.")