Skip to main content

cfgdrift — 语义级配置漂移检测系统

简体中文 | English

CI PyPI version PyPI downloads License Python versions Stars

cfgdrift 是语义级(semantic-level)配置漂移检测工具:解析 JSON / YAML / TOML / INI / XML / Java properties / .env / nginx 为结构化语义树,忽略注释 / 缩进 / 键序等格式噪音,只报告配置「含义」的真实变化。适合配置变更审计、安全合规检查、CI 门禁与日常运维巡检。

✨ 亮点

  • 精准检测:检出新增 / 删除 / 修改 / 类型变化 / 重排五类漂移,按 CRITICAL / WARN / INFO 分级,误报趋近于零
  • 闭环可操作:采集 → 解析 → 基线 → 比对 → 报告一条命令打通;基线版本化 + 回滚,SQLite 历史可追溯
  • 无人值守:daemon 周期扫描,检出漂移触发 webhook / 邮件 / 脚本 / Slack / Teams / PagerDuty 六通道告警(规则级重试可配),支持开机自启(systemd / launchd / schtasks)
  • 工程友好:退出码 0/1/2 契约可直接接入 CI/CD;JSON / 单文件离线 HTML 报告;本地 Web 仪表盘
  • 可扩展:内置 8 种格式开箱即用(JSON/YAML/TOML/INI + v0.18.0 的 XML/properties/.env/nginx),插件化解析器接口(entry point cfgdrift.parsers + 装饰器注册)支持任意自定义格式
  • 随处可装:C 核心解析 + 纯 Python 兜底,任意 Python 3.8+ 免编译器安装,跨平台

特性速览

能力 一句话说明 详见
语义 diff + 严重度 五类漂移 × CRITICAL/WARN/INFO 语义 diff 与严重度
一致性约束 五类约束叠加 diff,升级 + 关联判定 一致性约束
daemon + 告警 周期扫描、六通道、重试 / 静默 / 开机自启 daemon 与告警
自愈闭环 remediate 键级回滚 + 修复建议 hint 自愈闭环
Web 仪表盘 10 视图:时间线 / 环境对比 / 自愈审计… Web 仪表盘
corpus + kappa git 历史挖掘 + 双人标注一致性 corpus 基准语料 + kappa
敏感脱敏 13 类敏感键五出口打码 敏感值脱敏
插件 --format 自定义解析格式 自定义解析器插件
云/部署态采集 --source k8s 采集 K8s ConfigMap / Secret(v0.14.0 / v0.19.0) 云/部署态采集
原生告警通道 Slack / Teams / PagerDuty 原生通道(v0.15.0) 原生告警通道
列表重排检测 LCS 序列匹配,纯重排报 INFO reordered 而非多处误报(v0.16.0) 列表重排检测
Web 认证 可选 Bearer token 保护全部 /api/*,未配置时零噪音(v0.17.0) Web 认证
内置解析器扩充 内置 8 格式开箱即用(+ XML / properties / .env / nginx,v0.18.0) 内置解析器与自定义插件
小白易用性 diff OLD NEW 双文件 / parse error 方言引导 / 基线保存确认 / 常见误区文档(v0.20.0) 常见误区
双 wheel / C 加速 纯 Python 兜底 + CPython3.13 加速 安装

安装

pip install cfgdrift            # 通用安装(pip 自动选件)
pip install "cfgdrift[web]"     # 含 Web 仪表盘
pip install "cfgdrift[dev]"     # 含测试依赖
  • Python 3.8+ 免编译器;C 扩展为可选加速器,未编译或安装失败自动降级纯 Python。
  • 双 wheel 模型 / 本地构建配方 / 环境变量表 / 双模式一致性差异:见 安装文档

快速上手

cfgdrift init
cfgdrift scan ./config --save-as-baseline prod
# …修改配置…
cfgdrift diff ./config --baseline prod          # 退出码 1 = 有漂移
cfgdrift serve                                   # 打开 http://127.0.0.1:8080

常见误区(v0.20.0 小白必读)

  1. 基线按路径匹配,不按内容——scan/diff --baseline 是「当前快照 vs 基线快照」按文件路径(relpath)求交做键级对比。改内容又改文件名 = 旧路径消失 + 新路径出现 → 报告「文件删除 + 新增」,不是「内容修改」。想要内容级对比,直接用双文件:cfgdrift diff old.conf new.conf
  2. .conf 默认按 ini 解析——.conf/.cfg 扩展名默认映射 ini 方言。HOCON/nginx 风格内容(server { port = 8080 })按 ini 会报 parse error at line ...;此时会额外提示 hint: ... --format nginx 或 --format toml,按提示换格式即可。
  3. diff 有两种用法——单文件 vs 基线:cfgdrift diff PATH --baseline NAME(老用法);双文件直接对比:cfgdrift diff OLD NEW(OLD 为基准、NEW 为目标,输出同一套键级语义 diff)。两个 PATH 时不能再带 --baseline/--compare/--explain

常见报错速查

报错 触发场景 解法
Got unexpected extra argument 老版本对 diff old.conf new.conf 的报错 升级到 v0.20.0,直接 cfgdrift diff OLD NEW
parse error at line ... + .conf 文件 HOCON/nginx 内容按 ini 解析 报错下方有 hint:,按提示 --format nginx--format toml
--baseline is required (or use --compare) diff PATH 没带基线 cfgdrift scan ./config --save-as-baseline NAMEdiff PATH --baseline NAME
path is required with --source local scan 没给路径 cfgdrift scan ./config [--save-as-baseline NAME]
diff accepts at most two PATHs (OLD NEW) 给了 3 个及以上 PATH 双文件对比只收两个 PATH

云/部署态采集(v0.14.0 / v0.19.0)

--source(别名 --adapter)把采集来源从本地文件扩展为部署态真实配置。k8s 采集器通过只读 kubectl 子进程(零 SDK 依赖,只读白名单 get/cluster-info)抓取资源条目,接入现有解析 / diff / 脱敏 / 约束 / hint 全链路:

cfgdrift baseline create prod --source k8s --namespace prod        # 存 ConfigMap 部署态基线
cfgdrift baseline create prod --source k8s --kind secret           # 存 Secret 基线(只存指纹)
cfgdrift scan --source k8s --baseline prod --kind all              # ConfigMap + Secret 一并比对
cfgdrift daemon start --source k8s --baseline prod --kind secret   # 周期巡检 Secret 漂移
  • 资源选择:--kind configmap|secret|all(v0.19.0,G7)——默认 configmap(零噪音,与 v0.18.0 逐字节一致),secret 只采 Secret,all 显式合并两者(configmap 先、secret 后);不带 --kind 的既有命令行为不变
  • Secret 脱敏是结构性保证(v0.19.0):Secret 的 data(base64 解码)+ stringData 值在采集出口即被指纹化(sha256:<16hex>)——基线 / 报告 / 告警 / Web / hint 五个出口结构上只可能碰到指纹;显示层对 Secret 条目整体强制打码is_secret 标记或 /secret/ 路径段,无视键名),终端/JSON/CSV/HTML/告警/Web/hint 一律显示 ******,基线文件被拖库也带不出明文
  • 过滤:--namespace a,b(逐命名空间采集)、--label-selector app=gateway(透传 kubectl -l
  • 来源标注:非 local 漂移项在终端 / --json / 告警 payload 均带 sourcek8s/<ns>/<name>/<key> 伪路径、Secret 为 k8s/<ns>/secret/<name>/<key>line 恒为 null);终端 source 行按资源区分 ConfigMap=<name> / Secret=<name>
  • 降级清晰:kubectl 缺失 / 集群不可达 → 可读错误退出码 2;空结果 → 空报告退出码 0(D6 守卫防误报)
  • 默认 --source local 行为与 v0.13.0 逐字节一致(零噪音契约)
  • 扩展点:COLLECTORS 注册表挂一项即新增来源(AWS SSM 等后续版本)

原生告警通道(v0.15.0)

漂移告警从「webhook / 邮件 / 脚本」三通道升级为六通道——新增 Slack(Incoming Webhook)、Microsoft Teams(Workflow Webhook 卡片)与 PagerDuty(Events API v2)三个原生通道。每个通道一个专用渲染器 + 纯 HTTP POST 发送器(标准库 urllib.request,零新增依赖),完全复用既有 Channel 基类与调度链(规则级重试 / 10 分钟防抖 / 事件落库 / 审计全部白拿):

cfgdrift alert add --name ops-slack --type slack --severity WARN \
    --webhook-url https://hooks.slack.com/services/T.../B.../xxx
cfgdrift alert add --name ops-teams --type teams --severity WARN \
    --webhook-url https://<tenant>.webhook.office.com/webhookb2/<token>/IncomingWebhook/<id>/<key>
cfgdrift alert add --name oncall --type pagerduty --severity CRITICAL \
    --routing-key "{env:CFGDRIFT_PD_ROUTING_KEY}"     # {env:VAR} 引用,明文不落盘
cfgdrift alert test --rule ops-slack                  # 连通性验证 exit 0/2
  • severity 统一映射:CRITICAL → Slack/Teams #e11d48、PagerDuty critical;WARN → #f59e0b / warning;INFO → #64748b / infochannels.py 单点常量表,三渲染器共用)
  • 凭据不落盘webhook_url / routing_key 支持 {env:VAR} 在发送时展开;错误消息只含 scheme://host,不回显 webhook token / routing key
  • 零噪音:不配置新通道时,CLI / 告警 payload / Web / daemon 行为与 v0.14.0 逐字节一致

列表重排检测(v0.16.0)

列表 diff 从「按索引逐位比较」升级为 LCS 序列匹配(标准库 difflib,零新增依赖):元素按「类型 + 语义值」指纹配对,内容不变仅位置变的元素报 INFO 级 reordered,不再误报为多处 modified;真新增 / 真删除 / 真修改照常判定。

cfgdrift diff ./app.yaml --baseline prod          # 默认开启重排检测
cfgdrift diff ./app.yaml --baseline prod --no-reorder   # 恢复 v0.15.0 逐位行为
  • REORDERED 语义[alice,bob,carol][carol,alice,bob] = 3 条 reordered(INFO),不计入退出码(纯重排 exit 0,CI 友好);混合场景 [a,b,c,d][a,c,b,e] = b/c 重排 + d 删除 + e 新增
  • 可精确控制change_type=reordered 可用于 ignore 规则(静默)与 severity 规则(如把 ingress host 顺序提升为 WARN)
  • 零噪音契约:不含重排的 diff 与 v0.15.0 逐字节一致(reordered 计数 / reorder 详情仅非零时输出);--no-reorder 下完全恢复 v0.15.0 行为
  • 约束语义:索引引用 = 位置引用,随重排移动(hosts[2].port 按新列表 index 2 评估);内置 20 条约束均为 dict 路径,零改动
  • corpus 迁移评估:benchmark/corpus-v1/results/reorder_migration.md(232 实例中 9 个重排实例、223 个非重排实例逐字节一致)

📚 文档站

主题 链接
首页 / 总览 docs-site/index.html
安装(双 wheel / 构建 / 环境变量 / 双模式差异) installation.html
快速上手 quickstart.html
CLI 参考(完整命令清单) cli.html
Web 仪表盘 web-dashboard.html
告警(三通道 / 重试 / 静默 / 趋势) alerting.html
一致性约束 constraints.html
corpus 基准语料 corpus.html
自愈(remediate + hint) self-healing.html
示例 gallery gallery.html
贡献指南 contributing.html
FAQ faq.html

核心特性(按用户价值,不按版本)

语义 diff 与严重度

  • 检出新增 / 删除 / 修改 / 类型变化四类漂移,忽略注释 / 缩进 / 键序等格式噪音;快照结构 {relpath: tree},文件级新增 = INFO、删除 = CRITICAL。
  • 目录扫描约定:扩展名识别 .json / .yaml|.yml / .toml / .ini|.cfg|.conf / .xml / .properties / .env / .nginx(v0.18.0 新增四格式;.conf 仍映射 ini),未知扩展名跳过并告警;单文件未知扩展名需显式 --format;列表 diff 按索引比较(v0.16.0 起支持重排检测)。
  • 数据目录默认 ~/.cfgdrift/,可用 CFGDRIFT_HOME--store PATH 覆盖。
  • 退出码契约0=无漂移,1=检出漂移,2=错误——可直接接入 CI 门禁。
  • 多环境基线对比:compare ENV1 ENV2...(头部展示 compare A -> B (vX vs vY),支持 environments.yaml 映射);report --html / --json / --csv 导出报告。

一致性约束与约束挖掘

  • 在语义 diff 之上叠加约束检查层,仅报告与本次漂移关联的约束破坏(零噪音契约)。
  • 五类约束:range / enum / conditional_required / correlation / mutual_exclusion;diff / scan / daemon 默认启用内置库(20 条,--no-builtin 关闭,--constraints 追加),constraint add|list|remove|disable|enable 管理用户规则。
  • constraint mine 从历史扫描 / 语料挖掘候选(mined_candidates.yamlenabled: false 不自动生效),人工确认后一键转正。
cfgdrift diff ./config --baseline prod --constraints extra.yaml
cfgdrift constraint mine --min-support 5 --source scans

daemon 与告警

  • 后台常驻周期扫描,检出漂移触发 webhook / 邮件 / 脚本 / Slack / Teams / PagerDuty 六通道告警;防抖去重 + 失败重试(规则级 --retry-count / --retry-delay 可配)。
  • 开机自启:daemon enable-autostart|disable-autostart|autostart-status(systemd / launchd / schtasks,幂等语义,--dry-run 预览)。
  • 规则级静默 alert mute NAME --until <ISO> + 事件 ack;daemon 健康可观测(error_rate 聚合)。
cfgdrift daemon enable-autostart --target /etc/nginx --baseline prod --interval 300
cfgdrift alert add --name nginx-webhook --type webhook --url http://x --retry-count 5

自愈闭环(remediate + hint)

  • cfgdrift remediate --baseline NAME [--apply]<home>/remediate.yaml 策略把漂移键精确回滚回基线值:只改写目标键文本区间,注释 / 缩进 / 键序 / 其它键逐字节保留;写前备份 + 原子写 + 写后校验;默认 dry-run 预览。
  • daemon start --remediate 自动修复闭环;每次动作落 remediation_log 审计表(Web「自愈审计」视图)。
  • G4 修复建议:每条 CRITICAL/WARN 漂移自动生成 [hint](期望值 + 回滚命令 + 溯源);--no-hint 一键恢复旧输出(零噪音)。
cfgdrift remediate --baseline prod            # dry-run 预览
cfgdrift remediate --baseline prod --apply    # 执行回滚
cfgdrift diff ./config --baseline prod --no-hint   # 关闭 hint

Web 仪表盘(10 视图)

  • cfgdrift serve 启动本地 Web 仪表盘(127.0.0.1:8080,需 [web] extra)。
  • 10 视图:时间线(搜索 / 筛选 / 分页)、严重度分布(饼图点击联动)、环境对比、报告(含「导出 HTML」)、告警(规则管理 / 趋势图 / 事件 ack)、约束(生效列表 / 挖掘候选 / 违反)、corpus 统计、自愈审计等。
pip install "cfgdrift[web]"
cfgdrift serve

Web 认证(v0.17.0)

把 dashboard 共享给团队时,用 Bearer token 给全部 /api/* 路由(含回滚 / 改规则 / 发告警等写操作)上锁——不配置 token 时服务与 v0.16.0 逐字节一致(零噪音,默认匿名)。

cfgdrift web token                 # 生成一个 URL-safe token(43 字符,一次一行)
cfgdrift serve --token <TOKEN>     # 启动时开启认证
CFGDRIFT_WEB_TOKEN=<TOKEN> cfgdrift serve   # 或走环境变量(CLI --token 优先)
  • 认证开启后:Authorization: Bearer <token> 缺失 / 错误 / 缺 Bearer 前缀 → 401 + WWW-Authenticate: Bearer(写操作零副作用);对 token 的响应与 v0.16.0 逐字节一致。
  • 前端行为:任一 /api/* 请求返回 401 → 弹登录层;登录成功写入 localStorage(key cfgdrift_web_token)并自动重渲染,刷新页面保持登录态。未启用认证时前端不弹层、无探针请求
  • 安全提示:绑到非回环地址(如 0.0.0.0)且未配置 token 时,启动会向 stderr 打印警告(仅提示,不拦截启动)。token 只回显「已启用/未启用」状态,从不打印 token 值。

corpus 基准语料 + kappa

  • corpus init|fetch|export|validate 从真实项目 git 历史挖掘配置变更对,标准化为 instances.jsonllocal_path 离线采集 / CI 安全)。
  • corpus annotate 双人标注 + corpus kappa(Cohen's kappa + 混淆矩阵)+ corpus statskappa --export 导出论文附录。

敏感值脱敏

  • 终端 / JSON 报告 / HTML 报告 / Web API / 告警 payload 五出口对 password / token / secret 等 13 类敏感键自动打码(masking.yaml 可定制;数据库始终保存原始值)。

内置解析器与自定义插件

  • 内置 8 格式(v0.18.0):在 JSON / YAML / TOML / INI 之上新增 XMLxml.etree 标准库,属性→@attr、混合文本→$text、重复标签→list、值恒为字符串)、Java properties=/:/首空白分隔、#/! 注释、\ 续行、\uXXXX 转义、键保持扁平)、.envKEY=VALUEexport 前缀剥除、引号剥除、行尾注释剥离)、nginx(手写块状态机,server 无参块→恒定 list[dict]、命名块→组 dict、数字标量化、强制分号校验)——全部纯 Python 零新增依赖;--format xml|properties|env|nginx 显式可用,auto 识别 .xml / .properties / .env / .nginx 扩展名;.conf/.cfg 保持 ini(零噪音)。
  • --format <plugin> 支持自定义解析格式:插件返回原始树,由引擎统一归一化为语义树;可选 build_line_map 提供 file:line 行号。
  • 方式 A 装饰器 @register_plugin(...) 进程内注册(import 即生效);方式 B entry point [project.entry-points."cfgdrift.parsers"] pip 打包分发。
  • 完整可运行示例(含 pytest 测试):examples/mydsl-parser
pip install -e examples/mydsl-parser
cfgdrift scan app.dsl --format mydsl        # 或按 .dsl 扩展名自动识别

双 wheel / C 加速

  • 双 wheel 发布:纯 Python 通用 wheel(默认)+ CPython 3.13 C 加速平台 wheel + sdist;pip 标签优先级自动分流。
  • 构建配方 / 环境变量表(CFGDRIFT_BACKEND / CFGDRIFT_NO_C 等)/ 双模式一致性差异明细:见 installation.html

示例 gallery

三段可复现 demo,一键跑通「基线 → 漂移 → 检出 → 修复建议 → 自愈」全流程:

Demo 场景 演示能力 一键复现
nginx 生产配置被人工改端口 插件解析器 + range 约束 + hint + 自愈回滚 bash docs/gallery/nginx/run.sh
configmap staging/prod 双 ConfigMap 多环境对比 + correlation 约束 + 脱敏 bash docs/gallery/configmap/run.sh
ci-gate CI 配置漂移门禁 退出码契约 + JSON / HTML 报告 bash docs/gallery/ci-gate/run.sh

详见 docs/gallery/README.mdgallery.html

贡献

欢迎提交 issue 与 PR。请先阅读 贡献指南。开发环境:pip install "cfgdrift[dev]",测试用 pytest

FAQ

常见问题见 文档站 FAQ

License

本项目采用 MIT License(详见根目录 LICENSE 文件)。

MIT 许可允许你自由使用、修改与分发本项目(包括商业用途),只需保留原始版权声明与许可声明即可。

版本历史

各版本增量(v0.20.0 → v0.1.0)见 docs/CHANGELOG.md(英文版 docs/CHANGELOG.en.md)。

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cfgdrift-0.20.1.tar.gz (523.6 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

cfgdrift-0.20.1-py3-none-any.whl (315.6 kB view details)

Uploaded Python 3

cfgdrift-0.20.1-cp313-cp313-win_amd64.whl (335.0 kB view details)

Uploaded CPython 3.13Windows x86-64

File details

Details for the file cfgdrift-0.20.1.tar.gz.

File metadata

  • Download URL: cfgdrift-0.20.1.tar.gz
  • Upload date:
  • Size: 523.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cfgdrift-0.20.1.tar.gz
Algorithm Hash digest
SHA256 12f2c088550aac63e3af0213acbf8c610647b2e71dbb303ece4308410299e818
MD5 cf123033c21efa611477315a2425c9a8
BLAKE2b-256 6442057086d34a953d1e521adfad371883c3c2ca93538dbef2695cf301a25a98

See more details on using hashes here.

File details

Details for the file cfgdrift-0.20.1-py3-none-any.whl.

File metadata

  • Download URL: cfgdrift-0.20.1-py3-none-any.whl
  • Upload date:
  • Size: 315.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cfgdrift-0.20.1-py3-none-any.whl
Algorithm Hash digest
SHA256 aed4a8d2c646bf96279a27ca34dbd48279d7b377e341470f8331faf70f5589de
MD5 41e209cb064cbd421d9dbb736ff4ce67
BLAKE2b-256 a3dceace2f40d938efe9c017c41528627170dd6a7e3af5b06356bd34fd28b16d

See more details on using hashes here.

File details

Details for the file cfgdrift-0.20.1-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: cfgdrift-0.20.1-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 335.0 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cfgdrift-0.20.1-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 4d0ed1ca86bc45946254de612a2572c7c90b66910d0c5e757d8f8956e77d944d
MD5 7d150b15c9b3e226778d91b5057bcd0c
BLAKE2b-256 eb9ea5215275de17c617f79d198aad797a9b0f074d8d8963fb4aba7c724b3c0a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page