From 3d11367b7e9f0d47ffb3dfdec805da68248e6490 Mon Sep 17 00:00:00 2001 From: al amoda Date: Thu, 12 Feb 2026 00:30:05 -0500 Subject: [PATCH 1/7] squash stagex reproducible build --- .gitignore | 3 + Dockerfile | 134 ++++++++++++++++++++++++++++++++++++++++++++ Makefile | 24 ++++++++ README.md | 14 ++++- utils/build.sh | 32 +++++++++++ utils/compat.sh | 84 +++++++++++++++++++++++++++ utils/entrypoint.sh | 31 ++++++++++ utils/load_image.sh | 20 +++++++ 8 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 Dockerfile create mode 100644 Makefile create mode 100755 utils/build.sh create mode 100755 utils/compat.sh create mode 100755 utils/entrypoint.sh create mode 100755 utils/load_image.sh diff --git a/.gitignore b/.gitignore index 8c6b6ef..1fe81be 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ # Guard against accidental commits of the `local` and `tmp` paths /local /tmp + +#StageX build directory +/build diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9644037 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,134 @@ +# syntax=docker/dockerfile:1 + +# stages: +# - setup: sets default values +# - release: builds release binary +# - export: minimal binary export +# - runtime: prepares the release image +# +# We first set default values for build arguments used across the stages. +# Each stage must define the build arguments (ARGs) it uses. + +ARG RUST_VERSION=1.91.1 + +ARG FEATURES="" + +ARG UID=10801 +ARG GID=${UID} +ARG USER="user" +ARG HOME="/home/${USER}" +ARG CARGO_HOME="${HOME}/.cargo" +ARG CARGO_TARGET_DIR="${HOME}/target" +ARG TARGET_ARCH="x86_64-unknown-linux-musl" + +FROM stagex/core-busybox:sx2026.03.0@sha256:d608daa946e4799cf28b105aba461db00187657bd55ea7c2935ff11dac237e27 AS busybox +FROM stagex/pallet-rust:1.94.0@sha256:2fbe7b164dd92edb9c1096152f6d27592d8a69b1b8eb2fc907b5fadea7d11668 AS pallet-rust + +# This stage captures build args as env vars +FROM pallet-rust AS setup + +SHELL ["/bin/sh", "-xo", "pipefail", "-c"] + +# Build arguments and variables +ARG CARGO_INCREMENTAL +# default to 0, disables incremental compilation. +ENV CARGO_INCREMENTAL=${CARGO_INCREMENTAL:-0} + +ARG CARGO_HOME +ENV CARGO_HOME=${CARGO_HOME} + +# This stage builds the zcash-devtool release binary. +FROM setup AS release + +ARG HOME +WORKDIR ${HOME} + +ARG CARGO_HOME +ARG CARGO_TARGET_DIR +ARG TARGET_ARCH + +ENV RUST_BACKTRACE=1 +ENV RUSTFLAGS="-C codegen-units=1" +ENV RUSTFLAGS="${RUSTFLAGS} -C target-feature=+crt-static" +ENV RUSTFLAGS="${RUSTFLAGS} -C link-arg=-Wl,--build-id=none" + +ENV SOURCE_DATE_EPOCH=1 +ENV CXXFLAGS="-include cstdint" + +COPY . . + +RUN --mount=type=bind,source=Cargo.toml,target=Cargo.toml,ro \ + --mount=type=bind,source=Cargo.lock,target=Cargo.lock,ro \ + --mount=type=cache,target=${HOME}/target/ \ + --mount=type=cache,target=/usr/local/cargo/registry/ \ + --mount=type=cache,target=${CARGO_TARGET_DIR} \ + --mount=type=cache,target=${CARGO_HOME} \ + cargo fetch --locked --target $TARGET_ARCH && \ + cargo metadata --locked --format-version=1 > /dev/null 2>&1 + +RUN --network=none \ + --mount=type=bind,source=Cargo.toml,target=Cargo.toml,ro \ + --mount=type=bind,source=Cargo.lock,target=Cargo.lock,ro \ + --mount=type=cache,target=${HOME}/target/ \ + --mount=type=cache,target=/usr/local/cargo/registry/ \ + --mount=type=cache,target=${CARGO_TARGET_DIR} \ + --mount=type=cache,target=${CARGO_HOME} \ + cargo build --frozen --release --all-features --target ${TARGET_ARCH} && \ + install -D -m 0755 ${HOME}/target/${TARGET_ARCH}/release/zcash-devtool /usr/local/bin/zcash-devtool + +# This stage is used to export the binary +FROM scratch AS export +COPY --from=release /usr/local/bin/* / + +# This stage starts from StageX/busybox and copies the built +# zcash-devtool binary from the `release` stage +FROM busybox AS runtime + +ARG FEATURES +ENV FEATURES=${FEATURES} + +# Create a non-privileged user for running `zcash-devtool`. +# +# We use a high UID/GID (10801) to avoid overlap with host system users. +# This reduces the risk of container user namespace conflicts with host accounts, +# which could potentially lead to privilege escalation if a container escape occurs. +# +# We do not use the `--system` flag for user creation since: +# 1. System user ranges (100-999) can collide with host system users +# (see: https://github.com/nginxinc/docker-nginx/issues/490) +# 2. There's no value added and warning messages can be raised at build time +# (see: https://github.com/dotnet/dotnet-docker/issues/4624) +# +# The high UID/GID values provide an additional security boundary in containers +# where user namespaces are shared with the host. +ARG UID +ENV UID=${UID} +ARG GID +ENV GID=${GID} +ARG USER +ENV USER=${USER} +ARG HOME +ENV HOME=${HOME} + +COPY --chmod=550 <<-EOF /etc/passwd + root:x:0:0:root:/root:/bin/sh + user:x:${UID}:${GID}::${HOME}:/bin/sh +EOF + +COPY --chmod=550 <<-EOF /etc/group + root:x:0: + user:x:${GID}: +EOF + +USER ${UID}:${GID} + +WORKDIR /usr/local/bin + +USER root +COPY --from=release /usr/local/bin/zcash-devtool /usr/local/bin/ +COPY ./utils/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN mkdir -p /usr/local/bin/zec_sqlite_wallet && chown -R ${UID}:${GID} /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool +USER $USER + +ENTRYPOINT [ "entrypoint.sh" ] +CMD [ "./zcash-devtool" ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..287decd --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +# Simple wrapper for scripts with printed status messages. +# +# Running `make` or `make stagex` will leverage the steps below +# to check compatibility and build the binary via StageX. + +.PHONY: stagex compat build load create + +stagex: compat build + @echo "stagex build completed via make." + +compat: + @echo "Beginning Compatibility Check step." + @./utils/compat.sh + @echo " [PASS] Compatibility Check passed." + +build: + @echo "Entering Build step." + @./utils/build.sh + @echo "Build step complete." + +load: + @echo "Attempting to load OCI image into local docker image store." + @./utils/load_image.sh + @echo "make load step complete." diff --git a/README.md b/README.md index 6a6bdab..d6adcfe 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,18 @@ scale experimentation, at your own risk. ## Usage -No binary artifacts are provided for this crate; it is generally used via -`cargo run` as follows: +No binary artifacts are directly provided for this crate. + +However, a bootstrapped and reproducible build pipeline using StageX is included. +To create a binary, you can simply run `make` in the root directory of the repo. +The resulting binary will be found in the `/build/` directory. + +Running `make load` will load the OCI compliant image (built as a tarball) into +Docker. Subsequently, a container can be run interactively. For example: +`docker run -it zcash-devtool:latest ./zcash-devtool wallet init --name "stagex_demo" --identity ./age_id.txt --connection direct --network test -s zecrocks` +will initialize a wallet and connect to zecrocks over clearnet (instead of tor). + +It can also be used via `cargo run` as follows: To obtain the help docs: ``` diff --git a/utils/build.sh b/utils/build.sh new file mode 100755 index 0000000..5452e23 --- /dev/null +++ b/utils/build.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + +DIR="$( cd "$( dirname "$0" )" && pwd )" +REPO_ROOT="$(git rev-parse --show-toplevel)" +PLATFORM="linux/amd64" +OCI_OUTPUT="$REPO_ROOT/build/oci" +DOCKERFILE="$REPO_ROOT/Dockerfile" +NAME=zcash-devtool + +export DOCKER_BUILDKIT=1 +export SOURCE_DATE_EPOCH=1 + +echo $DOCKERFILE +mkdir -p $OCI_OUTPUT + +# Build runtime image for docker run +echo "Building runtime image..." +docker build -f "$DOCKERFILE" "$REPO_ROOT" \ + --platform "$PLATFORM" \ + --target runtime \ + --output type=oci,rewrite-timestamp=true,force-compression=true,dest=$OCI_OUTPUT/zcash-devtool.tar,name=zcash-devtool \ + "$@" + +# Extract from export stage +echo "Extracting binaries..." +docker build -f "$DOCKERFILE" "$REPO_ROOT" --quiet \ + --platform "$PLATFORM" \ + --target export \ + --output type=local,dest="$REPO_ROOT/build" \ + "$@" diff --git a/utils/compat.sh b/utils/compat.sh new file mode 100755 index 0000000..f2ad69d --- /dev/null +++ b/utils/compat.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -e +readonly MIN_BASH_VERSION=5 +readonly MIN_DOCKER_VERSION=26.0.0 +readonly MIN_BUILDX_VERSION=0.13 +### Exit with error message +die() { + echo "$@" >&2 + exit 1 +} + +### Bail and instruct user on missing package to install for their platform +die_pkg() { + local -r package=${1?} + local -r version=${2?} + local install_cmd + case "$OSTYPE" in + linux*) + if command -v "apt" >/dev/null; then + install_cmd="apt install ${package}" + elif command -v "yum" >/dev/null; then + install_cmd="yum install ${package}" + elif command -v "pacman" >/dev/null; then + install_cmd="pacman -Ss ${package}" + elif command -v "emerge" >/dev/null; then + install_cmd="emerge ${package}" + elif command -v "nix-env" >/dev/null; then + install_cmd="nix-env -i ${package}" + fi + ;; + bsd*) install_cmd="pkg install ${package}" ;; + darwin*) install_cmd="port install ${package}" ;; + *) die "Error: Your operating system is not supported" ;; + esac + echo "Error: ${package} ${version}+ does not appear to be installed." >&2 + [ -n "$install_cmd" ] && echo "Try: \`${install_cmd}\`" >&2 + exit 1 +} + +### Check if actual binary version is >= minimum version +check_version(){ + local pkg="${1?}" + local have="${2?}" + local need="${3?}" + local i ver1 ver2 IFS='.' + [[ "$have" == "$need" ]] && return 0 + read -r -a ver1 <<< "$have" + read -r -a ver2 <<< "$need" + for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); + do ver1[i]=0; + done + for ((i=0; i<${#ver1[@]}; i++)); do + [[ -z ${ver2[i]} ]] && ver2[i]=0 + ((10#${ver1[i]} > 10#${ver2[i]})) && return 0 + ((10#${ver1[i]} < 10#${ver2[i]})) && die_pkg "${pkg}" "${need}" + done +} + +### Check if required binaries are installed at appropriate versions +check_tools(){ + if [ -z "${BASH_VERSINFO[0]}" ] \ + || [ "${BASH_VERSINFO[0]}" -lt "${MIN_BASH_VERSION}" ]; then + die_pkg "bash" "${MIN_BASH_VERSION}" + fi + for cmd in "$@"; do + case $cmd in + buildx) + docker buildx version >/dev/null 2>&1 || die "Error: buildx not found" + version=$(docker buildx version 2>/dev/null | grep -o 'v[0-9.]*' | sed 's/v//') + check_version "buildx" "${version}" "${MIN_BUILDX_VERSION}" + ;; + docker) + command -v docker >/dev/null || die "Error: docker not found" + version=$(docker version -f '{{ .Server.Version }}') + check_version "docker" "${version}" "${MIN_DOCKER_VERSION}" + ;; + esac + done +} + +check_tools docker buildx; +docker info -f '{{ .DriverStatus }}' \ + | grep "io.containerd.snapshotter.v1" >/dev/null \ +|| die "Error: Docker Engine is not using containerd for image storage" diff --git a/utils/entrypoint.sh b/utils/entrypoint.sh new file mode 100755 index 0000000..43533b3 --- /dev/null +++ b/utils/entrypoint.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# Entrypoint for running zcash-devtool in Docker. +# +# The main script logic is at the bottom. +# +# ## Notes +# +# zcash-devtool is a stateless tool. Each command has some effect: +# inspect +# Intended to be run against "anything zcash" and provide information. For example, +# an address, or a transaction. +# wallet +# Can create and inspect wallets, sync, send zec and so on. + +set -eo pipefail + +# Main Script Logic +# +# 1. Print environment variables and config for debugging. +# 2. Tests if zcash-devtool runs, printing help. +# 3. Execs the CMD or custom command provided. + +echo "INFO: Using the following environment variables:" +printenv + +echo "Testing zcash-devtool to print version string:" +./zcash-devtool help + +echo "now exec'ing $@ " +exec "$@" diff --git a/utils/load_image.sh b/utils/load_image.sh new file mode 100755 index 0000000..c14b5bc --- /dev/null +++ b/utils/load_image.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e + +REPO_ROOT="$(git rev-parse --show-toplevel)" +OCI_OUTPUT="$REPO_ROOT/build/oci" +TARBALL="${OCI_OUTPUT}/zcash-devtool.tar" + + +# Build runtime image for docker run +echo "Checking if the OCI output from build is present." +if [ -f "$TARBALL" ]; +then + echo "OCI output file present, loading tar file into local docker image store." + docker load < $TARBALL + echo "...Done!" +else + echo "OCI output file not present." +fi + From 867a0980d3d88c548e11f1e7cf7eb82b5d5d7911 Mon Sep 17 00:00:00 2001 From: Anton Livaja Date: Fri, 13 Mar 2026 16:39:01 -0700 Subject: [PATCH 2/7] minor cleanup --- Dockerfile | 51 +++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9644037..86b7aa0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,35 +1,33 @@ # syntax=docker/dockerfile:1 # stages: -# - setup: sets default values # - release: builds release binary # - export: minimal binary export # - runtime: prepares the release image # # We first set default values for build arguments used across the stages. # Each stage must define the build arguments (ARGs) it uses. - -ARG RUST_VERSION=1.91.1 - ARG FEATURES="" ARG UID=10801 ARG GID=${UID} ARG USER="user" ARG HOME="/home/${USER}" -ARG CARGO_HOME="${HOME}/.cargo" +ARG CARGO_HOME="/usr/local/cargo" ARG CARGO_TARGET_DIR="${HOME}/target" ARG TARGET_ARCH="x86_64-unknown-linux-musl" -FROM stagex/core-busybox:sx2026.03.0@sha256:d608daa946e4799cf28b105aba461db00187657bd55ea7c2935ff11dac237e27 AS busybox +FROM stagex/core-busybox:1.37.0@sha256:d608daa946e4799cf28b105aba461db00187657bd55ea7c2935ff11dac237e27 AS busybox FROM stagex/pallet-rust:1.94.0@sha256:2fbe7b164dd92edb9c1096152f6d27592d8a69b1b8eb2fc907b5fadea7d11668 AS pallet-rust -# This stage captures build args as env vars -FROM pallet-rust AS setup +# This stage builds the zcash-devtool release binary. +FROM pallet-rust AS release SHELL ["/bin/sh", "-xo", "pipefail", "-c"] -# Build arguments and variables +ARG HOME +WORKDIR ${HOME} + ARG CARGO_INCREMENTAL # default to 0, disables incremental compilation. ENV CARGO_INCREMENTAL=${CARGO_INCREMENTAL:-0} @@ -37,15 +35,9 @@ ENV CARGO_INCREMENTAL=${CARGO_INCREMENTAL:-0} ARG CARGO_HOME ENV CARGO_HOME=${CARGO_HOME} -# This stage builds the zcash-devtool release binary. -FROM setup AS release - -ARG HOME -WORKDIR ${HOME} - -ARG CARGO_HOME ARG CARGO_TARGET_DIR ARG TARGET_ARCH +ARG FEATURES ENV RUST_BACKTRACE=1 ENV RUSTFLAGS="-C codegen-units=1" @@ -55,25 +47,20 @@ ENV RUSTFLAGS="${RUSTFLAGS} -C link-arg=-Wl,--build-id=none" ENV SOURCE_DATE_EPOCH=1 ENV CXXFLAGS="-include cstdint" -COPY . . +COPY Cargo.toml Cargo.lock rust-toolchain.toml ./ +COPY src/ src/ -RUN --mount=type=bind,source=Cargo.toml,target=Cargo.toml,ro \ - --mount=type=bind,source=Cargo.lock,target=Cargo.lock,ro \ - --mount=type=cache,target=${HOME}/target/ \ - --mount=type=cache,target=/usr/local/cargo/registry/ \ - --mount=type=cache,target=${CARGO_TARGET_DIR} \ +RUN --mount=type=cache,target=/usr/local/cargo/registry/ \ + --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=${CARGO_HOME} \ - cargo fetch --locked --target $TARGET_ARCH && \ - cargo metadata --locked --format-version=1 > /dev/null 2>&1 + cargo fetch --locked --target $TARGET_ARCH RUN --network=none \ - --mount=type=bind,source=Cargo.toml,target=Cargo.toml,ro \ - --mount=type=bind,source=Cargo.lock,target=Cargo.lock,ro \ - --mount=type=cache,target=${HOME}/target/ \ --mount=type=cache,target=/usr/local/cargo/registry/ \ + --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=${CARGO_TARGET_DIR} \ --mount=type=cache,target=${CARGO_HOME} \ - cargo build --frozen --release --all-features --target ${TARGET_ARCH} && \ + cargo build --frozen --release ${FEATURES:+--features ${FEATURES}} --target ${TARGET_ARCH} && \ install -D -m 0755 ${HOME}/target/${TARGET_ARCH}/release/zcash-devtool /usr/local/bin/zcash-devtool # This stage is used to export the binary @@ -120,15 +107,11 @@ COPY --chmod=550 <<-EOF /etc/group user:x:${GID}: EOF -USER ${UID}:${GID} - -WORKDIR /usr/local/bin - -USER root COPY --from=release /usr/local/bin/zcash-devtool /usr/local/bin/ COPY ./utils/entrypoint.sh /usr/local/bin/entrypoint.sh RUN mkdir -p /usr/local/bin/zec_sqlite_wallet && chown -R ${UID}:${GID} /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool -USER $USER +WORKDIR /usr/local/bin +USER ${UID}:${GID} ENTRYPOINT [ "entrypoint.sh" ] CMD [ "./zcash-devtool" ] From 7f26d8af18aac7e78f7a7079e7a792aae93b3221 Mon Sep 17 00:00:00 2001 From: Anton Livaja Date: Fri, 13 Mar 2026 17:07:30 -0700 Subject: [PATCH 3/7] remove features flag and add fix user perms --- Dockerfile | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 86b7aa0..8e89436 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,8 +7,6 @@ # # We first set default values for build arguments used across the stages. # Each stage must define the build arguments (ARGs) it uses. -ARG FEATURES="" - ARG UID=10801 ARG GID=${UID} ARG USER="user" @@ -37,7 +35,6 @@ ENV CARGO_HOME=${CARGO_HOME} ARG CARGO_TARGET_DIR ARG TARGET_ARCH -ARG FEATURES ENV RUST_BACKTRACE=1 ENV RUSTFLAGS="-C codegen-units=1" @@ -60,7 +57,7 @@ RUN --network=none \ --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=${CARGO_TARGET_DIR} \ --mount=type=cache,target=${CARGO_HOME} \ - cargo build --frozen --release ${FEATURES:+--features ${FEATURES}} --target ${TARGET_ARCH} && \ + cargo build --frozen --release --all-features --target ${TARGET_ARCH} && \ install -D -m 0755 ${HOME}/target/${TARGET_ARCH}/release/zcash-devtool /usr/local/bin/zcash-devtool # This stage is used to export the binary @@ -71,9 +68,6 @@ COPY --from=release /usr/local/bin/* / # zcash-devtool binary from the `release` stage FROM busybox AS runtime -ARG FEATURES -ENV FEATURES=${FEATURES} - # Create a non-privileged user for running `zcash-devtool`. # # We use a high UID/GID (10801) to avoid overlap with host system users. @@ -107,6 +101,7 @@ COPY --chmod=550 <<-EOF /etc/group user:x:${GID}: EOF +USER root COPY --from=release /usr/local/bin/zcash-devtool /usr/local/bin/ COPY ./utils/entrypoint.sh /usr/local/bin/entrypoint.sh RUN mkdir -p /usr/local/bin/zec_sqlite_wallet && chown -R ${UID}:${GID} /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool From 6f37da20ab40d5232bd563c9273a46bb239c3d85 Mon Sep 17 00:00:00 2001 From: al amoda Date: Wed, 18 Mar 2026 15:44:33 -0400 Subject: [PATCH 4/7] rm sqlite dir creation in Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8e89436..5fbdca7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -104,7 +104,7 @@ EOF USER root COPY --from=release /usr/local/bin/zcash-devtool /usr/local/bin/ COPY ./utils/entrypoint.sh /usr/local/bin/entrypoint.sh -RUN mkdir -p /usr/local/bin/zec_sqlite_wallet && chown -R ${UID}:${GID} /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool +RUN chown -R ${UID}:${GID} /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool WORKDIR /usr/local/bin USER ${UID}:${GID} From e26e8790f3a2f9c59ea7a5a87acbf7136cb93889 Mon Sep 17 00:00:00 2001 From: al amoda Date: Thu, 16 Apr 2026 19:02:57 -0400 Subject: [PATCH 5/7] hardcode UID, GID, user, home in runtime --- Dockerfile | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5fbdca7..ee79e52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,8 +7,6 @@ # # We first set default values for build arguments used across the stages. # Each stage must define the build arguments (ARGs) it uses. -ARG UID=10801 -ARG GID=${UID} ARG USER="user" ARG HOME="/home/${USER}" ARG CARGO_HOME="/usr/local/cargo" @@ -50,7 +48,8 @@ COPY src/ src/ RUN --mount=type=cache,target=/usr/local/cargo/registry/ \ --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=${CARGO_HOME} \ - cargo fetch --locked --target $TARGET_ARCH + cargo fetch --locked --target ${TARGET_ARCH} && \ + cargo metadata --locked --format-version=1 > /dev/null 2>&1 RUN --network=none \ --mount=type=cache,target=/usr/local/cargo/registry/ \ @@ -82,31 +81,27 @@ FROM busybox AS runtime # # The high UID/GID values provide an additional security boundary in containers # where user namespaces are shared with the host. -ARG UID -ENV UID=${UID} -ARG GID -ENV GID=${GID} -ARG USER -ENV USER=${USER} -ARG HOME -ENV HOME=${HOME} +ENV UID=10801 +ENV GID=10801 +ENV USER=user +ENV HOME=/home/user COPY --chmod=550 <<-EOF /etc/passwd root:x:0:0:root:/root:/bin/sh - user:x:${UID}:${GID}::${HOME}:/bin/sh + user:x:10801:10801::/home/user:/bin/sh EOF COPY --chmod=550 <<-EOF /etc/group root:x:0: - user:x:${GID}: + user:x:10801: EOF USER root COPY --from=release /usr/local/bin/zcash-devtool /usr/local/bin/ COPY ./utils/entrypoint.sh /usr/local/bin/entrypoint.sh -RUN chown -R ${UID}:${GID} /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool +RUN chown -R 10801:10801 /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool WORKDIR /usr/local/bin -USER ${UID}:${GID} +USER 10801:10801 ENTRYPOINT [ "entrypoint.sh" ] CMD [ "./zcash-devtool" ] From ef03fb8f6373e32b4684667438278f898b30ad65 Mon Sep 17 00:00:00 2001 From: al amoda Date: Fri, 17 Apr 2026 15:23:31 -0400 Subject: [PATCH 6/7] patch rage, cargo check --- Cargo.lock | 172 ++++++++++++++++++++++++++++++++++++----------------- Cargo.toml | 5 +- 2 files changed, 123 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 831263b..84fe80f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,29 +30,48 @@ dependencies = [ "zeroize", ] +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "age" version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf640be7658959746f1f0f2faab798f6098a9436a8e18e148d18bc9875e13c4b" +source = "git+https://github.com/antonleviathan/rage.git?branch=deterministic-iteration#5b147242a6778ca8a0b6132f0baeea68a285640b" dependencies = [ "age-core", - "base64 0.21.7", - "bech32 0.9.1", + "base64", + "bech32", "chacha20poly1305", + "cipher", "cookie-factory", + "hkdf", "hmac 0.12.1", + "hpke", "i18n-embed", "i18n-embed-fl", "lazy_static", - "nom 7.1.3", + "ml-kem", + "nom 8.0.0", + "p256", "pin-project", "rand 0.8.5", "rust-embed", "scrypt", "sha2 0.10.9", + "sha3", "subtle", - "which 4.4.2", + "which 8.0.2", "wsl", "x25519-dalek", "zeroize", @@ -61,15 +80,16 @@ dependencies = [ [[package]] name = "age-core" version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2bf6a89c984ca9d850913ece2da39e1d200563b0a94b002b253beee4c5acf99" +source = "git+https://github.com/antonleviathan/rage.git?branch=deterministic-iteration#5b147242a6778ca8a0b6132f0baeea68a285640b" dependencies = [ - "base64 0.21.7", + "base64", + "bech32", "chacha20poly1305", "cookie-factory", "hkdf", + "hpke", "io_tee", - "nom 7.1.3", + "nom 8.0.0", "rand 0.8.5", "secrecy 0.10.3", "sha2 0.10.9", @@ -565,12 +585,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -592,12 +606,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "bech32" version = "0.11.1" @@ -1547,6 +1555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] @@ -2031,6 +2040,7 @@ dependencies = [ "ff", "generic-array", "group", + "hkdf", "pkcs8", "rand_core 0.6.4", "sec1", @@ -2286,9 +2296,9 @@ dependencies = [ [[package]] name = "fluent" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" +checksum = "8137a6d5a2c50d6b0ebfcb9aaa91a28154e0a70605f112d30cb0cd4a78670477" dependencies = [ "fluent-bundle", "unic-langid", @@ -2296,16 +2306,16 @@ dependencies = [ [[package]] name = "fluent-bundle" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4" dependencies = [ "fluent-langneg", "fluent-syntax", "intl-memoizer", "intl_pluralrules", - "rustc-hash 1.1.0", - "self_cell 0.10.3", + "rustc-hash 2.1.2", + "self_cell", "smallvec", "unic-langid", ] @@ -2321,11 +2331,12 @@ dependencies = [ [[package]] name = "fluent-syntax" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198" dependencies = [ - "thiserror 1.0.69", + "memchr", + "thiserror 2.0.18", ] [[package]] @@ -2614,6 +2625,16 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gif" version = "0.14.1" @@ -2833,6 +2854,26 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" +[[package]] +name = "hpke" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4917627a14198c3603282c5158b815ad5534795451d3c074b53cf3cee0960b11" +dependencies = [ + "aead", + "aes-gcm", + "chacha20poly1305", + "digest 0.10.7", + "generic-array", + "hkdf", + "hmac 0.12.1", + "p256", + "rand_core 0.6.4", + "sha2 0.10.9", + "subtle", + "zeroize", +] + [[package]] name = "http" version = "1.4.0" @@ -2975,9 +3016,9 @@ dependencies = [ [[package]] name = "i18n-embed" -version = "0.15.4" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "669ffc2c93f97e6ddf06ddbe999fcd6782e3342978bb85f7d3c087c7978404c4" +checksum = "a217bbb075dcaefb292efa78897fc0678245ca67f265d12c351e42268fcb0305" dependencies = [ "arc-swap", "fluent", @@ -2995,9 +3036,9 @@ dependencies = [ [[package]] name = "i18n-embed-fl" -version = "0.9.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b2969d0b3fc6143776c535184c19722032b43e6a642d710fa3f88faec53c2d" +checksum = "e598ed73b67db92f61e04672e599eef2991a262a40e1666735b8a86d2e7e9f30" dependencies = [ "find-crate", "fluent", @@ -3345,6 +3386,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "kem" +version = "0.3.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8645470337db67b01a7f966decf7d0bafedbae74147d33e641c67a91df239f" +dependencies = [ + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "known-folders" version = "1.4.2" @@ -3663,6 +3714,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "ml-kem" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de49b3df74c35498c0232031bb7e85f9389f913e2796169c8ab47a53993a18f" +dependencies = [ + "hybrid-array", + "kem", + "rand_core 0.6.4", + "sha3", +] + [[package]] name = "moxcms" version = "0.7.11" @@ -4520,6 +4583,18 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if 1.0.4", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "postage" version = "0.5.0" @@ -5655,15 +5730,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "self_cell" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" -dependencies = [ - "self_cell 1.2.2", -] - [[package]] name = "self_cell" version = "1.2.2" @@ -5763,7 +5829,7 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" dependencies = [ - "base64 0.22.1", + "base64", "chrono", "hex", "indexmap 1.9.3", @@ -6521,7 +6587,7 @@ checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" dependencies = [ "async-trait", "axum", - "base64 0.22.1", + "base64", "bytes", "flate2", "h2", @@ -8670,7 +8736,7 @@ version = "0.1.0" dependencies = [ "age", "anyhow", - "bech32 0.11.1", + "bech32", "bellman", "bip0039", "bip32", @@ -8747,7 +8813,7 @@ name = "zcash_address" version = "0.10.1" source = "git+https://github.com/zcash/librustzcash.git?rev=69f1b3599cb79d08fa73018914bebd1c51db3ef8#69f1b3599cb79d08fa73018914bebd1c51db3ef8" dependencies = [ - "bech32 0.11.1", + "bech32", "bs58", "core2 0.3.3", "f4jumble", @@ -8763,8 +8829,8 @@ dependencies = [ "ambassador", "arti-client", "assert_matches", - "base64 0.22.1", - "bech32 0.11.1", + "base64", + "bech32", "bip32", "bls12_381", "bs58", @@ -8890,7 +8956,7 @@ name = "zcash_keys" version = "0.12.0" source = "git+https://github.com/zcash/librustzcash.git?rev=69f1b3599cb79d08fa73018914bebd1c51db3ef8#69f1b3599cb79d08fa73018914bebd1c51db3ef8" dependencies = [ - "bech32 0.11.1", + "bech32", "bip32", "blake2b_simd", "bls12_381", @@ -9109,7 +9175,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b64bf5186a8916f7a48f2a98ef599bf9c099e2458b36b819e393db1c0e768c4b" dependencies = [ - "bech32 0.11.1", + "bech32", "blake2b_simd", "memuse", "subtle", @@ -9121,7 +9187,7 @@ name = "zip321" version = "0.6.0" source = "git+https://github.com/zcash/librustzcash.git?rev=69f1b3599cb79d08fa73018914bebd1c51db3ef8#69f1b3599cb79d08fa73018914bebd1c51db3ef8" dependencies = [ - "base64 0.22.1", + "base64", "nom 7.1.3", "percent-encoding", "zcash_address", diff --git a/Cargo.toml b/Cargo.toml index 8cf7c4e..3736811 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,10 @@ clap = { version = "4.5", features = ["derive", "string", "unstable-styles"] } rand = { version = "0.8", default-features = false } # Seed encryption -age = { version = "0.11", features = ["armor", "plugin"] } +# original rage causing non-determinism +#age = { version = "0.11", features = ["armor", "plugin"] } +# patched version +age = { git="https://github.com/antonleviathan/rage.git", branch="deterministic-iteration", features = ["armor", "plugin"] } chrono = "0.4" rpassword = "7" From f49472917aab0ac91feb168229a41954b4b59f4e Mon Sep 17 00:00:00 2001 From: al amoda Date: Fri, 17 Apr 2026 15:23:57 -0400 Subject: [PATCH 7/7] update traits --- src/commands/wallet/pay.rs | 2 +- src/commands/wallet/send.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/wallet/pay.rs b/src/commands/wallet/pay.rs index 1193cad..a2f54fa 100644 --- a/src/commands/wallet/pay.rs +++ b/src/commands/wallet/pay.rs @@ -52,7 +52,7 @@ impl PaymentContext for Command { self.account_id } - fn age_identities(&self) -> anyhow::Result>> { + fn age_identities(&self) -> anyhow::Result>> { let identities = age::IdentityFile::from_file(self.identity.clone())?.into_identities()?; Ok(identities) } diff --git a/src/commands/wallet/send.rs b/src/commands/wallet/send.rs index ffb3756..0809ad9 100644 --- a/src/commands/wallet/send.rs +++ b/src/commands/wallet/send.rs @@ -81,7 +81,7 @@ pub(crate) struct Command { pub(crate) trait PaymentContext { fn spending_account(&self) -> Option; - fn age_identities(&self) -> anyhow::Result>>; + fn age_identities(&self) -> anyhow::Result>>; fn connection_args(&self) -> &ConnectionArgs; fn target_note_count(&self) -> usize; fn min_split_output_value(&self) -> u64; @@ -94,7 +94,7 @@ impl PaymentContext for Command { self.account_id } - fn age_identities(&self) -> anyhow::Result>> { + fn age_identities(&self) -> anyhow::Result>> { let identities = age::IdentityFile::from_file(self.identity.clone())?.into_identities()?; Ok(identities) }