Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3856eed3b | ||
|
|
eac54f8c79 | ||
|
|
a8dfd7017b | ||
|
|
99f4cf0220 |
No files matched your search
@@ -33,11 +33,15 @@ jobs:
|
|||||||
asset: tsunagi-linux-x86_64
|
asset: tsunagi-linux-x86_64
|
||||||
archive: tar.gz
|
archive: tar.gz
|
||||||
zig: true
|
zig: true
|
||||||
|
deb: true
|
||||||
|
deb_arch: amd64
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
target: aarch64-unknown-linux-musl
|
target: aarch64-unknown-linux-musl
|
||||||
asset: tsunagi-linux-aarch64
|
asset: tsunagi-linux-aarch64
|
||||||
archive: tar.gz
|
archive: tar.gz
|
||||||
zig: true
|
zig: true
|
||||||
|
deb: true
|
||||||
|
deb_arch: arm64
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
target: aarch64-apple-darwin
|
target: aarch64-apple-darwin
|
||||||
asset: tsunagi-macos-aarch64
|
asset: tsunagi-macos-aarch64
|
||||||
@@ -133,13 +137,31 @@ jobs:
|
|||||||
tar -C dist/pkg -czf "${archive}" "${{ matrix.asset }}"
|
tar -C dist/pkg -czf "${archive}" "${{ matrix.asset }}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# A dependency-free .deb for the x86_64 and aarch64 Linux builds: it drops
|
||||||
|
# the static binary, the systemd service and the polkit rule. Built with
|
||||||
|
# dpkg-deb (present on the runner); see dist/deb/build-deb.sh.
|
||||||
|
- name: Build the Debian package
|
||||||
|
if: matrix.deb
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
version="${GITHUB_REF_NAME#v}"
|
||||||
|
bash dist/deb/build-deb.sh \
|
||||||
|
"target/${{ matrix.target }}/release/tsunagi" \
|
||||||
|
"${{ matrix.deb_arch }}" \
|
||||||
|
"$version" \
|
||||||
|
"tsunagi_${version}_${{ matrix.deb_arch }}.deb"
|
||||||
|
|
||||||
# @v3 on purpose: Gitea does not support the v4 artifact backend. This is
|
# @v3 on purpose: Gitea does not support the v4 artifact backend. This is
|
||||||
# what makes the archive show up under the run and hands it to `publish`.
|
# what makes the archive (and the .deb, where built) show up under the run
|
||||||
- name: Upload the archive as a run artifact
|
# and hands it to `publish`.
|
||||||
|
- name: Upload the build outputs as run artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.asset }}
|
name: ${{ matrix.asset }}
|
||||||
path: ${{ matrix.asset }}-*.*
|
path: |
|
||||||
|
${{ matrix.asset }}-*.*
|
||||||
|
*.deb
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
@@ -211,5 +233,5 @@ jobs:
|
|||||||
cat up.json >&2 || true
|
cat up.json >&2 || true
|
||||||
rc=1
|
rc=1
|
||||||
fi
|
fi
|
||||||
done < <(find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' \) -print0)
|
done < <(find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.deb' \) -print0)
|
||||||
exit "$rc"
|
exit "$rc"
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
# GitHub version of the release pipeline. The build half mirrors the Gitea one
|
||||||
|
# in .gitea/workflows/release.yml (static musl Linux via cargo-zigbuild, native
|
||||||
|
# macOS and Windows); only the publish half differs: GitHub needs the v4
|
||||||
|
# artifact backend and fills the release with `gh`.
|
||||||
|
#
|
||||||
|
# Every job is gated on `github.server_url == 'https://github.com'`, so this file
|
||||||
|
# runs only on GitHub. Gitea runs its own copy in .gitea/workflows; should a
|
||||||
|
# Gitea instance also read .github/workflows, the guard skips these jobs there
|
||||||
|
# so they never fail on the @v4 artifact backend or `gh`.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v*"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
CARGO_NET_RETRY: "10"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.asset }}
|
||||||
|
if: ${{ github.server_url == 'https://github.com' }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
target: x86_64-unknown-linux-musl
|
||||||
|
asset: tsunagi-linux-x86_64
|
||||||
|
archive: tar.gz
|
||||||
|
zig: true
|
||||||
|
deb: true
|
||||||
|
deb_arch: amd64
|
||||||
|
- os: ubuntu-latest
|
||||||
|
target: aarch64-unknown-linux-musl
|
||||||
|
asset: tsunagi-linux-aarch64
|
||||||
|
archive: tar.gz
|
||||||
|
zig: true
|
||||||
|
deb: true
|
||||||
|
deb_arch: arm64
|
||||||
|
- os: macos-latest
|
||||||
|
target: aarch64-apple-darwin
|
||||||
|
asset: tsunagi-macos-aarch64
|
||||||
|
archive: tar.gz
|
||||||
|
zig: false
|
||||||
|
- os: windows-latest
|
||||||
|
target: x86_64-pc-windows-msvc
|
||||||
|
asset: tsunagi-windows-x86_64
|
||||||
|
archive: zip
|
||||||
|
zig: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.target }}
|
||||||
|
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
key: ${{ matrix.target }}
|
||||||
|
|
||||||
|
# aws-lc-sys (iroh's rustls backend) and the bundled sqlite are C, and the
|
||||||
|
# musl targets have no prebuilt bindings, so bindgen needs libclang and the
|
||||||
|
# C build needs cmake. zig is the cross C compiler cargo-zigbuild drives.
|
||||||
|
- name: Install musl build tooling
|
||||||
|
if: matrix.zig
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends cmake clang libclang-dev
|
||||||
|
- name: Install zig
|
||||||
|
if: matrix.zig
|
||||||
|
uses: mlugg/setup-zig@v2
|
||||||
|
with:
|
||||||
|
# Pin a real, archived Zig release. Left unpinned the action resolves
|
||||||
|
# to the newest version it knows of (a yet-unreleased 0.16.0-dev),
|
||||||
|
# whose tarball 404s on ziglang.org while the community mirrors flake.
|
||||||
|
version: 0.14.1
|
||||||
|
- name: Install cargo-zigbuild
|
||||||
|
if: matrix.zig
|
||||||
|
uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: cargo-zigbuild
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if [[ "${{ matrix.zig }}" == "true" ]]; then
|
||||||
|
# zig's linker ignores the `-O1` GNU-ld optimization flag Rust passes
|
||||||
|
# and says so on stderr, which rustc now surfaces as a linker_messages
|
||||||
|
# warning. It is cosmetic — the binary is correct — so quiet just that
|
||||||
|
# one lint to keep the musl build log clean. A real link error still
|
||||||
|
# fails the build.
|
||||||
|
export RUSTFLAGS="${RUSTFLAGS:-} -A linker_messages"
|
||||||
|
cargo zigbuild --release --locked --target "${{ matrix.target }}" --bin tsunagi
|
||||||
|
else
|
||||||
|
cargo build --release --locked --target "${{ matrix.target }}" --bin tsunagi
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Package
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
version="${GITHUB_REF_NAME#v}"
|
||||||
|
stage="dist/pkg/${{ matrix.asset }}"
|
||||||
|
mkdir -p "$stage"
|
||||||
|
|
||||||
|
bin="tsunagi"
|
||||||
|
[[ "${{ runner.os }}" == "Windows" ]] && bin="tsunagi.exe"
|
||||||
|
cp "target/${{ matrix.target }}/release/${bin}" "$stage/"
|
||||||
|
|
||||||
|
# The top-level README, plus the per-OS install notes and integration
|
||||||
|
# files, so the archive carries what the platform needs to set up.
|
||||||
|
cp README.md "$stage/"
|
||||||
|
case "${{ runner.os }}" in
|
||||||
|
Linux)
|
||||||
|
cp dist/linux/tsunagi.service dist/linux/install.sh "$stage/"
|
||||||
|
cp dist/linux/README.md "$stage/INSTALL.md"
|
||||||
|
;;
|
||||||
|
macOS)
|
||||||
|
cp dist/macos/cy.hexor.tsunagi.plist "$stage/"
|
||||||
|
cp dist/macos/README.md "$stage/INSTALL.md"
|
||||||
|
;;
|
||||||
|
Windows)
|
||||||
|
cp dist/windows/README.md "$stage/INSTALL.md"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
archive="${{ matrix.asset }}-${version}.${{ matrix.archive }}"
|
||||||
|
if [[ "${{ matrix.archive }}" == "zip" ]]; then
|
||||||
|
(cd dist/pkg && 7z a "../../${archive}" "${{ matrix.asset }}")
|
||||||
|
else
|
||||||
|
tar -C dist/pkg -czf "${archive}" "${{ matrix.asset }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A dependency-free .deb for the x86_64 and aarch64 Linux builds: it drops
|
||||||
|
# the static binary, the systemd service and the polkit rule. Built with
|
||||||
|
# dpkg-deb (present on the runner); see dist/deb/build-deb.sh.
|
||||||
|
- name: Build the Debian package
|
||||||
|
if: matrix.deb
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
version="${GITHUB_REF_NAME#v}"
|
||||||
|
bash dist/deb/build-deb.sh \
|
||||||
|
"target/${{ matrix.target }}/release/tsunagi" \
|
||||||
|
"${{ matrix.deb_arch }}" \
|
||||||
|
"$version" \
|
||||||
|
"tsunagi_${version}_${{ matrix.deb_arch }}.deb"
|
||||||
|
|
||||||
|
- name: Upload the build outputs as run artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.asset }}
|
||||||
|
path: |
|
||||||
|
${{ matrix.asset }}-*.*
|
||||||
|
*.deb
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
publish:
|
||||||
|
name: Publish release
|
||||||
|
needs: build
|
||||||
|
if: ${{ github.server_url == 'https://github.com' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Download every build artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
- name: Show what was collected
|
||||||
|
run: find artifacts -type f
|
||||||
|
|
||||||
|
- name: Create the release and upload the archives
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
TAG: ${{ github.ref_name }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# download-artifact@v4 nests each artifact under its own directory, so
|
||||||
|
# the archives are artifacts/<asset>/<file>.
|
||||||
|
mapfile -t files < <(find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.deb' \))
|
||||||
|
printf 'asset: %s\n' "${files[@]}"
|
||||||
|
|
||||||
|
prerelease=()
|
||||||
|
case "$TAG" in *-*) prerelease=(--prerelease) ;; esac
|
||||||
|
|
||||||
|
# Create the release on the first run; on a re-run, add/replace assets
|
||||||
|
# on the release that is already there.
|
||||||
|
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||||
|
gh release upload "$TAG" "${files[@]}" --repo "$GITHUB_REPOSITORY" --clobber
|
||||||
|
else
|
||||||
|
gh release create "$TAG" "${files[@]}" \
|
||||||
|
--repo "$GITHUB_REPOSITORY" \
|
||||||
|
--title "tsunagi $TAG" \
|
||||||
|
--generate-notes \
|
||||||
|
--verify-tag \
|
||||||
|
"${prerelease[@]}"
|
||||||
|
fi
|
||||||
Vendored
+25
@@ -0,0 +1,25 @@
|
|||||||
|
// Installed by the tsunagi package.
|
||||||
|
//
|
||||||
|
// Lets a non-root agent configure systemd-resolved for its overlay zones — the
|
||||||
|
// four resolve1 actions it calls, and nothing else — for any user in the
|
||||||
|
// "tsunagi" group (created by the package). The packaged systemd service runs
|
||||||
|
// as root and does not need this rule; it is for running the agent as your own
|
||||||
|
// user instead:
|
||||||
|
//
|
||||||
|
// sudo usermod -aG tsunagi "$USER"
|
||||||
|
// sudo setcap cap_net_admin,cap_net_bind_service+p /usr/bin/tsunagi
|
||||||
|
// tsunagi up
|
||||||
|
//
|
||||||
|
// polkit decides by user/group id, not by capability, which is why the resolver
|
||||||
|
// needs this rule even once the binary has the capability.
|
||||||
|
polkit.addRule(function(action, subject) {
|
||||||
|
var allowed = [
|
||||||
|
"org.freedesktop.resolve1.set-dns-servers",
|
||||||
|
"org.freedesktop.resolve1.set-domains",
|
||||||
|
"org.freedesktop.resolve1.set-default-route",
|
||||||
|
"org.freedesktop.resolve1.revert"
|
||||||
|
];
|
||||||
|
if (allowed.indexOf(action.id) >= 0 && subject.isInGroup("tsunagi")) {
|
||||||
|
return polkit.Result.YES;
|
||||||
|
}
|
||||||
|
});
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Assemble a dependency-free Debian package from a prebuilt static tsunagi
|
||||||
|
# binary, using only dpkg-deb (no cargo-deb, no nfpm). The binary is statically
|
||||||
|
# linked, so the package declares no Depends and runs on any Debian/Ubuntu.
|
||||||
|
#
|
||||||
|
# Usage: build-deb.sh <binary> <deb_arch> <version> <output.deb>
|
||||||
|
# <binary> path to the built tsunagi executable
|
||||||
|
# <deb_arch> Debian architecture: amd64 or arm64
|
||||||
|
# <version> package version (the tag without its leading v)
|
||||||
|
# <output> path to write the .deb to
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
binary="$1"
|
||||||
|
arch="$2"
|
||||||
|
version="$3"
|
||||||
|
output="$4"
|
||||||
|
|
||||||
|
here="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
root="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$root"' EXIT
|
||||||
|
|
||||||
|
# Payload. Debian installs to /usr/bin (not /usr/local), so the service's
|
||||||
|
# ExecStart is rewritten to match; the source unit targets /usr/local/bin for
|
||||||
|
# the tarball installer.
|
||||||
|
install -D -m 0755 "$binary" "$root/usr/bin/tsunagi"
|
||||||
|
|
||||||
|
mkdir -p "$root/lib/systemd/system"
|
||||||
|
sed 's#/usr/local/bin/tsunagi#/usr/bin/tsunagi#' \
|
||||||
|
"$here/../linux/tsunagi.service" > "$root/lib/systemd/system/tsunagi.service"
|
||||||
|
chmod 0644 "$root/lib/systemd/system/tsunagi.service"
|
||||||
|
|
||||||
|
install -D -m 0644 "$here/50-tsunagi-resolved.rules" \
|
||||||
|
"$root/usr/share/polkit-1/rules.d/50-tsunagi-resolved.rules"
|
||||||
|
install -D -m 0644 "$here/../../README.md" "$root/usr/share/doc/tsunagi/README.md"
|
||||||
|
install -D -m 0644 "$here/../linux/README.md" "$root/usr/share/doc/tsunagi/INSTALL.md"
|
||||||
|
|
||||||
|
mkdir -p "$root/DEBIAN"
|
||||||
|
|
||||||
|
cat > "$root/DEBIAN/control" <<CTRL
|
||||||
|
Package: tsunagi
|
||||||
|
Version: ${version}
|
||||||
|
Architecture: ${arch}
|
||||||
|
Maintainer: AB <ab@hexor.cy>
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Homepage: https://github.com/Ultradesu/tsunagi
|
||||||
|
Description: Serverless private mesh networking agent
|
||||||
|
tsunagi forms small private mesh IP networks between peers, with NAT
|
||||||
|
traversal and no central server. This package installs a static,
|
||||||
|
dependency-free binary, a systemd service that runs the agent as root, and a
|
||||||
|
polkit rule that lets a non-root agent configure systemd-resolved.
|
||||||
|
CTRL
|
||||||
|
|
||||||
|
# A system group for the optional non-root run (the polkit rule grants it the
|
||||||
|
# resolve1 actions). The packaged service runs as root and does not need it.
|
||||||
|
cat > "$root/DEBIAN/postinst" <<'POSTINST'
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
if ! getent group tsunagi >/dev/null 2>&1; then
|
||||||
|
addgroup --system tsunagi >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
if [ -d /run/systemd/system ]; then
|
||||||
|
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
POSTINST
|
||||||
|
|
||||||
|
cat > "$root/DEBIAN/prerm" <<'PRERM'
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
if [ "$1" = remove ] || [ "$1" = purge ]; then
|
||||||
|
if [ -d /run/systemd/system ]; then
|
||||||
|
systemctl disable --now tsunagi.service >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
PRERM
|
||||||
|
|
||||||
|
cat > "$root/DEBIAN/postrm" <<'POSTRM'
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
if [ -d /run/systemd/system ]; then
|
||||||
|
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
POSTRM
|
||||||
|
|
||||||
|
chmod 0755 "$root/DEBIAN/postinst" "$root/DEBIAN/prerm" "$root/DEBIAN/postrm"
|
||||||
|
|
||||||
|
# --root-owner-group writes the payload as root:root without needing fakeroot.
|
||||||
|
dpkg-deb --root-owner-group --build "$root" "$output"
|
||||||
|
echo "built $output"
|
||||||
Reference in new issue
Block a user