From ca0039400e334c2cabd207885ae6b6061574df7d Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Sat, 5 Sep 2026 12:52:36 +0200 Subject: [PATCH] fix: give the container a trust store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Proton Drive client verifies TLS against the system CAs, and debian-slim ships none at all — no /etc/ssl/certs, no bundle — so every request out of the container died at the handshake with "No CA certificates were loaded from the system", before it could even be a login. `webpki-roots` is compiled in, but choosing it happens inside the SDK when it builds its HTTP client, so the image is the place to fix it. Also answer `--help` before reading the configuration: a host that has not been set up yet is exactly where that question gets asked, and it was being met with "DIARY_USER must be set". Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01D5Gk8FPkRXu1e6Nj2BCRE1 --- Dockerfile | 10 ++++++++-- src/main.rs | 14 ++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index c894f9f..c3f5487 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,9 +21,15 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \ cargo build --release --locked \ && cp target/release/narl-diary /usr/local/bin/narl-diary -# 3. Runtime. SQLite is compiled into the binary, so nothing else is needed. +# 3. Runtime. SQLite is compiled into the binary; the only thing the image has +# to supply is a trust store. The Proton Drive client verifies TLS against +# the system CAs, and debian-slim ships none — without this, every request +# to Proton fails with "No CA certificates were loaded from the system". FROM debian:trixie-slim -RUN useradd --system --uid 10001 --create-home --home-dir /home/diary diary \ +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* \ + && useradd --system --uid 10001 --create-home --home-dir /home/diary diary \ && mkdir -p /data \ && chown diary:diary /data COPY --from=build /usr/local/bin/narl-diary /usr/local/bin/narl-diary diff --git a/src/main.rs b/src/main.rs index 0609640..626a190 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,6 +40,16 @@ async fn main() -> Result<()> { .with(tracing_subscriber::fmt::layer()) .init(); + // Asked before anything is loaded: `--help` must answer on a host that has + // not been configured yet, which is exactly where it gets asked. + if matches!( + std::env::args().nth(1).as_deref(), + Some("help" | "--help" | "-h") + ) { + print!("{}", cli::USAGE); + return Ok(()); + } + let config = Config::from_env()?; tokio::fs::create_dir_all(config.uploads_dir()) .await @@ -64,10 +74,6 @@ async fn main() -> Result<()> { ); return Ok(()); } - Some("help" | "--help" | "-h") => { - print!("{}", cli::USAGE); - return Ok(()); - } Some(other) => { anyhow::bail!("unknown command {other:?}\n\n{}", cli::USAGE); }