- `--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.
OpenSSL came from two removable defaults: teloxide's `default` feature
(native-tls) and x-media's reqwest default features (default-tls). Switch
both to rustls (webpki-roots) so the binary links no system TLS libs:
- teloxide: default-features=false + rustls + ctrlc_handler (was part of
the removed default)
- reqwest (x-media): default-features=false + rustls-tls
Verified: openssl-sys/native-tls gone from the tree, cargo check clean,
all 5 live twitter/bsky fetches pass over rustls, full container startup
works. The runtime image now needs no libssl.so.3/libcrypto.so.3 or CA
bundle (ffmpeg only processes local files; all downloads go through
reqwest), saving ~8MB.
c40b074 broke the image two ways:
- `cargo clean -p` removes 0 files, so the real sources (host mtimes
older than the step-1 stub build) were never recompiled and the image
shipped the 337KB fn-main stub, exiting 0 on start. Restore the
touch-based rebuild, which forces cargo to see every .rs as newer.
- bookworm-slim does not ship libssl3 despite the old comment; the bot
links OpenSSL via teloxide/reqwest native-tls, so restore the
libssl/libcrypto copies from the builder (same Debian release).
- Replace the mtime-touch stub-rebuild hack with cargo clean -p (a
future-dated host file could silently ship the stub binary)
- Optional FFMPEG_SHA256 build arg verified before extraction
- Drop the redundant libssl3/libcrypto copies and the root
supplementary group; strip the release binary; add a webhook-mode
healthcheck to the compose example