Skip to content

Commit 981389a

Browse files
hyperpolymathclaude
andcommitted
fix(wave3): repair 4 silent-stub / non-relocatable backends (tamarin twelf acl2 metamath)
Runtime-smoke-testing every built Wave-3 image (prompted by "look at scip") proved the green builds hid non-functional backends. Two recurring classes + two one-offs, all fixed at-source: - tamarin: NOT a dead URL — the GitHub download works, but the installer stage lacked `maude` (tamarin execs `maude --version` during its own --version), so the in-builder smoke-test always exited 1 and the graceful stub shipped every build. Add maude to installer + runtime, bump 1.8.0 -> 1.12.0, adopt the deterministic /opt/tamarin-export real-or-stub tree. Binary is dynamically linked (libgmp10/zlib1g), not static as the old comment claimed. - twelf: not relocatable — `make smlnj` bakes the absolute build dir into bin/twelf-server and bin/.heap/twelf-server; COPY /build/twelf -> /opt/twelf dangled the heap path. Build in-place at /opt/twelf. - acl2: not relocatable — saved_acl2 wrapper bakes the absolute saved_acl2.core path and the core bakes the source/books root; COPY /build/acl2 -> /opt/acl2 caused "open: No such file". Build in-place at /opt/acl2; also assert saved_acl2.core exists. - metamath: never installed at all. The "pure-Rust in-process verifier" premise was false — src/rust/provers/metamath.rs execs the `metamath` CLI. Add a metamath-builder stage (metamath-exe v0.198, pure-C `gcc m*.c`, no GitHub releases — git tags only), COPY the binary to /usr/local/bin; fix the false comments/labels. Same lesson as scip 63bacf0 / hol4 6032f2e: a green Wave-3 build is not a working backend — runtime-smoke every image. Brittle-pin re-validation tracked in #75; proverif deeper fix still #74. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6032f2e commit 981389a

1 file changed

Lines changed: 130 additions & 46 deletions

File tree

.containerization/Containerfile.wave3

Lines changed: 130 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -62,37 +62,47 @@ RUN cargo build --release --bin echidna
6262
# #############################################################################
6363
FROM docker.io/library/debian:bookworm-slim AS tamarin-installer
6464

65+
# maude is REQUIRED here, not just in the runtime stage: tamarin-prover
66+
# shells out to `maude --version` *before* printing its own version, so the
67+
# in-builder smoke-test below cannot pass without it. (This — NOT a dead URL —
68+
# was why tamarin always shipped a stub: the GitHub download succeeded but the
69+
# `--version` smoke-test exited 1 on missing maude. Brittle-pin tracking: #75.)
6570
RUN apt-get update && apt-get install -y --no-install-recommends \
6671
curl \
6772
ca-certificates \
68-
wget \
69-
file \
73+
maude \
7074
&& rm -rf /var/lib/apt/lists/*
7175

72-
WORKDIR /opt/tamarin
76+
# Official prebuilt binary from the tamarin-prover/tamarin-prover GitHub
77+
# releases (GPL-3.0; anonymous; reliable). The linux64-ubuntu tarball contains
78+
# a single dynamically-linked x86_64 `tamarin-prover` at the archive root;
79+
# its only shared-lib deps are libm/libz/libgmp10/libc. It is a Maude
80+
# front-end and needs `maude` (hard) + graphviz `dot` (visualisation) at
81+
# runtime. Re-validate at https://github.com/tamarin-prover/tamarin-prover/releases.
82+
ARG TAMARIN_VERSION="1.12.0"
83+
ARG TAMARIN_TARBALL="tamarin-prover-${TAMARIN_VERSION}-linux64-ubuntu.tar.gz"
84+
ARG TAMARIN_URL="https://github.com/tamarin-prover/tamarin-prover/releases/download/${TAMARIN_VERSION}/${TAMARIN_TARBALL}"
7385

74-
# Download prebuilt static binary from the tamarin-prover/tamarin-prover GitHub releases.
75-
# The release tarball contains a static Linux x86_64 binary that runs without Haskell.
76-
# Check https://github.com/tamarin-prover/tamarin-prover/releases for the latest version.
77-
ARG TAMARIN_VERSION="1.8.0"
86+
# Deterministic export tree so the runtime COPY never hard-fails: the real
87+
# binary if download + smoke-test succeed, a stub otherwise.
7888
RUN set -eux; \
79-
TARBALL="tamarin-prover-${TAMARIN_VERSION}-linux64-ubuntu.tar.gz"; \
80-
URL="https://github.com/tamarin-prover/tamarin-prover/releases/download/${TAMARIN_VERSION}/${TARBALL}"; \
81-
curl -fsSL --retry 3 "${URL}" -o /tmp/tamarin.tar.gz \
82-
&& tar -xzf /tmp/tamarin.tar.gz -C /opt/tamarin \
83-
&& rm /tmp/tamarin.tar.gz \
84-
&& chmod +x /opt/tamarin/tamarin-prover \
85-
&& /opt/tamarin/tamarin-prover --version \
86-
|| { \
87-
echo "WARNING: Prebuilt tamarin-prover binary download failed."; \
88-
echo "Fallback: build via Haskell Stack (uncomment the block below)."; \
89-
echo "Stack build takes several hours and ~8 GB RAM."; \
90-
echo "See: https://tamarin-prover.com/installation/"; \
91-
mkdir -p /opt/tamarin; \
92-
printf '#!/bin/sh\necho "tamarin-prover not available (prebuilt download failed at image build time)"\nexit 1\n' \
93-
> /opt/tamarin/tamarin-prover; \
94-
chmod +x /opt/tamarin/tamarin-prover; \
95-
}
89+
mkdir -p /opt/tamarin-export; \
90+
if curl -fsSL --retry 3 "${TAMARIN_URL}" -o /tmp/tamarin.tar.gz \
91+
&& tar -xzf /tmp/tamarin.tar.gz -C /opt/tamarin-export \
92+
&& chmod +x /opt/tamarin-export/tamarin-prover \
93+
&& /opt/tamarin-export/tamarin-prover --version; then \
94+
echo "tamarin-prover ${TAMARIN_VERSION} installed."; \
95+
else \
96+
echo "WARNING: tamarin-prover download/smoke-test failed."; \
97+
echo "Re-check https://github.com/tamarin-prover/tamarin-prover/releases."; \
98+
echo "Creating stub binary as fallback."; \
99+
mkdir -p /opt/tamarin-export; \
100+
printf '#!/bin/sh\necho "tamarin-prover not available (bundle install failed at image build time)"\nexit 1\n' \
101+
> /opt/tamarin-export/tamarin-prover; \
102+
chmod +x /opt/tamarin-export/tamarin-prover; \
103+
fi; \
104+
rm -f /tmp/tamarin.tar.gz; \
105+
touch /opt/tamarin-export/.keep
96106

97107
# --- Fallback: Haskell Stack build (uncomment if prebuilt binary is unavailable) ---
98108
# RUN apt-get update && apt-get install -y --no-install-recommends \
@@ -113,20 +123,25 @@ LABEL org.opencontainers.image.licenses="PMPL-1.0-or-later"
113123
LABEL org.opencontainers.image.version="2.3.0"
114124
LABEL org.opencontainers.image.vendor="hyperpolymath"
115125

116-
# Tamarin runtime deps: graphviz for its visualisation outputs, maude is the
117-
# underlying rewriting engine tamarin links against (bundled in the static
118-
# binary but maude files are loaded from the filesystem).
126+
# Tamarin runtime deps. The prebuilt binary is DYNAMICALLY linked (libm,
127+
# libz, libgmp10, libc) and is a Maude front-end: `maude` is a hard runtime
128+
# requirement (NOT bundled in the binary), graphviz `dot` is needed for
129+
# visualisation output.
119130
RUN apt-get update && apt-get install -y --no-install-recommends \
120131
ca-certificates \
121-
libssl3 \
122132
libgmp10 \
133+
zlib1g \
134+
maude \
123135
graphviz \
124136
&& rm -rf /var/lib/apt/lists/*
125137

126138
WORKDIR /app
127139

128140
COPY --from=rust-builder /build/target/release/echidna /app/bin/echidna
129-
COPY --from=tamarin-installer /opt/tamarin/tamarin-prover /usr/local/bin/tamarin-prover
141+
# Deterministic export tree (real binary if the GitHub download + smoke-test
142+
# succeeded, a one-file stub otherwise). A directory COPY never hard-fails.
143+
COPY --from=tamarin-installer /opt/tamarin-export/ /opt/tamarin/
144+
RUN ln -sf /opt/tamarin/tamarin-prover /usr/local/bin/tamarin-prover
130145

131146
ENV PATH="/app/bin:/usr/local/bin:${PATH}"
132147
ENV ECHIDNA_PROVER_PATH="/usr/local/bin"
@@ -547,23 +562,27 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
547562
gcc \
548563
&& rm -rf /var/lib/apt/lists/*
549564

550-
WORKDIR /build
551-
552-
# Clone ACL2 from the official GitHub mirror.
553-
# Use a versioned tag for reproducibility.
565+
# Clone ACL2 directly at its FINAL runtime path. ACL2 is NOT relocatable:
566+
# `make LISP=sbcl` writes a saved_acl2 wrapper that bakes the absolute path
567+
# to saved_acl2.core, and the SBCL core bakes the absolute ACL2 source/books
568+
# directory. Building at /build/acl2 then COPYing to /opt/acl2 produced a
569+
# saved_acl2 whose wrapper exec'd /build/acl2/saved_acl2.core — "open: No
570+
# such file or directory" at runtime. Build in-place at /opt/acl2 so the
571+
# baked paths are correct in the runtime image (ACL2_SYSTEM_BOOKS=/opt/acl2/books).
554572
# Check https://github.com/acl2/acl2/releases for the latest version.
555573
ARG ACL2_VERSION="8.6"
556574
RUN git clone --depth 1 --branch "v${ACL2_VERSION}" \
557-
https://github.com/acl2/acl2.git /build/acl2 \
575+
https://github.com/acl2/acl2.git /opt/acl2 \
558576
|| git clone --depth 1 \
559-
https://github.com/acl2/acl2.git /build/acl2
577+
https://github.com/acl2/acl2.git /opt/acl2
560578

561-
WORKDIR /build/acl2
579+
WORKDIR /opt/acl2
562580

563581
# Build ACL2 using SBCL. The `make` target `LISP=sbcl` compiles ACL2 and
564582
# saves a SBCL core image. The resulting saved_acl2 is the executable image.
565583
RUN make LISP=sbcl -j"$(nproc)" \
566-
&& test -f /build/acl2/saved_acl2 \
584+
&& test -f /opt/acl2/saved_acl2 \
585+
&& test -f /opt/acl2/saved_acl2.core \
567586
&& echo "ACL2 build succeeded"
568587

569588
# Create the acl2 wrapper script (mirrors the standard install convention)
@@ -591,7 +610,9 @@ WORKDIR /app
591610
COPY --from=rust-builder /build/target/release/echidna /app/bin/echidna
592611

593612
# Copy ACL2 saved image and source tree (ACL2 loads books from its source tree)
594-
COPY --from=acl2-builder /build/acl2 /opt/acl2
613+
# Built in-place at /opt/acl2 → the saved_acl2 wrapper's baked core path and
614+
# the core's baked source/books root stay valid at runtime.
615+
COPY --from=acl2-builder /opt/acl2 /opt/acl2
595616

596617
# Install the acl2 wrapper script
597618
RUN printf '#!/bin/sh\nexec /opt/acl2/saved_acl2 "$@"\n' > /usr/local/bin/acl2 \
@@ -627,17 +648,24 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
627648
smlnj \
628649
&& rm -rf /var/lib/apt/lists/*
629650

630-
WORKDIR /build
651+
# Clone+build Twelf directly at its FINAL runtime path. SML/NJ heap images
652+
# are NOT relocatable: `make smlnj` bakes the absolute build directory into
653+
# bin/twelf-server's `sml @SMLload=...` and into bin/.heap/twelf-server.
654+
# Building at /build/twelf then COPYing to /opt/twelf produced a twelf-server
655+
# whose heap path /build/twelf/bin/.heap/twelf-server dangled at runtime
656+
# ("unable to open heap image"). Build in-place at /opt/twelf so the baked
657+
# paths are correct in the runtime image (which also uses TWELFDIR=/opt/twelf).
658+
WORKDIR /opt
631659

632660
# Clone the Twelf source from the official repository.
633661
# The canonical upstream is hosted at https://github.com/standardml/twelf.
634662
# Twelf does not use versioned tags; we pin to the tip of the main branch and
635663
# note the commit in the label below. For strict reproducibility, replace
636664
# `--depth 1` with `--branch <commit-sha>`.
637665
RUN git clone --depth 1 \
638-
https://github.com/standardml/twelf.git /build/twelf
666+
https://github.com/standardml/twelf.git /opt/twelf
639667

640-
WORKDIR /build/twelf
668+
WORKDIR /opt/twelf
641669

642670
# Build Twelf using SML/NJ's ml-build.
643671
# The Makefile target `smlnj` compiles a heap image; `twelf-server` is a
@@ -670,7 +698,9 @@ WORKDIR /app
670698
COPY --from=rust-builder /build/target/release/echidna /app/bin/echidna
671699

672700
# Copy the Twelf installation (src tree + compiled heap + wrapper scripts)
673-
COPY --from=twelf-builder /build/twelf /opt/twelf
701+
# Built in-place at /opt/twelf → the baked absolute heap path in
702+
# bin/twelf-server / bin/.heap/twelf-server stays valid at runtime.
703+
COPY --from=twelf-builder /opt/twelf /opt/twelf
674704

675705
# The twelf-server wrapper script references $TWELFDIR; make it a proper
676706
# system binary by symlinking.
@@ -693,8 +723,55 @@ ENTRYPOINT ["/app/bin/echidna"]
693723
CMD ["--help"]
694724

695725
# #############################################################################
696-
# TARGET: metamath — pure-Rust in-process verifier + bundled databases
726+
# TARGET: metamath — upstream metamath-exe CLI verifier + bundled databases
697727
# #############################################################################
728+
729+
# metamath-exe — the upstream Metamath CLI verifier. The ECHIDNA Metamath
730+
# backend (src/rust/provers/metamath.rs) shells out to `metamath` and drives
731+
# `read "<file>" / verify proof * / exit` over stdin, so a REAL binary must be
732+
# on PATH at runtime. The previous stage installed NO metamath binary (the
733+
# "pure-Rust" comment was wrong) → "metamath: not found" at runtime.
734+
# metamath-exe is a tiny pure-C program (libc only); the GitHub source tarball
735+
# is the reliable anonymous source. NOTE: metamath-exe publishes NO GitHub
736+
# Releases — only git tags; do not query releases/latest.
737+
# Re-validate the tag at https://github.com/metamath/metamath-exe/tags (#75).
738+
FROM docker.io/library/debian:bookworm-slim AS metamath-builder
739+
740+
RUN apt-get update && apt-get install -y --no-install-recommends \
741+
curl \
742+
ca-certificates \
743+
gcc \
744+
make \
745+
&& rm -rf /var/lib/apt/lists/*
746+
747+
ARG MM_VERSION="0.198"
748+
ARG MM_TARBALL="v${MM_VERSION}.tar.gz"
749+
ARG MM_URL="https://github.com/metamath/metamath-exe/archive/refs/tags/${MM_TARBALL}"
750+
751+
# Deterministic export tree so the runtime COPY never hard-fails: the real
752+
# binary if download + build + smoke-test succeed, a stub otherwise. The
753+
# GitHub tarball ships no generated ./configure; the README-documented
754+
# `gcc m*.c -o metamath` path is dependency-free and authoritative.
755+
RUN set -eux; \
756+
mkdir -p /opt/mm-export/bin; \
757+
if curl -fsSL --retry 3 "${MM_URL}" -o /tmp/mm.tgz \
758+
&& tar -xzf /tmp/mm.tgz -C /tmp \
759+
&& ( cd "/tmp/metamath-exe-${MM_VERSION}" \
760+
&& gcc m*.c -o metamath -O2 \
761+
&& printf 'exit\n' | ./metamath ) ; then \
762+
cp "/tmp/metamath-exe-${MM_VERSION}/metamath" /opt/mm-export/bin/metamath; \
763+
else \
764+
echo "WARNING: metamath-exe download/build/smoke-test failed."; \
765+
echo "Re-check https://github.com/metamath/metamath-exe/tags."; \
766+
echo "Creating stub binary as fallback."; \
767+
printf '#!/bin/sh\necho "metamath not available (build failed at image build time)"\nexit 1\n' \
768+
> /opt/mm-export/bin/metamath; \
769+
chmod +x /opt/mm-export/bin/metamath; \
770+
fi; \
771+
chmod +x /opt/mm-export/bin/metamath; \
772+
rm -rf /tmp/mm.tgz "/tmp/metamath-exe-${MM_VERSION}"; \
773+
touch /opt/mm-export/.keep
774+
698775
FROM docker.io/library/debian:bookworm-slim AS mm-db-fetcher
699776

700777
RUN apt-get update && apt-get install -y --no-install-recommends \
@@ -725,13 +802,14 @@ FROM docker.io/library/debian:bookworm-slim AS metamath
725802

726803
LABEL maintainer="Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"
727804
LABEL org.opencontainers.image.source="https://github.com/hyperpolymath/echidna"
728-
LABEL org.opencontainers.image.description="ECHIDNA + Metamath - pure-Rust in-process verifier with bundled databases"
805+
LABEL org.opencontainers.image.description="ECHIDNA + Metamath - metamath-exe CLI verifier with bundled databases"
729806
LABEL org.opencontainers.image.licenses="PMPL-1.0-or-later"
730807
LABEL org.opencontainers.image.version="2.3.0"
731808
LABEL org.opencontainers.image.vendor="hyperpolymath"
732809

733-
# Metamath is a pure-Rust verifier with no external binary; runtime deps
734-
# are only those needed by the ECHIDNA binary itself.
810+
# The Metamath backend shells out to the metamath-exe CLI (installed to
811+
# /usr/local/bin below). metamath-exe is pure C / libc-only, so runtime
812+
# deps here are only those needed by the ECHIDNA Rust binary itself.
735813
RUN apt-get update && apt-get install -y --no-install-recommends \
736814
ca-certificates \
737815
libssl3 \
@@ -742,6 +820,12 @@ WORKDIR /app
742820

743821
COPY --from=rust-builder /build/target/release/echidna /app/bin/echidna
744822

823+
# The metamath-exe CLI verifier. The Rust backend execs bare `metamath`
824+
# (provers/mod.rs default_executable), resolved via PATH; /usr/local/bin is
825+
# on the default Debian PATH. The export tree always contains a file (real
826+
# binary or stub) so this single-file COPY never hard-fails.
827+
COPY --from=metamath-builder /opt/mm-export/bin/metamath /usr/local/bin/metamath
828+
745829
# Bundle the canonical Metamath databases at a well-known path.
746830
# ECHIDNA reads ECHIDNA_METAMATH_DB_DIR at startup to pre-index databases.
747831
COPY --from=mm-db-fetcher /opt/metamath-db /app/metamath-db

0 commit comments

Comments
 (0)