半公开Nix配置的版本控制

3 min

闲话: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 addgit commit --amend,不然 dirty 状态很麻烦。

首先把非 secrets 的隐藏信息都写到同一个文件或文件夹中,比如priv.nix,然后在引用处用任何一种喜欢的方式引用这里的内容。把priv.nix的内容替换为无意义内容,这样自然得到两个分支pubpri,使pub:/priv.nix无意义而pri:/priv.nix保存了隐藏信息,并且pri领先pub一个 commit,diff 内容就是干净的一个priv.nix更改,这样 rebase 几乎总是成功。

分别设置 remote,一个公开,一个私有(顺带可以跑 CI)。

用 jj 的 workspace(对应 Git 的 worktree)给pubpri各一个目录,在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 @一下就好了。