上一轮那段"一键安装"是坏的,而且只在节点上坏。实测三段里漏了三件: 1. systemd 单元写着 `User=msa-agent`,而命令从没创建这个用户; 2. `enroll` 是 sudo 跑的,配置是 root 所有 0600,服务以另一个用户运行——读不到自己的私钥; 3. 单元从 `msa-agent.service` 这个仓库里的路径拷,而节点上没有仓库。 三段都"看起来对",因为它们各自是一行合理的 shell;错的是它们与单元之间的接缝。这正 是这个项目里反复出现的那一类缺陷。 现在有 `msa-agent install`: - 建 `--system --no-create-home --shell /usr/sbin/nologin` 的用户(已存在则跳过); - 建日志目录,并把配置、配置目录、日志目录 chown 给该用户; - 把 systemd 单元写进去。单元**嵌在二进制里**(`go:embed`),不是从仓库路径拷的,也不是 从 URL 下的——一个能发 unit 的服务器就能给节点塞一个后门 unit,那与"中继不可信"是同一 条理由。`--print-unit` 可以在装之前把它打出来看; - `daemon-reload` 并 enable/start。 幂等:每步先看已经是什么状态,所以升级或上次失败后重跑都安全。`--dry-run` 打印计划且什么 都不改,并且在缺二进制或配置时**不拒绝**——"还没装"正是会去跑 dry-run 的状态,它只把缺的 东西指出来。chown 走 Runner 而不是 os.Chown,这样整条序列都能在无 root 的情况下测。 install 与 uninstall 共用同一份 `Paths`:装了什么没卸掉会在机器上留一份凭据,卸了什么没装 过会在新节点上失败。单元也一样,`TestVendoredUnitMatchesSystemd` 守着嵌入副本与 `systemd/msa-agent.service` 不漂移。 手机上的安装命令相应简化:`install` 那一步取代了原先手工的 useradd/install/systemctl 三行, 卸载那段也先给 `--dry-run`。 测试新增五项:单元不漂移、install 满足单元的全部要求(用户、所有权、单元来自二进制而非仓库 路径)、install dry run 什么都不改、缺二进制或配置时拒绝且一条命令都不跑、dry run 在全新 节点上不拒绝而是指出缺什么。变异验证:去掉 chown、去掉建用户、让 dry run 执行命令——三处都 让对应测试失败。 Go 全包、Node 134 项、Swift 116 项通过。
55 lines
2.1 KiB
Makefile
55 lines
2.1 KiB
Makefile
POLICY_SRC := ../contracts/agent-policy.json
|
|
POLICY_DST := internal/policy/agent-policy.json
|
|
# The systemd unit is embedded in the binary so that `msa-agent install` needs no route to anything but
|
|
# the relay, and so the unit a node runs is the one its agent was built with. Vendored mechanically for
|
|
# the same reason the policy is: an operator editing the copy under internal/ would be editing a file
|
|
# the build overwrites, and TestVendoredUnitMatchesSystemd makes that loud.
|
|
UNIT_SRC := systemd/msa-agent.service
|
|
UNIT_DST := internal/install/msa-agent.service
|
|
# The version stamped into the binary, and the tag scripts/release.sh publishes under. It is the
|
|
# agent's own version rather than the app's: the two are released together but a node can be running an
|
|
# older agent than the phone, and the handshake's `agentBuild` field is what makes that visible.
|
|
VERSION ?= 0.3.0
|
|
LDFLAGS := -s -w -X main.version=$(VERSION)
|
|
|
|
.PHONY: all vendor test vet build build-arm64 build-armv7 clean
|
|
|
|
all: vet test build
|
|
|
|
# The policy is embedded, so the vendored copy is part of the binary. Keep the copy mechanical:
|
|
# an operator editing internal/policy/agent-policy.json by hand would be editing a file the build
|
|
# overwrites, and the drift test makes that mistake loud rather than quiet.
|
|
vendor: $(POLICY_DST) $(UNIT_DST)
|
|
|
|
$(POLICY_DST): $(POLICY_SRC)
|
|
@cp $(POLICY_SRC) $(POLICY_DST)
|
|
|
|
$(UNIT_DST): $(UNIT_SRC)
|
|
@cp $(UNIT_SRC) $(UNIT_DST)
|
|
|
|
test: vendor
|
|
@go test ./...
|
|
|
|
vet: vendor
|
|
@go vet ./...
|
|
|
|
fmt:
|
|
@gofmt -l -w .
|
|
|
|
build: vendor
|
|
@mkdir -p dist
|
|
@go build -trimpath -ldflags '$(LDFLAGS)' -o dist/msa-agent ./cmd/msa-agent
|
|
|
|
# Nodes are ARM Debian boxes that also run SimAdmin, so the static binary is copied in rather than
|
|
# installed through a package manager: no runtime deps, no apt state, trivially removable.
|
|
build-arm64: vendor
|
|
@mkdir -p dist
|
|
@CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -ldflags '$(LDFLAGS)' -o dist/msa-agent-linux-arm64 ./cmd/msa-agent
|
|
|
|
build-armv7: vendor
|
|
@mkdir -p dist
|
|
@CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -trimpath -ldflags '$(LDFLAGS)' -o dist/msa-agent-linux-armv7 ./cmd/msa-agent
|
|
|
|
clean:
|
|
@rm -rf dist
|