半公开Nix配置的版本控制
闲话:NixOS 上 secret managing 是一个很有争议也很麻烦的事,因为/nix/store
是 world readable 的,因而需要 sops-nix、agenix 等方案。
不过今天不讲这件事,而是一个与此有所相关的问题:如何公开Nix配置的仓库,但使其中一些隐私信息保持隐藏?说有所相关是因为这两个问题常被同时提及,但实际上有相当大的不同:
- 不论仓库是否公开,secrets 都不应该进入
/nix/store
,解决办法是让 secrets 的内容不在 eval 过程中出现。sops-nix 和 agenix 其实就是这样的,它们只是一堆系统激活时的脚本,利用系统 ssh 私钥或者某个硬编码路径上的 key 来解密出所有 secrets 并放到合适的地方,设置合适的权限。 - 而在另一个问题上,要隐藏的东西完全可以是必须在 eval 过程中出现的,或者不在乎进入
/nix/store
的,比如电子邮箱、源站IP,甚至可能想要隐藏主机名。
对于今天的主题问题,最简单的解决方法是管理两个分支,一个 push 到 public repository 上,一个 push 到 private repository 上。看上去很简单,实际上就是超级简单。要是前一个问题也是这样简单就好了。
设置
我实际用的版本控制工具是 jj,心智负担很低。还能没有 dirty 状态,自动 rebase,对接下来的工作流很适合。当然用 Git 也毫无问题,但是得常常git add
和git commit --amend
,不然 dirty 状态很麻烦。
首先把非 secrets 的隐藏信息都写到同一个文件或文件夹中,比如priv.nix
,然后在引用处用任何一种喜欢的方式引用这里的内容。把priv.nix
的内容替换为无意义内容,这样自然得到两个分支pub
和pri
,使pub:/priv.nix
无意义而pri:/priv.nix
保存了隐藏信息,并且pri
领先pub
一个 commit,diff 内容就是干净的一个priv.nix
更改,这样 rebase 几乎总是成功。
分别设置 remote,一个公开,一个私有(顺带可以跑 CI)。
用 jj 的 workspace(对应 Git 的 worktree)给pub
、pri
各一个目录,在pub
编写,随手把pri
rebase 到pub
后在pri
调试。
除了pri
以外可以自由分支自由发挥,本质上只是在pri
维护了一个priv.nix
的 diff,随手 rebase 就好了。
日常修改:jj new -A pub
,然后开写,写完jj
一下pri
就自动 rebase 好了。
到处开分支:jj new pub
,然后开写,写完jj rebase -s pri -d @
一下就好了。