fix: avoid implicit API key imports

This commit is contained in:
Eddy committed 2026-07-05 12:16:27 +02:00
1 parent bd2463e0c3
commit 2fd02cbec9
3 files changed
+69 -33

No files matched your search

+26 -14
View File
@@ -1,18 +1,19 @@
#!/bin/bash #!/bin/bash
# T3MP3ST API Key Setup Script # T3MP3ST API Key Setup Script
set -euo pipefail
umask 077
echo "" echo ""
echo "╔═══════════════════════════════════════════════════════════╗" echo "╔═══════════════════════════════════════════════════════════╗"
echo "║ T3MP3ST API KEY CONFIGURATION ║" echo "║ T3MP3ST API KEY CONFIGURATION ║"
echo "╚═══════════════════════════════════════════════════════════╝" echo "╚═══════════════════════════════════════════════════════════╝"
echo "" echo ""
# Check if .env exists
ENV_FILE="$(dirname "$0")/../.env" ENV_FILE="$(dirname "$0")/../.env"
if [ -f "$ENV_FILE" ]; then if [ -f "$ENV_FILE" ]; then
echo "[*] Existing .env file found" echo "[*] Existing .env file found; it will be replaced after you enter a new key."
source "$ENV_FILE"
fi fi
echo "" echo ""
@@ -22,29 +23,38 @@ echo " 2) Anthropic (Claude direct)"
echo " 3) OpenAI (GPT models)" echo " 3) OpenAI (GPT models)"
echo "" echo ""
read -p "Enter choice [1-3]: " choice read -r -p "Enter choice [1-3]: " choice
case $choice in case $choice in
1) 1)
echo "" echo ""
echo "Get your OpenRouter API key at: https://openrouter.ai/keys" echo "Get your OpenRouter API key at: https://openrouter.ai/keys"
read -p "Enter your OpenRouter API key: " api_key read -rsp "Enter your OpenRouter API key: " api_key
echo "OPENROUTER_API_KEY=$api_key" > "$ENV_FILE" echo ""
echo "LLM_PROVIDER=openrouter" >> "$ENV_FILE" {
printf 'OPENROUTER_API_KEY=%s\n' "$api_key"
printf 'LLM_PROVIDER=openrouter\n'
} > "$ENV_FILE"
;; ;;
2) 2)
echo "" echo ""
echo "Get your Anthropic API key at: https://console.anthropic.com/" echo "Get your Anthropic API key at: https://console.anthropic.com/"
read -p "Enter your Anthropic API key: " api_key read -rsp "Enter your Anthropic API key: " api_key
echo "ANTHROPIC_API_KEY=$api_key" > "$ENV_FILE" echo ""
echo "LLM_PROVIDER=anthropic" >> "$ENV_FILE" {
printf 'ANTHROPIC_API_KEY=%s\n' "$api_key"
printf 'LLM_PROVIDER=anthropic\n'
} > "$ENV_FILE"
;; ;;
3) 3)
echo "" echo ""
echo "Get your OpenAI API key at: https://platform.openai.com/api-keys" echo "Get your OpenAI API key at: https://platform.openai.com/api-keys"
read -p "Enter your OpenAI API key: " api_key read -rsp "Enter your OpenAI API key: " api_key
echo "OPENAI_API_KEY=$api_key" > "$ENV_FILE" echo ""
echo "LLM_PROVIDER=openai" >> "$ENV_FILE" {
printf 'OPENAI_API_KEY=%s\n' "$api_key"
printf 'LLM_PROVIDER=openai\n'
} > "$ENV_FILE"
;; ;;
*) *)
echo "Invalid choice" echo "Invalid choice"
@@ -52,6 +62,8 @@ case $choice in
;; ;;
esac esac
chmod 600 "$ENV_FILE"
# Add .env to gitignore if not already there # Add .env to gitignore if not already there
GITIGNORE="$(dirname "$0")/../.gitignore" GITIGNORE="$(dirname "$0")/../.gitignore"
if [ -f "$GITIGNORE" ]; then if [ -f "$GITIGNORE" ]; then
@@ -69,7 +81,7 @@ echo "╔═══════════════════════
echo "║ CONFIGURATION COMPLETE! ║" echo "║ CONFIGURATION COMPLETE! ║"
echo "╚═══════════════════════════════════════════════════════════╝" echo "╚═══════════════════════════════════════════════════════════╝"
echo "" echo ""
echo "Your API key has been saved to .env" echo "Your API key has been saved to .env (mode 600)"
echo "" echo ""
echo "Start the server with:" echo "Start the server with:"
echo " npm run server" echo " npm run server"
+37
View File
@@ -0,0 +1,37 @@
import { describe, expect, it } from 'vitest';
import { readFileSync } from 'fs';
import { join } from 'path';
const configSource = readFileSync(join(process.cwd(), 'src/config/index.ts'), 'utf8');
const setupScript = readFileSync(join(process.cwd(), 'scripts/setup-api.sh'), 'utf8');
function configLoadEnvBlock(): string {
const start = configSource.indexOf('private loadEnvVariables(): void');
expect(start).toBeGreaterThanOrEqual(0);
const end = configSource.indexOf('\n /**\n * Get all settings', start);
expect(end).toBeGreaterThan(start);
return configSource.slice(start, end);
}
describe('API key environment handling hardening', () => {
it('ConfigManager does not implicitly read .env from the caller working directory', () => {
const block = configLoadEnvBlock();
expect(block).not.toContain("join(process.cwd(), '.env')");
expect(block).toContain("join(homedir(), '.t3mp3st', '.env')");
});
it('ConfigManager uses env keys in-memory and does not persist imported env keys', () => {
const block = configLoadEnvBlock();
expect(block).not.toMatch(/setApiKey\(/);
expect(block).not.toMatch(/config\.set\(['"]apiKeys['"]/);
});
it('setup-api.sh never sources .env and reads API keys silently into a 0600 file', () => {
expect(setupScript).not.toMatch(/\bsource\s+["']?\$ENV_FILE/);
expect(setupScript).toMatch(/umask\s+077/);
expect(setupScript).toMatch(/read\s+-rsp\s+"Enter your OpenRouter API key:/);
expect(setupScript).toMatch(/chmod\s+600\s+"\$ENV_FILE"/);
});
});
+6 -19
View File
@@ -452,9 +452,10 @@ class ConfigManager {
private loadEnvVariables(): void { private loadEnvVariables(): void {
if (this.envLoaded) return; if (this.envLoaded) return;
// Try to load from .env file in current directory or home // Load only T3MP3ST-owned/home env files. Do NOT read process.cwd()/.env:
// operators often run T3MP3ST inside target repos, and importing that repo's
// secrets would contaminate this process with unrelated credentials.
const envPaths = [ const envPaths = [
join(process.cwd(), '.env'),
join(homedir(), '.t3mp3st', '.env'), join(homedir(), '.t3mp3st', '.env'),
join(homedir(), '.env'), join(homedir(), '.env'),
]; ];
@@ -482,23 +483,9 @@ class ConfigManager {
} }
} }
// Check environment variables for API keys // Environment variables (including values loaded from ~/.t3mp3st/.env above)
const envKeys = { // are intentionally process-local. getApiKey() already gives env vars highest
openrouter: process.env.OPENROUTER_API_KEY, // priority, so do not persist them into Conf's apiKeys store as a side effect.
venice: process.env.VENICE_API_KEY,
anthropic: process.env.ANTHROPIC_API_KEY,
openai: process.env.OPENAI_API_KEY,
};
// Only set from env if not already set in config
const currentKeys = this.config.get('apiKeys');
for (const [provider, envKey] of Object.entries(envKeys)) {
if (envKey && !currentKeys[provider as keyof typeof currentKeys]) {
this.setApiKey(provider as 'openrouter' | 'venice' | 'anthropic' | 'openai', envKey);
}
}
this.envLoaded = true; this.envLoaded = true;
} }