不要把配置拼写错误当作默认值
目标
测试严格的配置解析、机密剔除和按应用划分的快照。
为什么重要
把字符串 false 转成 bool,结果变成了 True。生产环境里调试响应被打开了,状态页面还把整个配置字典都输出了出来。环境变量是字符串,所以仅靠类型声明,并不能成为安全的值。读取配置的时间点和公开的范围,同样是应用的契约。
步骤
- 在
/root/work/fa-config-lab/service.py中,parse_bool(value) 只对忽略大小写的 true 或 false 返回 bool。如果带有空白或不是字符串,就是 ValueError。
先做一次准备。已有的文件不会被覆盖。
mkdir -p /root/work/fa-config-lab
test -e /root/work/fa-config-lab/service.py || cp /opt/fixtures/ten_labs/fa-config-lab/service.py /root/work/fa-config-lab/service.py
cd /root/work/fa-config-lab
-
在
/root/work/fa-config-lab/service.py中,parse_port(value) 把只含 ASCII 数字的字符串转换为 int,在 1–65535 范围内时返回。其余都是 ValueError。 -
在
/root/work/fa-config-lab/service.py中,parse_timeout(value) 把字符串转换为 float,只返回大于 0 且不超过 30 的有限值。其余都是 ValueError。 -
在
/root/work/fa-config-lab/service.py中,required_token(env) 在 TOKEN 是字符串,且 strip 之后不为空时,返回 strip 后的值。缺失或为空值都是 ValueError。 -
在
/root/work/fa-config-lab/service.py中,load_settings(env) 是一个字典:service=env 的 SERVICE,缺失时为 'api';debug=parse_bool(DEBUG 缺失时为 'false');port=parse_port(PORT 缺失时为 '8000');timeout=parse_timeout(TIMEOUT 缺失时为 '5');token=required_token。空的 SERVICE 是 ValueError。 -
在
/root/work/fa-config-lab/service.py中,public_settings(settings) 是只含 service 和 debug 的新字典。不要修改原件。 -
在
/root/work/fa-config-lab/service.py中,snapshot(env) 返回 load_settings 的结果。调用之后即使修改 env,返回的配置也不会改变。 -
在
/root/work/fa-config-lab/service.py中,create_app(env) 立即读取 snapshot,如果配置非法,就以 ValueError 使应用创建失败。GET /info 只返回 public_settings。用不同的 env 创建的应用之间不共享配置。
参考
- 不联网、不安装软件包,在现有的 lab-dev 环境中进行。
- 每一步都在 45 秒的评分预算内运行。不要添加真实的 sleep 或网络调用。
- 评分会重新导入提交的模块,并用独立的输入和临时 DB 进行检查。请实现契约,而不要把预期值当作常量返回。
- FastAPI 官方文档 · pytest 官方文档 · Python sqlite3
- 局限:环境是通过普通字典注入的,所以不依赖真实的进程全局环境。这个示例并不会实现加密的机密存储、密钥轮换和动态重新加载。令牌字符串是学习用的输入,不会把真正的生产密钥放进实验 Pod。
显式解析布尔值
在 /root/work/fa-config-lab/service.py 中,parse_bool(value) 只对忽略大小写的 true 或 false 返回 bool。如果带有空白或不是字符串,就是 ValueError。
先做一次准备。已有的文件不会被覆盖。
mkdir -p /root/work/fa-config-lab
test -e /root/work/fa-config-lab/service.py || cp /opt/fixtures/ten_labs/fa-config-lab/service.py /root/work/fa-config-lab/service.py
cd /root/work/fa-config-lab
bool('false') 是 True。请直接比较允许的两个字符串。
保存后用 bash /opt/lab/checks/fa-config-lab/01-contract.sh 确认。
检查端口范围
在 /root/work/fa-config-lab/service.py 中,parse_port(value) 把只含 ASCII 数字的字符串转换为 int,在 1–65535 范围内时返回。其余都是 ValueError。
整数转换成功,并不意味着它是有效的端口范围。
保存后用 bash /opt/lab/checks/fa-config-lab/02-contract.sh 确认。
让超时时间成为有限值
在 /root/work/fa-config-lab/service.py 中,parse_timeout(value) 把字符串转换为 float,只返回大于 0 且不超过 30 的有限值。其余都是 ValueError。
NaN 在一般比较中的表现与预期不同,所以要检查 isfinite。
保存后用 bash /opt/lab/checks/fa-config-lab/03-contract.sh 确认。
拒绝缺失的必需机密
在 /root/work/fa-config-lab/service.py 中,required_token(env) 在 TOKEN 是字符串,且 strip 之后不为空时,返回 strip 后的值。缺失或为空值都是 ValueError。
不要用示例中的默认值来替代缺失的必需机密。
保存后用 bash /opt/lab/checks/fa-config-lab/04-contract.sh 确认。
只对缺失的情形应用默认值
在 /root/work/fa-config-lab/service.py 中,load_settings(env) 是一个字典:service=env 的 SERVICE,缺失时为 'api';debug=parse_bool(DEBUG 缺失时为 'false');port=parse_port(PORT 缺失时为 '8000');timeout=parse_timeout(TIMEOUT 缺失时为 '5');token=required_token。空的 SERVICE 是 ValueError。
get 的默认值与“值 or 默认值”,在处理空字符串时是不同的。
保存后用 bash /opt/lab/checks/fa-config-lab/05-contract.sh 确认。
从公开配置中剔除机密
在 /root/work/fa-config-lab/service.py 中,public_settings(settings) 是只含 service 和 debug 的新字典。不要修改原件。
与对令牌值的一部分做掩码相比,更应采用根本不公开该字段的契约。
保存后用 bash /opt/lab/checks/fa-config-lab/06-contract.sh 确认。
把外部变更与配置分开
在 /root/work/fa-config-lab/service.py 中,snapshot(env) 返回 load_settings 的结果。调用之后即使修改 env,返回的配置也不会改变。
把应用启动时刻的配置,与以后可能变化的输入字典分开。
保存后用 bash /opt/lab/checks/fa-config-lab/07-contract.sh 确认。
确认启动失败和公开响应
在 /root/work/fa-config-lab/service.py 中,create_app(env) 立即读取 snapshot,如果配置非法,就以 ValueError 使应用创建失败。GET /info 只返回 public_settings。用不同的 env 创建的应用之间不共享配置。
为了不让配置错误等到服务器启动后的第一个请求才暴露,要在创建时就验证。
保存后用 bash /opt/lab/checks/fa-config-lab/08-contract.sh 确认。