diff options
| author | Nikolay Govorov <me@govorov.online> | 2026-05-17 03:04:58 +0100 |
|---|---|---|
| committer | Nikolay Govorov <me@govorov.online> | 2026-05-17 04:13:14 +0100 |
| commit | 10a73f38116adb4003bdf4c4e180f3bd5b9177a3 (patch) | |
| tree | 0f27fb70f07b5c418593a760eaf7346ae5932d04 | |
| parent | 83cf86e65529d897d16f134a20618e1685415a0a (diff) | |
| download | tar tar.gz tar.bz2 tar.lz tar.xz tar.zst zip | |
Bootstrap mirum agent
Diffstat
| -rw-r--r-- | .github/workflows/build.yml | 5 | +5 −0 |
| -rw-r--r-- | .gitignore | 5 | +5 −0 |
| -rw-r--r-- | REUSE.toml | 1 | +1 −0 |
| -rw-r--r-- | Taskfile.yml | 60 | +60 −0 |
| -rw-r--r-- | cmd/mirum-agent/build.zig | 113 | +113 −0 |
| -rw-r--r-- | cmd/mirum-agent/build.zig.zon | 17 | +17 −0 |
| -rw-r--r-- | cmd/mirum-agent/main.c | 10 | +10 −0 |
| -rw-r--r-- | cmd/mirum-agent/mirum-agent.c | 10 | +10 −0 |
| -rw-r--r-- | cmd/mirum-agent/mirum-agent.h | 9 | +9 −0 |
| -rw-r--r-- | cmd/mirum-agent/test.c | 22 | +22 −0 |
| -rw-r--r-- | nfpm.yaml | 7 | +7 −0 |
11 files changed, 259 insertions, 0 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8310bb..38bb2dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,6 +29,11 @@ jobs: with: go-version-file: go.mod + - uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1 + with: + mirror: https://pkg.earth/zig # maintained by mirum author + version: 0.16.0 # keep in sync with build.zig.zon + - name: Install tools run: | echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list diff --git a/.gitignore b/.gitignore index e9e681e..426c177 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,11 @@ cmd/mirum-server/static cmd/mirum-server/web/node_modules +# zig build artifacts +.zig-cache/ +zig-out/ +zig-pkg/ + # grpc generated code /internal/protocol/wirepb /cmd/mirum-server/apipb diff --git a/REUSE.toml b/REUSE.toml index 791cdce..5a6cb57 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -8,6 +8,7 @@ path = [ ".mailmap", "CLA.md", "VERSION", + "cmd/mirum-agent/build.zig.zon", "cmd/mirum-server/web/*.json", "go.mod", "go.sum", diff --git a/Taskfile.yml b/Taskfile.yml index 4ba97ed..6dcac22 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -16,6 +16,15 @@ vars: DIST_DIR: build/dist BUILD_DIR: build LINUX_PKG_TARGETS: amd64 arm64 riscv64 ppc64le loong64 s390x + # Guest matrix for mirum-agent — a strict superset of the host cross + # matrix. Extend here as more guest targets are supported. + AGENT_TARGETS: >- + linux-amd64 linux-arm64 linux-riscv64 linux-ppc64le linux-loong64 linux-s390x + darwin-amd64 darwin-arm64 + windows-amd64 windows-arm64 + freebsd-amd64 freebsd-arm64 freebsd-riscv64 + netbsd-amd64 netbsd-arm64 + openbsd-amd64 openbsd-arm64 tasks: # Production build pipeline @@ -114,8 +123,55 @@ tasks: - go build -ldflags="{{.LDFLAGS}}" -o {{.BUILD_DIR}}/mirum-worker-{{.GOOS}}-{{.GOARCH}} ./cmd/mirum-worker - go build -ldflags="{{.LDFLAGS}}" -o {{.BUILD_DIR}}/mirum-{{.GOOS}}-{{.GOARCH}} ./cmd/mirum + agent:build: + desc: "Build mirum-agent for one guest target (override GOOS/GOARCH)" + dir: cmd/mirum-agent + vars: + GOOS: { sh: "echo ${GOOS:-$(go env GOOS)}" } + GOARCH: { sh: "echo ${GOARCH:-$(go env GOARCH)}" } + cmds: + - | + case "{{.GOARCH}}" in + amd64) za=x86_64 ;; + arm64) za=aarch64 ;; + riscv64) za=riscv64 ;; + ppc64le) za=powerpc64le ;; + loong64) za=loongarch64 ;; + s390x) za=s390x ;; + *) echo "agent: unsupported arch {{.GOARCH}}" >&2; exit 1 ;; + esac + case "{{.GOOS}}" in + linux) ztriple="${za}-linux" ;; + darwin) ztriple="${za}-macos" ;; + windows) ztriple="${za}-windows-gnu" ;; + freebsd) ztriple="${za}-freebsd" ;; + openbsd) ztriple="${za}-openbsd" ;; + netbsd) ztriple="${za}-netbsd" ;; + *) echo "agent: unsupported os {{.GOOS}}" >&2; exit 1 ;; + esac + ext=""; [ "{{.GOOS}}" = windows ] && ext=.exe + zig build -Dtarget="$ztriple" -Doptimize=ReleaseFast -Dstrip + mkdir -p ../../{{.BUILD_DIR}}/agent + cp "zig-out/bin/mirum-agent${ext}" "../../{{.BUILD_DIR}}/agent/mirum-agent-{{.GOOS}}-{{.GOARCH}}${ext}" + + agent:cross: + desc: Cross-compile mirum-agent for the full guest matrix + cmds: + - rm -rf {{.BUILD_DIR}}/agent + - for: { var: AGENT_TARGETS } + cmd: | + target="{{.ITEM}}" + task agent:build GOOS="${target%-*}" GOARCH="${target##*-}" + + agent:test: + desc: Build and run mirum-agent unit tests + dir: cmd/mirum-agent + cmds: + - zig build test + cross: desc: Cross-compile and archive binaries for all supported platforms + deps: [agent:cross] cmds: - mkdir -p {{.DIST_DIR}} - for: [ @@ -140,8 +196,10 @@ tasks: cp -r LICENSES "$staging/" for cmd in cmd/*/; do bin=$(basename "$cmd") + [ "$bin" = "mirum-agent" ] && continue cp "{{.BUILD_DIR}}/${bin}-${os}-${arch}" "${staging}/${bin}${ext}" done + cp -r "{{.BUILD_DIR}}/agent" "$staging/agent" if [ "$os" = "windows" ]; then (cd "$staging" && zip -qr "$OLDPWD/{{.DIST_DIR}}/mirum-${target}.zip" .) @@ -198,6 +256,7 @@ tasks: mkdir -p {{.BUILD_DIR}}/tmp for cmd in cmd/*/; do bin=$(basename "$cmd") + [ "$bin" = "mirum-agent" ] && continue cp "{{.BUILD_DIR}}/${bin}-linux-${arch}" "{{.BUILD_DIR}}/tmp/${bin}" done ARCH=$arch nfpm package --packager deb --target {{.DIST_DIR}}/ @@ -515,5 +574,6 @@ tasks: CGO_ENABLED: "1" # required for -race cmds: - go test -race -count=1 ./... + - task: agent:test # yaml-language-server: $schema=https://taskfile.dev/schema.json diff --git a/cmd/mirum-agent/build.zig b/cmd/mirum-agent/build.zig new file mode 100644 --- /dev/null +++ b/cmd/mirum-agent/build.zig @@ -0,0 +1,113 @@ +// Copyright (c) 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{ + .default_target = .{ .abi = .musl }, + }); + const optimize = b.standardOptimizeOption(.{}); + + const strip = b.option(bool, "strip", "Strip debug info from the agent binary") orelse false; + + // Strict flags for our own C. Unity is compiled separately, without + // them — a third-party header should not have to satisfy our lint. + const cflags: []const []const u8 = &.{ + "-std=c99", + "-Wall", + "-Wextra", + "-Wconversion", + "-Wshadow", + "-Wstrict-prototypes", + }; + + // libmirum-agent: the agent logic, compiled once and exposed only + // through mirum-agent.h. Both the executable and the tests link it. + const lib = b.addLibrary(.{ + .name = "mirum-agent", + .linkage = .static, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .strip = strip, + .link_libc = true, + .link_libcpp = false, + }), + }); + lib.root_module.addIncludePath(b.path("")); + lib.root_module.addCSourceFile(.{ + .file = b.path("mirum-agent.c"), + .flags = cflags, + }); + + // mirum-agent: the executable entry point, links the library. + const exe = b.addExecutable(.{ + .name = "mirum-agent", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .strip = strip, + .link_libc = true, + .link_libcpp = false, + }), + }); + exe.root_module.addIncludePath(b.path("")); + exe.root_module.addCSourceFile(.{ + .file = b.path("main.c"), + .flags = cflags, + }); + exe.root_module.linkLibrary(lib); + + b.installArtifact(exe); + + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd.addArgs(args); + + const run_step = b.step("run", "Run the agent"); + run_step.dependOn(&run_cmd.step); + + // Unity: built as its own library so its sources never see our flags. + const unity_dep = b.dependency("unity", .{}); + const unity = b.addLibrary(.{ + .name = "unity", + .linkage = .static, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + .link_libcpp = false, + }), + }); + unity.root_module.addIncludePath(unity_dep.path("src")); + unity.root_module.addCSourceFile(.{ + .file = unity_dep.path("src/unity.c"), + }); + + // test: links libmirum-agent through its public header only — the + // agent sources are never recompiled into the test binary. Unity's + // headers go on the system path so they bypass our warnings. + const exe_tests = b.addExecutable(.{ + .name = "test", + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + .link_libcpp = false, + }), + }); + exe_tests.root_module.addIncludePath(b.path("")); + exe_tests.root_module.addSystemIncludePath(unity_dep.path("src")); + exe_tests.root_module.addCSourceFile(.{ + .file = b.path("test.c"), + .flags = cflags, + }); + exe_tests.root_module.linkLibrary(lib); + exe_tests.root_module.linkLibrary(unity); + + const run_exe_tests = b.addRunArtifact(exe_tests); + + const test_step = b.step("test", "Run tests"); + test_step.dependOn(&run_exe_tests.step); +} diff --git a/cmd/mirum-agent/build.zig.zon b/cmd/mirum-agent/build.zig.zon new file mode 100644 --- /dev/null +++ b/cmd/mirum-agent/build.zig.zon @@ -0,0 +1,17 @@ +.{ + .name = .agent, + .version = "0.0.0", + .fingerprint = 0x268b9c9d6e24fb9b, // Changing this has security and trust implications. + .minimum_zig_version = "0.16.0", // keep in sync with github actions + .dependencies = .{ + .unity = .{ + .url = "https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.6.1.tar.gz", + .hash = "N-V-__8AAAQfEgAjW551lOzfHoVAve6KndztgTjCXsJvElP9", + }, + }, + .paths = .{ + "build.zig", "build.zig.zon", + "test.c", "main.c", + "mirum-agent.c", "mirum-agent.h", + }, +} diff --git a/cmd/mirum-agent/main.c b/cmd/mirum-agent/main.c new file mode 100644 --- /dev/null +++ b/cmd/mirum-agent/main.c @@ -0,0 +1,10 @@ +// Copyright (c) 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +#include "mirum-agent.h" + +int main(int argc, const char *argv[]) { + mirum_init(); + + return 0; +} diff --git a/cmd/mirum-agent/mirum-agent.c b/cmd/mirum-agent/mirum-agent.c new file mode 100644 --- /dev/null +++ b/cmd/mirum-agent/mirum-agent.c @@ -0,0 +1,10 @@ +// Copyright (c) 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +#include <stdio.h> + +#include "mirum-agent.h" + +void mirum_init(void) { + printf("This is %s\n", "mirum-agent"); +} diff --git a/cmd/mirum-agent/mirum-agent.h b/cmd/mirum-agent/mirum-agent.h new file mode 100644 --- /dev/null +++ b/cmd/mirum-agent/mirum-agent.h @@ -0,0 +1,9 @@ +// Copyright (c) 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +#ifndef MIRUM_AGENT_H +#define MIRUM_AGENT_H + +void mirum_init(void); + +#endif // MIRUM_AGENT_H diff --git a/cmd/mirum-agent/test.c b/cmd/mirum-agent/test.c new file mode 100644 --- /dev/null +++ b/cmd/mirum-agent/test.c @@ -0,0 +1,22 @@ +// Copyright (c) 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +#include "unity.h" + +#include "mirum-agent.h" + +void setUp(void) {} +void tearDown(void) {} + +// Smoke test: the public entry point links and runs without crashing. +// Substantive suites (TLV decode, channel state machine) land with that +// code, exercising mirum-agent.h the same way. +static void test_mirum_init_runs(void) { + mirum_init(); +} + +int main(void) { + UNITY_BEGIN(); + RUN_TEST(test_mirum_init_runs); + return UNITY_END(); +} diff --git a/nfpm.yaml b/nfpm.yaml index 3ade60c..2fa1f6b 100644 --- a/nfpm.yaml +++ b/nfpm.yaml @@ -33,6 +33,13 @@ contents: file_info: mode: 0755 + # mirum-agent guest binaries — payload the worker injects into VMs. + # Not host executables; the full guest matrix ships in every package. + - src: build/agent/mirum-agent-* + dst: /usr/lib/mirum/agent/ + file_info: + mode: 0755 + - src: packaging/server/config.yaml dst: /etc/mirum/server/config.yaml type: config|noreplace |
