mirror of
https://github.com/TheFunny/TelegramTwitterMediaBot.git
synced 2026-09-22 23:32:04 +00:00
- `--locked` on every cargo invocation (ci.yml clippy/test/build, both Dockerfile builds). The version bump edits Cargo.lock by hand, so a stale lock must fail loudly instead of being silently re-resolved: CI would otherwise test a different dependency set than the one committed — and than the one the released image is built from. - docker.yml: build the image (no push, no registry login, read-only build cache) on pull requests touching the build inputs. The Dockerfile's stub-source machinery, the ffmpeg download and the entrypoint previously only ran at release time. Also: a release tag must equal both crate versions before anything is built (the binary carries no version, so `v1.5.1` with manifests at 1.5.0 used to publish silently wrong tags), `FFMPEG_URL`/ `FFMPEG_SHA256` are taken from repository variables when set, and the unused `setup-qemu-action` step is gone (single-arch build; the comment says what arm64 would need). - ci.yml: `concurrency` cancels superseded runs, `permissions: contents: read`, `RUST_BACKTRACE=1`, job timeouts, and a release-profile build of the same package the Dockerfile builds (the profile was otherwise never compiled before a merge). The `live` job narrows to `-p x-media`: every network- or secret-gated test lives there, and the bot crate's offline suite already ran in the `test` job. Timeout is 45 min because the release build is cold on the first run — a timeout there would kill the job before rust-cache could save its cache, leaving every later run cold too. - Actions pinned to commit SHAs (Dependabot keeps them current); `dtolnay/rust-toolchain` stays on its channel ref by design. - .github/dependabot.yml: crates (patch bumps grouped), action pins, Docker base images — the audit gate reports advisories, this is what moves them. - tokio's `sync` feature is now declared instead of arriving transitively via teloxide; `.dockerignore` drops docs and markdown. Verified locally: `cargo fmt --check`, `cargo clippy --workspace --all-targets --locked`, `cargo test --workspace --locked` (70 + 69 pass), `cargo build --release --locked` (6m03s cold, the 15.9 MB stripped binary starts and registers 10 commands), the tag/version gate against both a matching and a mismatching tag, and YAML parsing of all three workflow files.
84 lines
4.1 KiB
Docker
84 lines
4.1 KiB
Docker
# ---------- build stage ----------
|
|
# rust:1-bookworm (full, not slim) ships the C toolchain needed by
|
|
# rusqlite's bundled SQLite, plus wget/unzip for the ffmpeg download.
|
|
FROM rust:1-bookworm AS builder
|
|
|
|
ARG APP_NAME=telegram-twitter-media-bot
|
|
# Prebuilt static ffmpeg (glibc-linked, includes libx264) for ugoira MP4
|
|
# encoding. Served from https://ffmpeg.martin-riedl.de (Cloudflare CDN,
|
|
# built on Debian 12 — glibc-compatible with the bookworm-slim runtime).
|
|
# johnvansickle.com throttles datacenter IPs and served garbage from GitHub
|
|
# runners. `/redirect/latest/` floats to the newest release build; each build
|
|
# also ships a .sha256. Swap `amd64` for `arm64` when building arm64 images.
|
|
ARG FFMPEG_URL=https://ffmpeg.martin-riedl.de/redirect/latest/linux/amd64/release/ffmpeg.zip
|
|
# Arm64 images need this URL swapped for the `linux/arm64` build (currently
|
|
# hardcoded amd64; the workflow builds amd64 only — see docker.yml).
|
|
# Optional sha256 of ffmpeg.zip (pinned releases only): set to verify the
|
|
# download. The mirror publishes .sha256 sidecars next to pinned builds, e.g.
|
|
# https://ffmpeg.martin-riedl.de/download/linux/amd64/<id>_9.0/ffmpeg.zip.sha256
|
|
# (the /redirect/latest/ URL itself has no sidecar — pin the effective URL).
|
|
ARG FFMPEG_SHA256=
|
|
|
|
WORKDIR /build
|
|
|
|
# 1. Rust dependencies first: only the manifests plus stub sources, so the
|
|
# expensive dependency fetch + compile lives in a layer invalidated only by
|
|
# manifest/lock changes.
|
|
COPY Cargo.toml Cargo.lock ./
|
|
COPY crates/x-media/Cargo.toml crates/x-media/Cargo.toml
|
|
COPY crates/xmedia-bot/Cargo.toml crates/xmedia-bot/Cargo.toml
|
|
RUN mkdir -p crates/x-media/src crates/xmedia-bot/src \
|
|
&& printf 'fn main() {}\n' > crates/xmedia-bot/src/main.rs \
|
|
&& : > crates/x-media/src/lib.rs \
|
|
&& cargo build --release --locked -p xmedia-bot
|
|
|
|
# 2. Static ffmpeg next (cached unless FFMPEG_URL changes), so source edits
|
|
# never re-download it. The zip contains a single `ffmpeg` binary at the
|
|
# root. `unzip -t` verifies the archive before extraction so a bad
|
|
# download fails loudly here instead of a cryptic later error.
|
|
RUN wget -q -O /tmp/ffmpeg.zip "$FFMPEG_URL" \
|
|
&& if [ -n "$FFMPEG_SHA256" ]; then echo "$FFMPEG_SHA256 /tmp/ffmpeg.zip" | sha256sum -c -; fi \
|
|
&& unzip -tq /tmp/ffmpeg.zip \
|
|
&& unzip -q /tmp/ffmpeg.zip -d /usr/local/bin \
|
|
&& chmod +x /usr/local/bin/ffmpeg \
|
|
&& rm /tmp/ffmpeg.zip \
|
|
&& /usr/local/bin/ffmpeg -version >/dev/null
|
|
|
|
# 3. Real sources last: only our crates recompile on source changes. Cargo's
|
|
# freshness check is mtime-based; the COPY'd host files usually predate the
|
|
# step-1 stub build, so cargo would consider the stub up to date and never
|
|
# compile the real sources. `touch` makes every .rs newer than the stub
|
|
# artifacts, forcing a rebuild of just the two crates while the compiled
|
|
# dependency layer stays cached. (`cargo clean -p` does NOT work here — it
|
|
# removes 0 files and the stub binary silently ships.)
|
|
COPY crates/ ./crates/
|
|
RUN find crates -type f -name '*.rs' -exec touch {} + \
|
|
&& cargo build --release --locked -p xmedia-bot
|
|
|
|
# ---------- runtime stage ----------
|
|
FROM debian:bookworm-slim
|
|
|
|
# ARG scope is per-stage: re-declare for the label below.
|
|
ARG APP_NAME=telegram-twitter-media-bot
|
|
|
|
LABEL maintainer="admin@yoursfunny.top"
|
|
LABEL org.opencontainers.image.title="${APP_NAME}"
|
|
|
|
# Everything is copied in — no apt in the runtime stage. Privilege dropping is
|
|
# done by docker-entrypoint.sh with setpriv (util-linux, already in
|
|
# bookworm-slim), so no gosu needed. TLS is rustls (webpki-roots baked in,
|
|
# see Cargo.toml feature `rustls`/`rustls-tls`), so no system CA bundle or
|
|
# libssl are needed; the static ffmpeg only processes local files (all
|
|
# downloads go through reqwest).
|
|
COPY --from=builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg
|
|
|
|
WORKDIR /app
|
|
COPY --from=builder /build/target/release/xmedia-bot /usr/local/bin/xmedia-bot
|
|
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
|
|
RUN chmod a+x /app/docker-entrypoint.sh
|
|
|
|
# State lives in /app/data (SQLite task queue + chat state); mount a volume
|
|
# there to keep it across restarts.
|
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
|
CMD ["xmedia-bot"]
|