Status: Automated enforcement via pre-commit hooks
This guide provides detailed implementation instructions for the NO HARDCODED VALUES policy.
MANDATORY RULE: NO HARDCODED VALUES - USE SSOT CONFIG
The following values must NEVER be hardcoded in source files:
| Type | Examples | Correct Alternative |
|---|---|---|
| IP Addresses | "<backend-ip>", "192.168.1.100" |
config.backend.host (Python) or SSOT env vars |
| Port Numbers | 8001, 6379, 5173 |
config.backend.port (Python) or SSOT env vars |
| LLM Model Names | "qwen3.5:9b", "mistral:7b-instruct" |
config.llm.default_model or AUTOBOT_DEFAULT_LLM_MODEL |
| URLs | "http://example.com/api" |
getBackendUrl() (TypeScript) or SSOT config |
| API Keys/Secrets | "sk-abc123...", "password123" |
Environment variables (NEVER commit) |
See also: SSOT_CONFIG_GUIDE.md for complete configuration patterns
The pre-commit hook (autobot-infrastructure/shared/scripts/hooks/pre-commit-hardcoded-values) scans staged files before every commit and runs again on every PR via the code-quality GitHub Actions workflow. The local hook and the CI step share the same script and allowlist, so a violation that's blocked locally can't be bypassed by skipping pre-commit (--no-verify).
# Local: runs automatically on git commit (configured in .pre-commit-config.yaml)
git commit ...
# CI: runs as the "Block hardcoded value regressions" step
# in .github/workflows/code-quality.yml — uses pipeline-scripts/check-hardcoded-values-pr.sh
# which calls the same hook in argv mode against changed files.Run the same check locally before pushing:
GITHUB_BASE_REF=Dev_new_gui bash pipeline-scripts/check-hardcoded-values-pr.shWhat it blocks (by category, see hook source for full patterns):
- Hardcoded VM IPs (
172.16.168.19-25) - Hardcoded infrastructure ports in URL context
- Magic numbers that should use constants from
threshold_constants.py - Hardcoded role / category strings
- Hardcoded AutoBot file paths
- Hardcoded LLM model name literals
- Hardcoded database DSNs
- Hardcoded timeouts
What it allows (intentional, see pre-commit-hardcoded-values_test.py for the locked-in rules):
ssot_config.py/ssot-config.ts(these IS the SSOT — IPs ARE the source of truth there)network_constants.py,path_constants.py,security_constants.py,threshold_constants.py- Anything under
constants/,config.py, or.env* - Test files (
test_*.py,*_test.py,*.test.ts,*.spec.ts) — fixtures legitimately use literal IPs - Lines containing
config.,getenv,CONFIG[, orAUTOBOT_(already routed through SSOT) - Comments (any line starting with
#////*) - File types other than
.py/.ts/.vue(Markdown, YAML, JSON, etc. are not scanned at all — Ansible inventories and docs are explicitly out of scope) 192.168.x.xand127.0.0.xliterals (RFC 1918 example space and loopback — used in SSRF guards, network-tooling examples, test fixtures, i18n placeholders)
Known limitation (tracked in #6725 follow-up): the hook's line filter currently skips any line containing the substring getenv, so a literal IP fallback inside os.getenv("AUTOBOT_REDIS_HOST", "172.16.168.23") is not flagged. This is the false-negative an AST-aware Python rewrite would close. The locked-in test test_allows_code_using_ssot_config documents this behavior so any future tightening has a clear regression target.
When violations are found:
- Commit (or PR) is blocked
- Violation report shows file, line number, value, and the SSOT alternative
- Fix the violation, re-stage, re-commit (or push the fix)
autobot-frontend/eslint.config.ts includes a no-restricted-syntax rule that blocks hardcoded VM IPs in .ts / .mts / .tsx / .vue files. Two selectors:
Literal[value=/^(https?:\/\/)?172\.16\.168\.\d+/]— bare IP literals or HTTP(S) URLs containing themTemplateElement[value.cooked=/172\.16\.168\.\d+/]— IP inside a template literal
Catches:
const x = '172.16.168.20'const x = 'http://172.16.168.21:5173'const x = vmHost ?? 'http://172.16.168.20:8001'(the original||/??fallback anti-pattern)const x = `ws://172.16.168.21:5173/ws`
Doesn't trigger on:
127.0.0.1(loopback — single-host install default)192.168.x.x(RFC 1918 example space — used in tests, SSRF guards, i18n placeholders)- IPs in
.jsonlocale files,.mddocs, generated types (not in lint scope)
Test fixtures live in autobot-frontend/eslint-tests/ (excluded from production lint by design — see eslint-tests/README.md).
pipeline-scripts/check-pre-commit-hook-pr.sh <hook-name> runs any pre-commit hook in argv mode against the PR's changed files. Hooks that support argv mode today:
pre-commit-hardcoded-values(#6725) — wrapped bycheck-hardcoded-values-pr.shpre-commit-no-direct-redis(#1086, argv mode added in #6785)pre-commit-no-print-console(#1082, argv mode added in #6785)
To add a new hook to CI:
-
Add argv mode to the hook (positional args = files to scan, no args =
git diff --cached). -
Add a step in
.github/workflows/code-quality.yml:- name: Block <thing> regressions (#issue) run: bash pipeline-scripts/check-pre-commit-hook-pr.sh <hook-name>
-
Optionally add a test class in
pipeline-scripts/check-pre-commit-hook-pr_test.pyfor end-to-end coverage.
Run the detection script manually to audit the entire codebase:
# Scan entire codebase for violations
./autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh
# Get detailed report with line numbers
./autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh | less
# Scan specific file or directory
./autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh autobot-user-autobot-backend/api/chat.py
./autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh autobot-backend/Script location: autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh
registry_defaults.py now sources all default values from autobot_shared.ssot_config at import time. This means ConfigRegistry.get() callers no longer need hardcoded fallbacks -- the registry defaults tier provides SSOT-sourced values automatically.
# GOOD -- no hardcoded fallback needed
redis_host = ConfigRegistry.get("vm.redis")
npu_port = ConfigRegistry.get("port.npu")
# BAD -- redundant hardcoded fallback (will trigger detection script)
redis_host = ConfigRegistry.get("vm.redis", "<database-ip>")For model names and embedding models, use the SSOT constants:
from autobot_shared.ssot_config import DEFAULT_LLM_MODEL, DEFAULT_EMBEDDING_MODEL
# GOOD
model = DEFAULT_LLM_MODEL
embedding = DEFAULT_EMBEDDING_MODEL
# BAD
model = "qwen3.5:9b"
embedding = "nomic-embed-text:latest"Use the SSOT config (Python):
# BAD - Hardcoded values
url = "https://<backend-ip>:8443/api/chat"
redis_host = "<database-ip>"
redis_port = 6379
# GOOD - Use SSOT config
from autobot_shared.ssot_config import config
url = config.backend.url + "/api/chat"
redis_host = config.redis.host
redis_port = config.redis.portUse the SSOT config (TypeScript):
// BAD - Hardcoded values
const url = "https://<backend-ip>:8443/api/chat"
// GOOD - Use SSOT config
import { getBackendUrl } from '@/config/ssot-config'
const url = getBackendUrl() + "/api/chat"Use SSOT in Shell Scripts:
# Load .env at script start
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source "$PROJECT_ROOT/.env"
set +a
fi
# BAD - Hardcoded
BACKEND_HOST="<backend-ip>"
# GOOD - SSOT env var with fallback
BACKEND_HOST="${AUTOBOT_BACKEND_HOST:-<backend-ip>}"Use SSOT config:
# BAD - Hardcoded model name
model = "qwen3.5:9b"
# GOOD - Use SSOT config
from autobot_shared.ssot_config import config
model = config.llm.default_modelEnvironment variable: Set in .env file:
AUTOBOT_DEFAULT_LLM_MODEL=qwen3.5:9bUse environment variables via SSOT:
Step 1: Add to .env file (never commit this file):
AUTOBOT_API_BASE_URL=http://api.example.com
AUTOBOT_API_KEY=sk-abc123...
AUTOBOT_CUSTOM_SETTING=valueStep 2: Read via SSOT config or env vars:
# BAD - Hardcoded URL
api_url = "http://api.example.com"
# GOOD - Use SSOT config for standard values
from autobot_shared.ssot_config import config
backend_url = config.backend.url
# GOOD - Use os.getenv for custom values
import os
api_key = os.getenv("AUTOBOT_API_KEY") # NEVER hardcode secrets!Step 3: Document in .env.example:
# API Configuration
AUTOBOT_API_BASE_URL=http://api.example.com
AUTOBOT_API_KEY=your-api-key-hereWhen hardcoding is ABSOLUTELY necessary (extremely rare cases):
- Document WHY in code comments
- Add entry to
.hardcode-exceptionsfile - Get approval in code review
Create/edit .hardcode-exceptions in repository root:
# Hardcoding Exceptions
# Format: file_path:line_number:reason
autobot-backend/utils/legacy_module.py:45:Legacy API requires hardcoded endpoint
infrastructure/shared/tests/integration/test_fixtures.py:120:Test fixture needs static IP
NOT RECOMMENDED - Only use if you've added exception:
# Bypass pre-commit hook (use with extreme caution)
git commit --no-verify -m "Your message"Warning: This bypasses ALL pre-commit checks, not just hardcoding detection.
autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh
IP Address Patterns:
- IPv4:
<backend-ip>,192.168.1.1, etc. - IPv6: Full and compressed formats
- Excludes: Comments, documentation, test files
Port Numbers:
- Common service ports: 8001, 6379, 5173, etc.
- Excludes: Commented code, examples
LLM Model Names:
- Ollama models:
qwen3.5:9b,mistral:7b-instruct,gemma2:2b,llama3.2:1b - OpenAI models:
gpt-4,gpt-3.5-turbo - Anthropic models:
claude-3-opus
URLs and Secrets:
- HTTP/HTTPS URLs
- Potential API keys (pattern matching)
- Tokens and credentials
The script automatically excludes:
.envfiles (intended for configuration).env.examplefiles (documentation)network_constants.py(canonical source of truth)- Documentation files (
.md) - Test fixtures (when marked as such)
- Comments and docstrings
The hook is automatically installed via:
bash infrastructure/shared/scripts/install-pre-commit-hooks.shIf needed, install manually:
# Make script executable
chmod +x autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh
# Create pre-commit hook
cat > .git/hooks/pre-commit-hardcode-check << 'EOF'
#!/bin/bash
./autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh --staged
if [ $? -ne 0 ]; then
echo "Hardcoded values detected. Fix violations before committing."
exit 1
fi
EOF
chmod +x .git/hooks/pre-commit-hardcode-check.git/hooks/pre-commit-hardcode-check
- Know the proper pattern before writing code
- Use SSOT
configfor IPs/ports/URLs - Use
config.llm.default_modelfor models - Use
.envfor custom values
# Before starting work
./autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh
# After making changes
./autobot-autobot-infrastructure/shared/scripts/detect-hardcoded-values.sh autobot-user-autobot-backend/api/When adding new environment variables:
# Add to .env (local only)
AUTOBOT_NEW_FEATURE=value
# Document in .env.example (committed)
AUTOBOT_NEW_FEATURE=example-value- Pre-commit hook runs automatically
- Fix violations immediately
- Don't use
--no-verifyunless absolutely necessary
Issue: Script flags legitimate code
Solution 1: Add comment to clarify
# This is a test fixture, not production code
test_ip = "127.0.0.1" # Test onlySolution 2: Add to .hardcode-exceptions
infrastructure/shared/tests/fixtures/network_mock.py:45:Test fixture requires static IP
Issue: Hook doesn't run on git commit
Solution:
# Reinstall hooks
bash infrastructure/shared/scripts/install-pre-commit-hooks.sh
# Verify hook exists and is executable
ls -la .git/hooks/pre-commit-hardcode-check
chmod +x .git/hooks/pre-commit-hardcode-checkIssue: Need to commit despite violations (emergency)
Solution:
- Document the violation in code comments
- Create GitHub issue to fix it
- Add to
.hardcode-exceptions - Use
--no-verify(last resort)
# Emergency commit (not recommended)
git commit --no-verify -m "Emergency fix - see issue #123"- SSOT Config Guide: SSOT_CONFIG_GUIDE.md - Complete SSOT configuration patterns
- Migration Checklist: CONFIG_MIGRATION_CHECKLIST.md - Migrating code to SSOT
- SSOT Architecture: ../architecture/SSOT_CONFIGURATION_ARCHITECTURE.md
- Python SSOT Config:
autobot_shared/ssot_config.py - TypeScript SSOT Config:
autobot-frontend/src/config/ssot-config.ts - Environment Setup: DEVELOPER_SETUP.md
- Code Quality: CODE_QUALITY_ENFORCEMENT.md
Before committing:
- No hardcoded IP addresses (use SSOT
config.*.host) - No hardcoded port numbers (use SSOT
config.*.port) - No hardcoded model names (use
config.llm.default_model) - No hardcoded URLs (use
getBackendUrl()or SSOT config) - No hardcoded secrets (use environment variables)
- Pre-commit hook passes
-
.env.exampleupdated (if new variables added)
If you must hardcode (rare):
- Documented WHY in code comments
- Added to
.hardcode-exceptionsfile - Got approval in code review
- Created issue to remove hardcoding later