feat: add changelog and semver-tagged releases
This commit is contained in:
parent
50e5e444bc
commit
ddd1687eca
4 changed files with 53 additions and 14 deletions
23
CHANGELOG.md
Normal file
23
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The version lives in `Cargo.toml`; the flake and the release apps read it from there.
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.1.0] - 2026-10-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Smol Mail 1.1 server over Noise_NX TCP: `AUTH`, `RESOLVE`, `SEND`, `FETCH`, `DELETE` and `REGISTER`, with accept tokens, main/requests quota tiers, fetch cursors, `REGISTER` proof of possession and dual-signed key rotation chains.
|
||||||
|
- Smol Mail 1.2 RNS carrier behind the `rns` feature, over a patched microReticulum fork, with an idle-link reaper, refusal logging and per-link limits.
|
||||||
|
- Multiple domains in one process, each with its own key, port and database.
|
||||||
|
- Sliding-window rate limits and a TCP connection cap (`--max-connections`).
|
||||||
|
- Frame header deadline against slow clients.
|
||||||
|
- Debug-level per-operation, session and link metrics (`--verbose`).
|
||||||
|
- Hostile test harness and multi-session driver.
|
||||||
|
- Nix flake with `packages.default`, `packages.rns`, a static musl `packages.static`, and a NixOS module.
|
||||||
|
- Container image with a self-provisioning entrypoint.
|
||||||
|
- `release-static` and `release-container` flake apps publishing to Forgejo.
|
||||||
|
|
||||||
|
[Unreleased]: https://code.randogoth.com/randogoth/bunshin/compare/v0.1.0...HEAD
|
||||||
|
[0.1.0]: https://code.randogoth.com/randogoth/bunshin/releases/tag/v0.1.0
|
||||||
|
|
@ -137,6 +137,10 @@ bunshin serve --key server.key --db mail.db --host 0.0.0.0 --port 1961
|
||||||
|
|
||||||
`--verbose` (or `services.bunshin.verbose` in the NixOS module) raises logging to debug level, which adds server-side metrics on both carriers: per-operation timing, request and response sizes, handshake duration, per-session summaries, and RNS link events. The default info level stays quiet on success.
|
`--verbose` (or `services.bunshin.verbose` in the NixOS module) raises logging to debug level, which adds server-side metrics on both carriers: per-operation timing, request and response sizes, handshake duration, per-session summaries, and RNS link events. The default info level stays quiet on success.
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
Versions follow [Semantic Versioning](https://semver.org); changes are recorded in [CHANGELOG.md](CHANGELOG.md). To cut a release, bump `version` in `Cargo.toml`, move the `Unreleased` changelog entries under the new version, commit, tag the commit `v<version>` and push the tag, then run `nix run .#release-static` and `nix run .#release-container`. Both refuse to publish unless `HEAD` carries the matching tag; the container is pushed as `:<version>` and `:latest`.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Implements SPEC.md version 1.1 in full: `AUTH`, `RESOLVE`, `SEND`, `FETCH`, `DELETE` and `REGISTER`, including accept tokens and the main/requests tier split, fetch cursors, 32-byte message ids, `REGISTER` proof of possession, and dual-signed key rotation chains.
|
Implements SPEC.md version 1.1 in full: `AUTH`, `RESOLVE`, `SEND`, `FETCH`, `DELETE` and `REGISTER`, including accept tokens and the main/requests tier split, fetch cursors, 32-byte message ids, `REGISTER` proof of possession, and dual-signed key rotation chains.
|
||||||
|
|
|
||||||
38
flake.nix
38
flake.nix
|
|
@ -69,9 +69,12 @@
|
||||||
RNS_MICROSTORE_SOURCE_DIR = "${rns-microstore}";
|
RNS_MICROSTORE_SOURCE_DIR = "${rns-microstore}";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Cargo.toml is the single source of the semver version.
|
||||||
|
version = (lib.importTOML ./Cargo.toml).package.version;
|
||||||
|
|
||||||
bunshin = { rns ? false }: pkgs.rustPlatform.buildRustPackage {
|
bunshin = { rns ? false }: pkgs.rustPlatform.buildRustPackage {
|
||||||
pname = "bunshin";
|
pname = "bunshin";
|
||||||
version = "0.1.0";
|
inherit version;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
nativeBuildInputs = [ pkgs.pkg-config ]
|
nativeBuildInputs = [ pkgs.pkg-config ]
|
||||||
|
|
@ -97,7 +100,7 @@
|
||||||
# see apps.release-static.
|
# see apps.release-static.
|
||||||
packages.static = pkgs.pkgsStatic.rustPlatform.buildRustPackage {
|
packages.static = pkgs.pkgsStatic.rustPlatform.buildRustPackage {
|
||||||
pname = "bunshin";
|
pname = "bunshin";
|
||||||
version = "0.1.0";
|
inherit version;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
nativeBuildInputs = [ pkgs.pkgsStatic.pkg-config ];
|
nativeBuildInputs = [ pkgs.pkgsStatic.pkg-config ];
|
||||||
|
|
@ -110,9 +113,10 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
# Builds packages.static and publishes it as a Forgejo release on
|
# Builds packages.static and publishes it as a Forgejo release on
|
||||||
# this repo, tagged by short commit hash (creating the release if
|
# this repo, tagged v<Cargo.toml version> (creating the release if
|
||||||
# it doesn't exist yet, replacing the asset if it does — safe to
|
# it doesn't exist yet, replacing the asset if it does — safe to
|
||||||
# rerun for the same commit). Needs FORGEJO_TOKEN (a token with
|
# rerun). Refuses unless HEAD carries that tag, so a release always
|
||||||
|
# matches a bumped version and its CHANGELOG entry. Needs FORGEJO_TOKEN (a token with
|
||||||
# write:repository scope) in the environment; run from a checkout
|
# write:repository scope) in the environment; run from a checkout
|
||||||
# so `git rev-parse` and the `.` flake ref resolve to the right
|
# so `git rev-parse` and the `.` flake ref resolve to the right
|
||||||
# place.
|
# place.
|
||||||
|
|
@ -129,7 +133,11 @@
|
||||||
fi
|
fi
|
||||||
: "''${FORGEJO_TOKEN:?set FORGEJO_TOKEN (env or .env) to a Forgejo token with write:repository scope}"
|
: "''${FORGEJO_TOKEN:?set FORGEJO_TOKEN (env or .env) to a Forgejo token with write:repository scope}"
|
||||||
|
|
||||||
rev=$(git rev-parse --short HEAD)
|
tag="v${version}"
|
||||||
|
if [ "$(git rev-parse -q --verify "$tag^{commit}" || true)" != "$(git rev-parse HEAD)" ]; then
|
||||||
|
echo "HEAD is not tagged $tag; bump Cargo.toml and CHANGELOG.md, then tag the release commit" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
sha=$(git rev-parse HEAD)
|
sha=$(git rev-parse HEAD)
|
||||||
out=$(nix build .#static --no-link --print-out-paths)
|
out=$(nix build .#static --no-link --print-out-paths)
|
||||||
bin="$out/bin/bunshin"
|
bin="$out/bin/bunshin"
|
||||||
|
|
@ -137,10 +145,10 @@
|
||||||
api="https://code.randogoth.com/api/v1/repos/randogoth/bunshin"
|
api="https://code.randogoth.com/api/v1/repos/randogoth/bunshin"
|
||||||
auth=(-H "Authorization: token ''${FORGEJO_TOKEN}")
|
auth=(-H "Authorization: token ''${FORGEJO_TOKEN}")
|
||||||
|
|
||||||
release_id=$(curl -sS "''${auth[@]}" "$api/releases/tags/$rev" | jq -r '.id // empty')
|
release_id=$(curl -sS "''${auth[@]}" "$api/releases/tags/$tag" | jq -r '.id // empty')
|
||||||
if [ -z "$release_id" ]; then
|
if [ -z "$release_id" ]; then
|
||||||
release_id=$(curl -sSf "''${auth[@]}" -H "Content-Type: application/json" \
|
release_id=$(curl -sSf "''${auth[@]}" -H "Content-Type: application/json" \
|
||||||
-d "$(jq -n --arg tag "$rev" --arg sha "$sha" \
|
-d "$(jq -n --arg tag "$tag" --arg sha "$sha" \
|
||||||
'{tag_name:$tag, target_commitish:$sha, name:$tag, body:"Static musl build.", draft:false, prerelease:false}')" \
|
'{tag_name:$tag, target_commitish:$sha, name:$tag, body:"Static musl build.", draft:false, prerelease:false}')" \
|
||||||
"$api/releases" | jq -r '.id')
|
"$api/releases" | jq -r '.id')
|
||||||
fi
|
fi
|
||||||
|
|
@ -151,15 +159,15 @@
|
||||||
fi
|
fi
|
||||||
curl -sSf "''${auth[@]}" -F "attachment=@$bin;filename=bunshin" "$api/releases/$release_id/assets?name=bunshin" >/dev/null
|
curl -sSf "''${auth[@]}" -F "attachment=@$bin;filename=bunshin" "$api/releases/$release_id/assets?name=bunshin" >/dev/null
|
||||||
|
|
||||||
echo "released: https://code.randogoth.com/randogoth/bunshin/releases/tag/$rev"
|
echo "released: https://code.randogoth.com/randogoth/bunshin/releases/tag/$tag"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Builds the Containerfile image (same non-rns build the release
|
# Builds the Containerfile image (same non-rns build the release
|
||||||
# binary is, see its header comment) and pushes it to this repo's
|
# binary is, see its header comment) and pushes it to this repo's
|
||||||
# Forgejo container registry, tagged by short commit hash and
|
# Forgejo container registry, tagged with the Cargo.toml version and
|
||||||
# `latest`. Needs FORGEJO_TOKEN (a token with write:package scope)
|
# `latest`. Same tag guard as release-static. Needs FORGEJO_TOKEN (a token with write:package scope)
|
||||||
# in the environment; run from a checkout so `git rev-parse` and
|
# in the environment; run from a checkout so `git rev-parse` and
|
||||||
# the Containerfile build context resolve to the right place.
|
# the Containerfile build context resolve to the right place.
|
||||||
apps.release-container = flake-utils.lib.mkApp {
|
apps.release-container = flake-utils.lib.mkApp {
|
||||||
|
|
@ -175,12 +183,16 @@
|
||||||
fi
|
fi
|
||||||
: "''${FORGEJO_TOKEN:?set FORGEJO_TOKEN (env or .env) to a Forgejo token with write:package scope}"
|
: "''${FORGEJO_TOKEN:?set FORGEJO_TOKEN (env or .env) to a Forgejo token with write:package scope}"
|
||||||
|
|
||||||
rev=$(git rev-parse --short HEAD)
|
tag="v${version}"
|
||||||
|
if [ "$(git rev-parse -q --verify "$tag^{commit}" || true)" != "$(git rev-parse HEAD)" ]; then
|
||||||
|
echo "HEAD is not tagged $tag; bump Cargo.toml and CHANGELOG.md, then tag the release commit" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
registry="code.randogoth.com/randogoth/bunshin"
|
registry="code.randogoth.com/randogoth/bunshin"
|
||||||
|
|
||||||
echo "''${FORGEJO_TOKEN}" | podman login code.randogoth.com -u randogoth --password-stdin
|
echo "''${FORGEJO_TOKEN}" | podman login code.randogoth.com -u randogoth --password-stdin
|
||||||
podman build -f Containerfile -t "$registry:$rev" -t "$registry:latest" .
|
podman build -f Containerfile -t "$registry:${version}" -t "$registry:latest" .
|
||||||
podman push "$registry:$rev"
|
podman push "$registry:${version}"
|
||||||
podman push "$registry:latest"
|
podman push "$registry:latest"
|
||||||
|
|
||||||
echo "pushed: https://code.randogoth.com/randogoth/-/packages/container/bunshin"
|
echo "pushed: https://code.randogoth.com/randogoth/-/packages/container/bunshin"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use clap::{Parser, Subcommand};
|
||||||
use crate::proto::DEFAULT_PORT;
|
use crate::proto::DEFAULT_PORT;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(about = "Smol Mail server")]
|
#[command(version, about = "Smol Mail server")]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[arg(short, long, global = true)]
|
#[arg(short, long, global = true)]
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue