fix(devops): .env.example 移除可用 Fernet key 换不可用占位符 + 轮换提示(CR-H8)

This commit is contained in:
Yaojia Wang
2026-07-08 10:56:01 +02:00
parent e1a24a2c2c
commit baa41d370b
2 changed files with 41 additions and 2 deletions

View File

@@ -6,6 +6,7 @@ DATABASE_URL_SYNC=postgresql+psycopg://writer:writer@localhost:5432/writer
APP_ENV=dev
LOG_JSON=false
# 凭据加密密钥Fernet, urlsafe-base64 32B— **必填**API 启动即校验,缺失/非法则拒绝启动。
# 下方为开发占位 key可直接用于本地生产请换新值
# ⚠️ 下方为**不可用占位符**,必须替换:`cp .env.example .env` 后用下方命令生成真实 key 填入。
# 切勿把真实 key 提交进版本库;任何曾经泄露过的 key 必须立即轮换(重新加密已存凭据)。
# uv run python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
CREDENTIAL_ENC_KEY=cnMpG6QQxJejuDLHTe_S-nq2snoKgXCqWFfsctEHB-4=
CREDENTIAL_ENC_KEY=replace-me-with-generated-fernet-key

View File

@@ -0,0 +1,38 @@
"""回归守卫:`.env.example` 不得携带可用的真实密钥CR-H8
`.env.example` 是入库模板;若其中的 `CREDENTIAL_ENC_KEY` 是一把真实可用的
Fernet key任何照抄 `.env.example` 的环境都会共用同一把泄露过的密钥。此测试
确保模板里只放**不可用占位符**——照抄到 `.env` 会在启动校验main._lifespan
处快速失败,逼迫运维生成真实 key。
"""
from __future__ import annotations
import re
from pathlib import Path
import pytest
from cryptography.fernet import Fernet
_ENV_EXAMPLE = Path(__file__).resolve().parent.parent / ".env.example"
_PLACEHOLDER = "replace-me-with-generated-fernet-key"
def _credential_enc_key() -> str:
text = _ENV_EXAMPLE.read_text(encoding="utf-8")
match = re.search(r"^CREDENTIAL_ENC_KEY=(.*)$", text, flags=re.MULTILINE)
assert match is not None, ".env.example 缺少 CREDENTIAL_ENC_KEY 行"
return match.group(1).strip()
def test_env_example_credential_key_is_non_functional_placeholder() -> None:
value = _credential_enc_key()
assert value, "CREDENTIAL_ENC_KEY 不能为空"
# 真实可用的 Fernet key 会构造成功——那正是要杜绝的泄露面。
with pytest.raises(ValueError):
Fernet(value.encode())
def test_env_example_credential_key_is_the_expected_placeholder() -> None:
# 更紧的锁:值必须恰是约定占位符,防止未来又塞进别的真实 key。
assert _credential_enc_key() == _PLACEHOLDER