Dockerfile: build git-ents in-image instead of copying a prebuilt binary
commit f2d4241
Dockerfile: build git-ents in-image instead of copying a prebuilt binary
docker/bin/git-ents was a musl binary cross-compiled by hand on the
host (cargo zigbuild) and materialized into the build context before
docker build — the exact step someone forgot right after today’s
signed-push fix landed, silently deploying stale code that never
advertised push-cert despite the config changes taking effect. The
Dockerfile now has a builder stage (rust:1-slim-bookworm + musl-tools)
that compiles crates/cli/git-ents for x86_64-unknown-linux-musl from
the same source tree the rest of the image comes from; .dockerignore
now admits Cargo.toml/Cargo.lock/crates/ instead of excluding
everything but docker/. flyctl deploy alone is the whole pipeline
again.
Also fixes the earlier nginx redirect fix landing here: the .git-less
clone-URL redirect hardcodes https:// rather than $scheme, since Fly’s
edge terminates TLS and always forwards plain HTTP to this app —
$scheme as nginx sees it is always http and was downgrading every
redirected client to plaintext.
No reviews of this commit yet — record a verdict below.
Start a review
.dockerignore
@@ -1,6 +1,10 @@
-# The Dockerfile only ever COPYs docker/*; ignore everything else so the
-# build context stays a few KB instead of the whole workspace (including
-# target/, which alone can run into the tens of GB).
+# The Dockerfile's builder stage compiles the workspace, so the build
+# context needs the actual sources — but never `target/`, which alone can
+# run into the tens of GB and would balloon every build upload.
*
+!Cargo.toml
+!Cargo.lock
+!crates/
+!crates/**
!docker/
!docker/**
.gitignore
@@ -1,5 +1,2 @@
.DS_Store
target/
-# Materialized from refs/meta/releases/<sha> just before `docker build`;
-# never a normal tracked file.
-docker/bin/
Dockerfile
@@ -4,11 +4,24 @@
# nginx+fcgiwrap) invokes its `pre-receive`/`post-receive` hooks. No
# Postgres/Tigris/gix-receive here — that is `git-ents-server`, phase 8.
#
-# No Rust toolchain, no cargo build, in this image: `docker/bin/git-ents` is
-# a musl static binary cross-compiled on the host (`cargo zigbuild --target
-# x86_64-unknown-linux-musl`) and materialized here from the on-disk blob
-# recorded at `refs/meta/releases/<source-commit-sha>` — never a normal
-# tracked file on `refs/heads` (see `.gitignore`).
+# The binary builds *in* this image, from the same source tree the rest
+# of the deploy comes from — never a separately cross-compiled artifact
+# copied in by hand. That used to be `docker/bin/git-ents`, a musl binary
+# built on the host and materialized here before `docker build`; the
+# whole point of that indirection was to skip a slow in-container Rust
+# build, but it silently deployed stale code whenever someone forgot the
+# manual rebuild step, exactly the failure mode a deploy pipeline exists
+# to prevent.
+FROM rust:1-slim-bookworm AS builder
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends musl-tools \
+ && rm -rf /var/lib/apt/lists/*
+RUN rustup target add x86_64-unknown-linux-musl
+WORKDIR /src
+COPY Cargo.toml Cargo.lock ./
+COPY crates crates
+RUN cargo build --release --locked --target x86_64-unknown-linux-musl -p git-ents
+
FROM debian:bookworm-slim AS runtime
WORKDIR /app
# git: the bare repo + git-http-backend CGI itself.
@@ -26,7 +39,7 @@
RUN curl -fsSL https://sprites.dev/install.sh \
| env SPRITE_INSTALL_PREFERRED_DIRS=/usr/local/bin \
SPRITE_INSTALL_DEFAULT_BIN_DIR=/usr/local/bin bash
-COPY docker/bin/git-ents /usr/local/bin/git-ents
+COPY --from=builder /src/target/x86_64-unknown-linux-musl/release/git-ents /usr/local/bin/git-ents
RUN chmod +x /usr/local/bin/git-ents
COPY docker/nginx.conf /etc/git-ents/nginx.conf
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
docker/nginx.conf
@@ -41,11 +41,17 @@
# to the canonical `.git` path above. git's http client re-issues
# every request of the clone/fetch/push against the redirected
# base, not just this first one, so one redirect here is enough.
+ #
+ # Hardcoded `https://`, not `$scheme`: Fly's edge terminates TLS
+ # and always forwards plain HTTP to this app (`force_https=true`
+ # in fly.toml already guarantees no real client reaches here over
+ # HTTP), so `$scheme` as nginx sees it is always `http` and would
+ # downgrade every redirected client to plaintext.
location = /git-ents/git-ents {
- return 301 $scheme://$host/git-ents/git-ents.git;
+ return 301 https://$host/git-ents/git-ents.git;
}
location ~ ^/git-ents/git-ents/(.*)$ {
- return 301 $scheme://$host/git-ents/git-ents.git/$1$is_args$args;
+ return 301 https://$host/git-ents/git-ents.git/$1$is_args$args;
}
# The server key's public half (`git ents setup --hosted` writes