2 Commits
12 changed files with 374 additions and 41 deletions
+5
View File
@@ -0,0 +1,5 @@
signer/target
signer/dist
signer/.git
nostr_core_lib_rust/target
nostr_core_lib_rust/.git
+1
View File
@@ -1,3 +1,4 @@
/target/
/dist/
*.log
*.tar.gz
Generated
+3 -3
View File
@@ -1446,7 +1446,7 @@ dependencies = [
[[package]]
name = "nostr-core"
version = "0.0.3"
version = "0.1.0"
dependencies = [
"aes",
"base64",
@@ -1468,7 +1468,7 @@ dependencies = [
[[package]]
name = "nostr-nips"
version = "0.0.3"
version = "0.1.0"
dependencies = [
"aes",
"block-modes",
@@ -2207,7 +2207,7 @@ dependencies = [
[[package]]
name = "signer"
version = "0.0.21"
version = "0.0.22"
dependencies = [
"base64",
"chacha20poly1305",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "signer"
version = "0.0.21"
version = "0.0.23"
edition = "2021"
license = "MIT"
description = "Attended Nostr signing daemon — Rust port of n_signer"
+28
View File
@@ -0,0 +1,28 @@
FROM rust:1.88.0-alpine3.20
RUN apk add --no-cache \
build-base \
binutils \
file \
musl-dev \
openssl-dev \
openssl-libs-static \
perl \
pkgconf \
linux-headers \
&& rustup target add x86_64-unknown-linux-musl
ENV CARGO_NET_OFFLINE=false \
RUSTFLAGS=-Ctarget-cpu=x86-64
WORKDIR /workspace/signer
COPY nostr_core_lib_rust /workspace/nostr_core_lib_rust
COPY signer /workspace/signer
RUN cargo build --release --target x86_64-unknown-linux-musl
RUN file target/x86_64-unknown-linux-musl/release/signer \
&& file target/x86_64-unknown-linux-musl/release/signer-client \
&& ! readelf -l target/x86_64-unknown-linux-musl/release/signer | grep -q 'INTERP'
CMD ["sh", "-c", "mkdir -p /out && cp target/x86_64-unknown-linux-musl/release/signer /out/signer && cp target/x86_64-unknown-linux-musl/release/signer-client /out/signer_client"]
+37 -2
View File
@@ -728,12 +728,43 @@ git submodule update --init ratatui
### 8.2 Local dev build
Native builds are intended for local development and use the host Rust toolchain and libc:
```bash
cargo build
./target/debug/signer --version
```
### 8.3 Release build
### 8.3 Portable static musl release build
Portable release binaries are built in Docker for x86_64 Linux using the `x86_64-unknown-linux-musl` target. This avoids a runtime dependency on the target system's glibc version. The build expects the sibling `nostr_core_lib_rust` checkout described above.
```bash
./build_musl.sh
```
The artifacts are written directly to `dist/`:
- `signer`
- `signer_client`
Verify the output:
```bash
file dist/signer
ldd dist/signer
./dist/signer --version
```
`ldd` should report that the executable is not dynamically linked. Static musl removes the glibc runtime dependency, but the binaries still require a compatible Linux kernel, x86_64 CPU, terminal environment, Qubes/qrexec environment where applicable, and sufficient `RLIMIT_MEMLOCK` for locked secret memory.
To deploy the portable binaries locally:
```bash
./deploy_local.sh --musl
```
### 8.4 Native release build
The release profile is tuned for a small, optimized, stripped binary:
@@ -751,12 +782,14 @@ cargo build --release
./target/release/signer --version
```
### 8.4 Tests
### 8.5 Tests
```bash
cargo test
```
The portable build runs the release compilation and static-linkage checks inside Docker. Runtime smoke tests should be performed on the intended Qubes/Linux deployment environment, including Unix sockets, TCP/HTTP, qrexec, TUI startup, signing, and `mlock` behavior.
## 9. Project layout
| Path | Purpose |
@@ -769,6 +802,8 @@ cargo test
| [`src/role_table.rs`](src/role_table.rs:1) | Role registry, path-template parsing, purpose/curve enforcement |
| [`src/selector.rs`](src/selector.rs:1) | Role selector resolution (`role` + `role_path`) |
| [`src/enforcement.rs`](src/enforcement.rs:1) | Verb/algorithm/purpose/curve enforcement matrix |
| [`Dockerfile.musl`](Dockerfile.musl:1) | Reproducible Docker environment for static musl releases |
| [`build_musl.sh`](build_musl.sh:1) | Builds and validates portable x86_64 musl binaries |
| [`src/key_store.rs`](src/key_store.rs:1) | BIP-32 / SLIP-0010 key derivation and storage |
| [`src/mnemonic.rs`](src/mnemonic.rs:1) | BIP-39 mnemonic loading and seed derivation |
| [`src/pq_crypto.rs`](src/pq_crypto.rs:1) | Post-quantum keygen (ML-DSA-65, SLH-DSA-128s, ML-KEM-768) |
Executable
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
set -euo pipefail
# Build portable static x86_64 Linux binaries in a pinned musl container.
# The Docker build context is the parent directory because Cargo.toml uses
# ../nostr_core_lib_rust as a path dependency. Set SIGNER_NOSTR_CORE_DIR
# when the sibling checkout is stored elsewhere.
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_NAME="$(basename "${PROJECT_DIR}")"
PARENT_DIR="$(dirname "${PROJECT_DIR}")"
IMAGE_NAME="${SIGNER_MUSL_IMAGE:-signer-musl-build:rust-1.88.0-alpine3.20}"
OUTPUT_DIR="${SIGNER_MUSL_OUTPUT_DIR:-${PROJECT_DIR}/dist}"
DEPENDENCY_DIR="${SIGNER_NOSTR_CORE_DIR:-${PARENT_DIR}/nostr_core_lib_rust}"
if ! command -v docker >/dev/null 2>&1; then
echo "error: Docker is required for the musl build" >&2
exit 1
fi
if [[ ! -f "${PROJECT_DIR}/Cargo.toml" ]]; then
echo "error: Cargo.toml not found in ${PROJECT_DIR}" >&2
exit 1
fi
if [[ ! -f "${DEPENDENCY_DIR}/core/Cargo.toml" || ! -f "${DEPENDENCY_DIR}/nips/Cargo.toml" ]]; then
echo "error: invalid nostr_core_lib_rust checkout: ${DEPENDENCY_DIR}" >&2
echo "expected core/Cargo.toml and nips/Cargo.toml" >&2
echo "hint: clone the complete sibling checkout or set SIGNER_NOSTR_CORE_DIR" >&2
exit 1
fi
mkdir -p "${OUTPUT_DIR}"
rm -f "${OUTPUT_DIR}/signer" \
"${OUTPUT_DIR}/signer_client"
CONTAINER_NAME="signer-musl-build-$$-${RANDOM}"
cleanup() {
docker rm -f "${CONTAINER_NAME}" >/dev/null 2>&1 || true
}
trap cleanup EXIT
printf '[INFO] Building musl image %s\n' "${IMAGE_NAME}"
if [[ "${DEPENDENCY_DIR}" != "${PARENT_DIR}/nostr_core_lib_rust" ]]; then
echo "error: SIGNER_NOSTR_CORE_DIR must point to the sibling ../nostr_core_lib_rust directory when using Docker" >&2
exit 1
fi
docker build \
--file "${PROJECT_DIR}/Dockerfile.musl" \
--tag "${IMAGE_NAME}" \
"${PARENT_DIR}"
printf '[INFO] Extracting portable binaries\n'
docker create --name "${CONTAINER_NAME}" "${IMAGE_NAME}" >/dev/null
docker cp "${CONTAINER_NAME}:/workspace/signer/target/x86_64-unknown-linux-musl/release/signer" \
"${OUTPUT_DIR}/signer"
docker cp "${CONTAINER_NAME}:/workspace/signer/target/x86_64-unknown-linux-musl/release/signer-client" \
"${OUTPUT_DIR}/signer_client"
chmod 0755 "${OUTPUT_DIR}/signer" \
"${OUTPUT_DIR}/signer_client"
for binary in \
"${OUTPUT_DIR}/signer" \
"${OUTPUT_DIR}/signer_client"; do
file "${binary}"
if ! file "${binary}" | grep -Eq 'ELF 64-bit LSB (pie )?executable, x86-64'; then
echo "error: ${binary} is not an x86_64 ELF executable" >&2
exit 1
fi
if ldd "${binary}" 2>&1 | grep -Eqi 'not a dynamic executable|statically linked'; then
:
else
echo "error: ${binary} appears to be dynamically linked" >&2
ldd "${binary}" 2>&1 || true
exit 1
fi
"${binary}" --version
done
printf '[SUCCESS] Portable binaries written to %s\n' "${OUTPUT_DIR}"
+36 -17
View File
@@ -3,11 +3,12 @@ set -e
# signer (Rust) — Local Deploy Script
#
# Builds release binaries and installs them to /usr/local/bin/.
# Builds binaries and installs them to /usr/local/bin/.
#
# USAGE:
# ./deploy_local.sh # build release + install
# ./deploy_local.sh --debug # build debug + install
# ./deploy_local.sh # native release build + install
# ./deploy_local.sh --musl # portable static musl release + install
# ./deploy_local.sh --debug # native debug build + install
# ./deploy_local.sh -h, --help
#
# Installs:
@@ -29,6 +30,7 @@ print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
PROFILE="release"
CARGO_FLAG="--release"
TARGET_DIR="target/release"
BUILD_KIND="native"
show_usage() {
echo "signer (Rust) Local Deploy Script"
@@ -37,7 +39,8 @@ show_usage() {
echo " $0 [OPTIONS]"
echo ""
echo "OPTIONS:"
echo " --debug Build debug profile instead of release"
echo " --musl Build static x86_64 musl binaries in Docker"
echo " --debug Build native debug profile instead of release"
echo " -h, --help Show this help message"
echo ""
echo "Installs to /usr/local/bin/:"
@@ -47,7 +50,18 @@ show_usage() {
while [[ $# -gt 0 ]]; do
case $1 in
--musl)
BUILD_KIND="musl"
PROFILE="release"
CARGO_FLAG=""
TARGET_DIR="dist"
shift
;;
--debug)
if [[ "$BUILD_KIND" == "musl" ]]; then
print_error "--musl currently supports release builds only"
exit 1
fi
PROFILE="debug"
CARGO_FLAG=""
TARGET_DIR="target/debug"
@@ -78,14 +92,20 @@ if ! grep -q 'name = "signer"' Cargo.toml || ! grep -q 'name = "signer-client"'
fi
# Build
print_status "Building ${PROFILE} binaries (cargo build ${CARGO_FLAG})..."
cargo build ${CARGO_FLAG} 2>&1 | tail -5 || {
print_error "Build failed"
exit 1
}
SIGNER_BIN="${TARGET_DIR}/signer"
CLIENT_BIN="${TARGET_DIR}/signer-client"
if [[ "$BUILD_KIND" == "musl" ]]; then
print_status "Building static musl release binaries in Docker..."
./build_musl.sh
SIGNER_BIN="${TARGET_DIR}/signer-linux-x86_64-musl"
CLIENT_BIN="${TARGET_DIR}/signer-client-linux-x86_64-musl"
else
print_status "Building ${PROFILE} binaries (cargo build ${CARGO_FLAG})..."
cargo build ${CARGO_FLAG} 2>&1 | tail -5 || {
print_error "Build failed"
exit 1
}
SIGNER_BIN="${TARGET_DIR}/signer"
CLIENT_BIN="${TARGET_DIR}/signer-client"
fi
for bin in "$SIGNER_BIN" "$CLIENT_BIN"; do
if [[ ! -f "$bin" ]]; then
@@ -106,19 +126,18 @@ fi
install_binary() {
local src="$1"
local name
name=$(basename "$src")
local name="$2"
print_status "Installing $name to $DEST_DIR/..."
sudo install -m 0755 "$src" "$DEST_DIR/$name"
print_success "Installed: $DEST_DIR/$name"
}
install_binary "$SIGNER_BIN"
install_binary "$CLIENT_BIN"
install_binary "$SIGNER_BIN" "signer"
install_binary "$CLIENT_BIN" "signer-client"
# Verify
print_status "Verification:"
"$DEST_DIR/signer" --version || true
"$DEST_DIR/signer-client" --version || true
print_success "Local deploy completed (${PROFILE} profile)"
print_success "Local deploy completed (${PROFILE} ${BUILD_KIND} profile)"
+11 -10
View File
@@ -169,18 +169,19 @@ verify_binary_version() {
}
build_release_binary() {
print_status "Building release binaries (cargo build --release)..."
cargo build --release 2>&1 | tail -5 || return 1
print_status "Building static musl release binaries..."
./build_musl.sh || return 1
local bin_path="target/release/signer"
local bin_path="dist/signer"
verify_binary_version "$bin_path" "$NEW_VERSION" || return 1
local client_path="target/release/signer-client"
local client_path="dist/signer_client"
if [[ -f "$client_path" ]]; then
print_success "Release binary built: $client_path"
verify_binary_version "$client_path" "$NEW_VERSION" || return 1
print_success "Portable client binary built: $client_path"
fi
print_success "Release binary built: $bin_path"
print_success "Portable signer binary built: $bin_path"
return 0
}
@@ -284,8 +285,8 @@ main() {
git_commit_and_push
local binary_path="target/release/signer"
local client_path="target/release/signer-client"
local binary_path="dist/signer"
local client_path="dist/signer_client"
local tarball_path=""
tarball_path=$(create_source_tarball || true)
@@ -303,8 +304,8 @@ main() {
print_status "Uploading signer-client..."
curl -s -X POST "$assets_url" \
-H "Authorization: token $token" \
-F "attachment=@$client_path;filename=signer-client" \
-F "name=signer-client" > /dev/null
-F "attachment=@$client_path;filename=signer_client" \
-F "name=signer_client" > /dev/null
fi
fi
+19 -7
View File
@@ -15,11 +15,15 @@ set -euo pipefail
#
# Optional env vars:
# SIGNER_VERSION=vX.Y.Z # optional override; default is latest release tag
# SIGNER_GITEA_TOKEN=<token> # if signer release assets are private
# SIGNER_GITEA_TOKEN=<token> # if signer release assets are private
# SIGNER_BINARY_URL=<direct url to signer binary>
# SIGNER_CLIENT_BINARY_URL=<direct url to signer-client binary>
# SIGNER_BINARY_ASSET=<asset name> # optional release asset override
# SIGNER_CLIENT_BINARY_ASSET=<asset name> # optional release asset override
SIGNER_VERSION="${SIGNER_VERSION:-}"
SIGNER_BINARY_ASSET="${SIGNER_BINARY_ASSET:-signer}"
SIGNER_CLIENT_BINARY_ASSET="${SIGNER_CLIENT_BINARY_ASSET:-signer_client}"
PREFIX_BIN="${HOME}/.local/bin"
@@ -41,9 +45,11 @@ Options:
Optional env vars:
SIGNER_VERSION=vX.Y.Z # optional override; default is latest release tag
SIGNER_GITEA_TOKEN=<token> # required if signer release assets are private
SIGNER_GITEA_TOKEN=<token> # required if signer release assets are private
SIGNER_BINARY_URL=<direct url to signer binary>
SIGNER_CLIENT_BINARY_URL=<direct url to signer-client binary>
SIGNER_BINARY_ASSET=<asset name> # defaults to signer-linux-x86_64-musl
SIGNER_CLIENT_BINARY_ASSET=<asset name> # defaults to signer-client-linux-x86_64-musl
Install paths:
~/.local/bin/signer
@@ -102,7 +108,7 @@ resolve_signer_version() {
}
# Resolve a release asset URL by asset name suffix.
# $1 = asset name to match exactly (e.g. "signer" or "signer-client")
# $1 = asset name to match exactly (e.g. "signer-linux-x86_64-musl")
download_signer_asset_url() {
local asset_name="$1"
local headers=()
@@ -162,6 +168,12 @@ download_binary() {
asset_url="$(download_signer_asset_url "${asset_name}")"
fi
# Older releases used unqualified asset names. Keep that fallback while
# preferring explicit portable musl assets for new releases.
if [[ -z "${asset_url}" && "${asset_name}" == *-linux-x86_64-musl ]]; then
asset_url="$(download_signer_asset_url "${asset_name%-linux-x86_64-musl}")"
fi
if [[ -z "${asset_url}" ]]; then
err "Could not find downloadable ${asset_name} release binary for ${SIGNER_VERSION}."
err "Provide ${override_env} or SIGNER_GITEA_TOKEN so the release asset can be resolved."
@@ -186,16 +198,16 @@ install_signer() {
log "Installing signer ${SIGNER_VERSION}"
log "Release page: ${release_page}"
# Install the signer daemon binary
download_binary "signer" "SIGNER_BINARY_URL" "${PREFIX_BIN}/signer"
# Prefer the statically linked musl artifact; fall back to legacy names.
download_binary "${SIGNER_BINARY_ASSET}" "SIGNER_BINARY_URL" "${PREFIX_BIN}/signer"
verify_installed_version "${SIGNER_VERSION}" "${PREFIX_BIN}/signer"
log "Installed ${PREFIX_BIN}/signer from release binary"
# Install the signer-client CLI binary (best-effort: older releases may not have it)
if [[ -z "${SIGNER_CLIENT_BINARY_URL:-}" ]] && ! download_signer_asset_url "signer-client" >/dev/null 2>&1; then
if [[ -z "${SIGNER_CLIENT_BINARY_URL:-}" ]] && ! download_signer_asset_url "${SIGNER_CLIENT_BINARY_ASSET}" >/dev/null 2>&1 && ! download_signer_asset_url "signer-client" >/dev/null 2>&1; then
warn "No signer-client asset found for ${SIGNER_VERSION}; skipping client install."
else
download_binary "signer-client" "SIGNER_CLIENT_BINARY_URL" "${PREFIX_BIN}/signer-client"
download_binary "${SIGNER_CLIENT_BINARY_ASSET}" "SIGNER_CLIENT_BINARY_URL" "${PREFIX_BIN}/signer-client"
log "Installed ${PREFIX_BIN}/signer-client from release binary"
fi
}
+152
View File
@@ -0,0 +1,152 @@
# Static musl portability plan
## Objective
Produce portable x86_64 Linux release binaries that do not depend on the target machine's glibc version. The primary release artifacts will be statically linked against musl and will remain compatible with the project's Linux, Qubes, Unix-socket, qrexec, TCP/HTTP, terminal, and secure-memory requirements.
## Current findings
- The development host is x86_64 Ubuntu 22.04 with glibc 2.35.
- Rust 1.80.1 and Cargo 1.80.1 are installed, but `rustup` is unavailable.
- Docker is available, so the build can be isolated from the host toolchain and libc.
- The project directly uses conventional Linux APIs through `libc`: `mlock`, `munlock`, `AF_UNIX`, `SO_PEERCRED`, `getuid`, `close`, `listen`, and `localtime_r`.
- Cryptography is implemented through Rust crates; no mandatory OpenSSL dependency was found in this repository.
- The sibling `nostr_core_lib_rust` checkout is a path dependency declared by `Cargo.toml` and must be present in the container build context.
- The vendored `ratatui` submodule and its crossterm backend must compile for the musl target.
- Existing release scripts build directly with the host Cargo installation and therefore do not guarantee libc portability.
## Compatibility policy
- Primary portable target: `x86_64-unknown-linux-musl`.
- Release artifacts are intended for x86_64 Linux systems regardless of the installed glibc version, subject to Linux kernel, CPU, terminal, qrexec, and resource-limit requirements.
- Do not use `-C target-cpu=native`; build for a conservative x86_64 baseline.
- Keep the normal host-native build for development and debugging.
- Treat `RLIMIT_MEMLOCK` separately from libc portability; static linking does not remove the need for appropriate memory-lock limits.
## Implementation phases
### 1. Add a reproducible musl build image
Create a pinned Docker build definition, preferably using a stable musl-based Rust image or a pinned Alpine image with an explicitly installed Rust toolchain.
The image must provide:
- Rust and Cargo versions compatible with the project's `Cargo.toml` and lockfile.
- The `x86_64-unknown-linux-musl` target.
- A C compiler/linker suitable for musl.
- Required build utilities and certificate configuration.
- No dependency on the host's Rust installation or glibc-linked build output.
Ensure the container can access both the project and the sibling `nostr_core_lib_rust` path dependency. The build must initialize or use the existing `ratatui` submodule consistently with normal project setup.
### 2. Add a portable build entry point
Create `build_musl.sh` with explicit behavior:
1. Validate that Docker is available.
2. Validate that the project root and required sibling path dependency exist.
3. Build both `signer` and `signer-client` for `x86_64-unknown-linux-musl` in release mode.
4. Use a dedicated output directory such as `dist/musl-x86_64`.
5. Copy the binaries using explicit names:
- `signer-linux-x86_64-musl`
- `signer-client-linux-x86_64-musl`
6. Avoid copying host-native binaries into the portable output.
7. Run binary validation and version checks before reporting success.
8. Return a nonzero status for missing dependencies, failed builds, invalid ELF output, dynamic linkage, or version mismatch.
Keep the script usable from the repository root and make its Docker invocation safe for ordinary user development.
### 3. Validate static linkage and runtime behavior
Add validation to the build flow using tools available in the container:
- `file` must identify x86_64 ELF executables.
- `readelf` must show the expected musl/static characteristics and no glibc loader requirement.
- `ldd` must not identify unresolved dynamic runtime dependencies.
- `signer --version` and `signer-client --version` must report the Cargo package version.
- Run `cargo test --target x86_64-unknown-linux-musl` where the test environment supports it.
Perform smoke checks for:
- stdio framing;
- Unix abstract socket bind/connect and peer identity;
- TCP and HTTP startup;
- qrexec subprocess integration where the host provides qrexec;
- mnemonic input and key derivation;
- representative signing and verification operations;
- TUI initialization in a terminal;
- `mlock` success or the documented unlocked-memory fallback behavior.
If a dependency cannot support musl, record the failure and determine whether it is optional, can be feature-gated, or requires retaining a glibc artifact.
### 4. Integrate release automation
Update `increment_and_push.sh` so release mode invokes the portable musl builder rather than the host-native `cargo build --release` path.
Preserve:
- version incrementing;
- source version updates;
- binary version verification;
- tagging and pushing;
- Gitea release creation;
- source tarball generation.
Extend asset upload handling to upload both musl binaries with their platform-specific names. Do not silently publish a host-linked binary under an ambiguous name.
Decide whether the existing unqualified assets remain as compatibility aliases. The safer default is to publish explicit musl names and retain legacy fallback handling only for older releases.
### 5. Update local deployment
Extend `deploy_local.sh` with an explicit portable option, such as `--musl`.
Suggested behavior:
- default development/debug builds remain native;
- `--musl` invokes the Docker build and installs the resulting portable binaries;
- release deployment should clearly report whether the installed binary is native or musl;
- installation continues to use `/usr/local/bin/` only when the user has the required privileges.
Add checks so the script does not mistake a musl artifact for a native build or install an absent/stale binary.
### 6. Update the installer
Update `install_signer.sh` to prefer the explicit musl release assets:
- `signer-linux-x86_64-musl`
- `signer-client-linux-x86_64-musl`
Retain support for existing older releases whose assets are named simply `signer` or `signer-client`. Add an override for users who need a different asset URL or a native glibc build.
Continue verifying the installed program version, and add target/artifact validation where practical so a mislabeled asset is rejected.
### 7. Update documentation
Update the build and platform sections of `README.md` to explain:
- native builds are for local development;
- portable release builds use static musl;
- the portable target is x86_64 Linux;
- the artifact names and output directory;
- how to verify static linkage with `file`, `readelf`, and `ldd`;
- static musl removes the glibc runtime dependency but not Linux kernel, CPU, terminal, qrexec, or `RLIMIT_MEMLOCK` requirements;
- Qubes users should use the musl release artifact unless a native glibc build is specifically required.
Update the project layout section with the new build definition and script.
## Acceptance criteria
- A clean Docker invocation builds both release binaries without using the host Rust compiler or host glibc.
- The resulting binaries are x86_64 and statically linked against musl.
- Neither binary requires the glibc dynamic loader or a minimum GLIBC symbol version.
- Both binaries pass version checks and the relevant test suite.
- Representative Unix, stdio, TCP/HTTP, crypto, TUI, and secure-memory paths are validated.
- Release automation uploads unambiguous musl artifacts.
- The installer can select the musl artifacts and remains compatible with older release naming.
- Documentation explains how to build, verify, install, and deploy the portable binaries.
## Deferred options
- Publishing a glibc-2.17-compatible artifact can be added later if a target integration requires glibc behavior.
- Additional architectures can be added later, but must have separate build images, artifact names, and validation.
- Musl should not be made the only local development target until the smoke tests demonstrate that all supported transports and terminal behavior are equivalent for the project's deployment environments.
+1 -1
View File
@@ -31,4 +31,4 @@ pub mod error;
pub use error::SignerError;
/// Version string (matches C NSIGNER_VERSION).
pub const VERSION: &str = "v0.0.21";
pub const VERSION: &str = "v0.0.23";