Cleanup unused deployment secrets & args (#2698)

## Description:

* Remove unused otel creds
* Remove unused R2 creds
* remove left-over BASIC_AUTH
* Generate an admin token on startup
* Removed kick_player since lobby creators already have ability to kick
player

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

evan
This commit is contained in:
Evan
2025-12-25 19:34:36 -08:00
committed by GitHub
parent e1d0773672
commit 77908f7a1a
11 changed files with 24 additions and 203 deletions
-7
View File
@@ -106,21 +106,14 @@ jobs:
chmod 600 ~/.ssh/id_rsa
- name: 🚢 Deploy
env:
ADMIN_TOKEN: ${{ secrets.ADMIN_TOKEN }}
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: ${{ vars.GHCR_REPO }}
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
ENV: ${{ inputs.target_domain == 'openfront.io' && 'prod' || 'staging' }}
HOST: ${{ github.event_name == 'workflow_dispatch' && inputs.target_host || 'staging' }}
OTEL_ENDPOINT: ${{ secrets.OTEL_ENDPOINT }}
OTEL_PASSWORD: ${{ secrets.OTEL_PASSWORD }}
OTEL_USERNAME: ${{ secrets.OTEL_USERNAME }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
R2_ACCESS_KEY: ${{ secrets.R2_ACCESS_KEY }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_MASTERS: ${{ secrets.SERVER_HOST_MASTERS }}
-28
View File
@@ -63,21 +63,14 @@ jobs:
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
ADMIN_TOKEN: ${{ secrets.ADMIN_TOKEN }}
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: openfront-prod
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_ENDPOINT: ${{ secrets.OTEL_ENDPOINT }}
OTEL_PASSWORD: ${{ secrets.OTEL_PASSWORD }}
OTEL_USERNAME: ${{ secrets.OTEL_USERNAME }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
R2_ACCESS_KEY: ${{ secrets.R2_ACCESS_KEY }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_STAGING: ${{ secrets.SERVER_HOST_STAGING }}
@@ -121,21 +114,14 @@ jobs:
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
ADMIN_TOKEN: ${{ secrets.ADMIN_TOKEN }}
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: ${{ vars.GHCR_REPO }}
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_ENDPOINT: ${{ secrets.OTEL_ENDPOINT }}
OTEL_PASSWORD: ${{ secrets.OTEL_PASSWORD }}
OTEL_USERNAME: ${{ secrets.OTEL_USERNAME }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
R2_ACCESS_KEY: ${{ secrets.R2_ACCESS_KEY }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
@@ -179,21 +165,14 @@ jobs:
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
ADMIN_TOKEN: ${{ secrets.ADMIN_TOKEN }}
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: ${{ vars.GHCR_REPO }}
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_ENDPOINT: ${{ secrets.OTEL_ENDPOINT }}
OTEL_PASSWORD: ${{ secrets.OTEL_PASSWORD }}
OTEL_USERNAME: ${{ secrets.OTEL_USERNAME }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
R2_ACCESS_KEY: ${{ secrets.R2_ACCESS_KEY }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
@@ -237,21 +216,14 @@ jobs:
chmod 600 ~/.ssh/id_rsa
- name: 🚀 Deploy image
env:
ADMIN_TOKEN: ${{ secrets.ADMIN_TOKEN }}
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
GHCR_REPO: ${{ vars.GHCR_REPO }}
GHCR_USERNAME: ${{ vars.GHCR_USERNAME }}
DOMAIN: ${{ vars.DOMAIN }}
IMAGE_ID: ${{ needs.build.outputs.IMAGE_ID }}
OTEL_ENDPOINT: ${{ secrets.OTEL_ENDPOINT }}
OTEL_PASSWORD: ${{ secrets.OTEL_PASSWORD }}
OTEL_USERNAME: ${{ secrets.OTEL_USERNAME }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
R2_ACCESS_KEY: ${{ secrets.R2_ACCESS_KEY }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
API_KEY: ${{ secrets.API_KEY }}
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
+5 -22
View File
@@ -15,34 +15,34 @@ print_header "BUILD AND DEPLOY WRAPPER"
echo "This script will run build.sh and deploy.sh in sequence."
echo "You can also run them separately:"
echo " ./build.sh [prod|staging] [version_tag]"
echo " ./deploy.sh [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]"
echo " ./deploy.sh [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain]"
echo ""
# Check command line arguments
if [ $# -lt 3 ] || [ $# -gt 5 ]; then
echo "Error: Please specify environment, host, and subdomain"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain] [--enable_basic_auth]"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
exit 1
fi
# Validate first argument (environment)
if [ "$1" != "prod" ] && [ "$1" != "staging" ]; then
echo "Error: First argument must be either 'prod' or 'staging'"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain] [--enable_basic_auth]"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
exit 1
fi
# Validate second argument (host)
if [ "$2" != "falk1" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then
echo "Error: Second argument must be either 'falk1', 'nbg1', 'staging', or 'masters'"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain] [--enable_basic_auth]"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
exit 1
fi
# Validate third argument (subdomain)
if [ -z "$3" ]; then
echo "Error: Subdomain is required"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain] [--enable_basic_auth]"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
exit 1
fi
@@ -54,23 +54,6 @@ echo "Generated version tag: $VERSION_TAG"
ENV="$1"
HOST="$2"
SUBDOMAIN="$3"
ENABLE_BASIC_AUTH=""
# Parse remaining arguments
shift 3
while [[ $# -gt 0 ]]; do
case $1 in
--enable_basic_auth)
ENABLE_BASIC_AUTH="--enable_basic_auth"
shift
;;
*)
echo "Error: Unknown argument: $1"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain] [--enable_basic_auth]"
exit 1
;;
esac
done
# Step 1: Run build.sh
echo "Step 1: Running build.sh..."
+3 -51
View File
@@ -6,27 +6,6 @@
set -e # Exit immediately if a command exits with a non-zero status
# Initialize variables
ENABLE_BASIC_AUTH=false
# Parse command line arguments
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
case $1 in
--enable_basic_auth)
ENABLE_BASIC_AUTH=true
shift
;;
*)
POSITIONAL_ARGS+=("$1")
shift
;;
esac
done
# Restore positional parameters
set -- "${POSITIONAL_ARGS[@]}"
# Function to print section headers
print_header() {
echo "======================================================"
@@ -37,21 +16,21 @@ print_header() {
# Check command line arguments
if [ $# -ne 4 ]; then
echo "Error: Please specify environment, host, version tag, and subdomain"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain]"
exit 1
fi
# Validate first argument (environment)
if [ "$1" != "prod" ] && [ "$1" != "staging" ]; then
echo "Error: First argument must be either 'prod' or 'staging'"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain]"
exit 1
fi
# Validate second argument (host)
if [ "$2" != "falk1" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then
echo "Error: Second argument must be either 'falk1', 'nbg1', 'staging', or 'masters'"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain] [--enable_basic_auth]"
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain]"
exit 1
fi
@@ -107,21 +86,6 @@ if [ -z "$SERVER_HOST" ]; then
exit 1
fi
# Check if basic auth is enabled and credentials are available
if [ "$ENABLE_BASIC_AUTH" = true ]; then
print_header "BASIC AUTH ENABLED"
if [ -z "$BASIC_AUTH_USER" ] || [ -z "$BASIC_AUTH_PASS" ]; then
echo "Error: Basic Auth is enabled but BASIC_AUTH_USER or BASIC_AUTH_PASS not defined in .env file or environment"
exit 1
fi
echo "Basic Authentication will be enabled with user: $BASIC_AUTH_USER"
else
# If basic auth is not enabled, set the variables to empty to ensure they don't get used
BASIC_AUTH_USER=""
BASIC_AUTH_PASS=""
echo "Basic Authentication is disabled"
fi
# Configuration
UPDATE_SCRIPT="./update.sh" # Path to your update script
REMOTE_USER="openfront"
@@ -170,23 +134,14 @@ ENV=$ENV
HOST=$HOST
GHCR_IMAGE=$GHCR_IMAGE
GHCR_TOKEN=$GHCR_TOKEN
ADMIN_TOKEN=$ADMIN_TOKEN
CF_ACCOUNT_ID=$CF_ACCOUNT_ID
R2_ACCESS_KEY=$R2_ACCESS_KEY
R2_SECRET_KEY=$R2_SECRET_KEY
R2_BUCKET=$R2_BUCKET
CF_API_TOKEN=$CF_API_TOKEN
TURNSTILE_SECRET_KEY=$TURNSTILE_SECRET_KEY
API_KEY=$API_KEY
DOMAIN=$DOMAIN
SUBDOMAIN=$SUBDOMAIN
OTEL_USERNAME=$OTEL_USERNAME
OTEL_PASSWORD=$OTEL_PASSWORD
OTEL_ENDPOINT=$OTEL_ENDPOINT
OTEL_EXPORTER_OTLP_ENDPOINT=$OTEL_EXPORTER_OTLP_ENDPOINT
OTEL_AUTH_HEADER=$OTEL_AUTH_HEADER
BASIC_AUTH_USER=$BASIC_AUTH_USER
BASIC_AUTH_PASS=$BASIC_AUTH_PASS
EOL
chmod 600 $ENV_FILE && \
$REMOTE_UPDATE_SCRIPT $ENV_FILE"
@@ -198,8 +153,5 @@ fi
print_header "DEPLOYMENT COMPLETED SUCCESSFULLY"
echo "✅ New version deployed to ${ENV} environment in ${HOST} with subdomain ${SUBDOMAIN}!"
if [ "$ENABLE_BASIC_AUTH" = true ]; then
echo "🔒 Basic authentication enabled with user: $BASIC_AUTH_USER"
fi
echo "🌐 Check your server to verify the deployment."
echo "======================================================="
-8
View File
@@ -6,19 +6,11 @@ GHCR_USERNAME=username
GHCR_REPO=your-repo-name
GHCR_TOKEN=your_docker_token_here
# Admin credentials
ADMIN_TOKEN=your_admin_token_here
# Cloudflare Configuration
CF_ACCOUNT_ID=your_cloudflare_account_id
CF_API_TOKEN=your_cloudflare_api_token
DOMAIN=your-domain.com
# R2 Configuration
R2_ACCESS_KEY=your_r2_access_key
R2_SECRET_KEY=your_r2_secret_key
R2_BUCKET=your-bucket-name
# API Key
API_KEY=your_api_key_here
-4
View File
@@ -46,10 +46,6 @@ export interface ServerConfig {
adminHeader(): string;
// Only available on the server
gitCommit(): string;
r2Bucket(): string;
r2Endpoint(): string;
r2AccessKey(): string;
r2SecretKey(): string;
apiKey(): string;
otelEndpoint(): string;
otelAuthHeader(): string;
+5 -14
View File
@@ -141,19 +141,6 @@ export abstract class DefaultServerConfig implements ServerConfig {
gitCommit(): string {
return process.env.GIT_COMMIT ?? "";
}
r2Endpoint(): string {
return `https://${process.env.CF_ACCOUNT_ID}.r2.cloudflarestorage.com`;
}
r2AccessKey(): string {
return process.env.R2_ACCESS_KEY ?? "";
}
r2SecretKey(): string {
return process.env.R2_SECRET_KEY ?? "";
}
r2Bucket(): string {
return process.env.R2_BUCKET ?? "";
}
apiKey(): string {
return process.env.API_KEY ?? "";
@@ -163,7 +150,11 @@ export abstract class DefaultServerConfig implements ServerConfig {
return "x-admin-key";
}
adminToken(): string {
return process.env.ADMIN_TOKEN ?? "dummy-admin-token";
const token = process.env.ADMIN_TOKEN;
if (!token) {
throw new Error("ADMIN_TOKEN not set");
}
return token;
}
abstract numWorkers(): number;
abstract env(): GameEnv;
+8 -36
View File
@@ -1,11 +1,12 @@
import cluster from "cluster";
import crypto from "crypto";
import express from "express";
import rateLimit from "express-rate-limit";
import http from "http";
import path from "path";
import { fileURLToPath } from "url";
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
import { GameInfo, ID } from "../core/Schemas";
import { GameInfo } from "../core/Schemas";
import { generateID } from "../core/Util";
import { logger } from "./Logger";
import { MapPlaylist } from "./MapPlaylist";
@@ -73,10 +74,15 @@ export async function startMaster() {
log.info(`Primary ${process.pid} is running`);
log.info(`Setting up ${config.numWorkers()} workers...`);
// Generate admin token for worker authentication
const ADMIN_TOKEN = crypto.randomBytes(16).toString("hex");
process.env.ADMIN_TOKEN = ADMIN_TOKEN;
// Fork workers
for (let i = 0; i < config.numWorkers(); i++) {
const worker = cluster.fork({
WORKER_ID: i,
ADMIN_TOKEN,
});
log.info(`Started worker ${i} (PID: ${worker.process.pid})`);
@@ -128,6 +134,7 @@ export async function startMaster() {
// Restart the worker with the same ID
const newWorker = cluster.fork({
WORKER_ID: workerId,
ADMIN_TOKEN,
});
log.info(
@@ -154,41 +161,6 @@ app.get("/api/public_lobbies", async (req, res) => {
res.send(publicLobbiesJsonStr);
});
app.post("/api/kick_player/:gameID/:clientID", async (req, res) => {
if (req.headers[config.adminHeader()] !== config.adminToken()) {
res.status(401).send("Unauthorized");
return;
}
const { gameID, clientID } = req.params;
if (!ID.safeParse(gameID).success || !ID.safeParse(clientID).success) {
res.sendStatus(400);
return;
}
try {
const response = await fetch(
`http://localhost:${config.workerPort(gameID)}/api/kick_player/${gameID}/${clientID}`,
{
method: "POST",
headers: {
[config.adminHeader()]: config.adminToken(),
},
},
);
if (!response.ok) {
throw new Error(`Failed to kick player: ${response.statusText}`);
}
res.status(200).send("Player kicked successfully");
} catch (error) {
log.error(`Error kicking player from game ${gameID}:`, error);
res.status(500).send("Failed to kick player");
}
});
async function fetchLobbies(): Promise<number> {
const fetchPromises: Promise<GameInfo | null>[] = [];
-18
View File
@@ -270,24 +270,6 @@ export async function startWorker() {
}
});
app.post("/api/kick_player/:gameID/:clientID", async (req, res) => {
if (req.headers[config.adminHeader()] !== config.adminToken()) {
res.status(401).send("Unauthorized");
return;
}
const { gameID, clientID } = req.params;
const game = gm.game(gameID);
if (!game) {
res.status(404).send("Game not found");
return;
}
game.kickClient(clientID);
res.status(200).send("Player kicked successfully");
});
// WebSocket handling
wss.on("connection", (ws: WebSocket, req) => {
ws.on("message", async (message: string) => {
-12
View File
@@ -82,16 +82,4 @@ export class TestServerConfig implements ServerConfig {
gitCommit(): string {
throw new Error("Method not implemented.");
}
r2Bucket(): string {
throw new Error("Method not implemented.");
}
r2Endpoint(): string {
throw new Error("Method not implemented.");
}
r2AccessKey(): string {
throw new Error("Method not implemented.");
}
r2SecretKey(): string {
throw new Error("Method not implemented.");
}
}
+3 -3
View File
@@ -32,8 +32,8 @@ echo "Pulling ${GHCR_IMAGE} from GitHub Container Registry..."
docker pull "${GHCR_IMAGE}"
echo "Checking for existing container..."
# Check for running container
RUNNING_CONTAINER="$(docker ps | grep ${CONTAINER_NAME} | awk '{print $1}')"
# Use docker ps with filter for exact name match
RUNNING_CONTAINER="$(docker ps --filter "name=^${CONTAINER_NAME}$" -q)"
if [ -n "$RUNNING_CONTAINER" ]; then
echo "Stopping running container $RUNNING_CONTAINER..."
docker stop "$RUNNING_CONTAINER"
@@ -44,7 +44,7 @@ if [ -n "$RUNNING_CONTAINER" ]; then
fi
# Also check for stopped containers with the same name
STOPPED_CONTAINER="$(docker ps -a | grep ${CONTAINER_NAME} | awk '{print $1}')"
STOPPED_CONTAINER="$(docker ps -a --filter "name=^${CONTAINER_NAME}$" -q)"
if [ -n "$STOPPED_CONTAINER" ]; then
echo "Removing stopped container $STOPPED_CONTAINER..."
docker rm "$STOPPED_CONTAINER"