fix: bust stale Dagger cache and harden SSH key normalisation in Deployer (#406)
## Summary Fixes the persistent `Load key "/root/.ssh/id_ed25519": error in libcrypto` failures in the `deploy-apk` and `deploy-linux` CI jobs (and the `website` workflow SSH steps) that have been occurring on every deploy run since the jobs first started running after #369. Closes #404 ### Root cause (diagnosed from run #1516 log) Two compounding problems were found: 1. **Stale Dagger cache** — The `tr -d \x27\r\x27` normalisation step added in #369 was shown as `CACHED` by Dagger on every subsequent run. Dagger caches by input-content hash; if the very first execution produced a corrupted key file, that broken cached layer is replayed forever. 2. **`.ssh/` directory permissions** — Dagger creates parent directories for secret mounts with 755 permissions. Mounting the raw key directly inside `/root/.ssh/` may cause Dagger to (re-)create that directory with 755 instead of the 700 that OpenSSH requires. ### Changes (`ci/main.go` — `Deployer` function only) - **Explicit `.ssh` setup**: `mkdir -p /root/.ssh && chmod 700 /root/.ssh` runs before any Dagger secret mount. - **Move raw-key mount out of `.ssh/`**: Secret mounted at `/tmp/id_ed25519.raw`. - **Python3 normalisation instead of `tr`**: Handles CRLF, bare-CR, and missing trailing newline. Changing the command changes the Dagger cache key, forcing a fresh read of the current live secret. ## Test plan - [ ] `deploy-apk` job completes without `error in libcrypto` - [ ] `deploy-linux` job completes without `error in libcrypto` - [ ] `publish-android` (Play Store) job continues to succeed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Thomas SharedInbox <sharedinbox@thomas-guettler.de> Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/406
This commit was merged in pull request #406.
This commit is contained in:
committed by
guettli
co-authored by
guettli
Thomas SharedInbox
parent
cd8c930000
commit
0195f6e75c
+11
-6
@@ -338,12 +338,17 @@ func (m *Ci) Deployer(sshKey *dagger.Secret, knownHosts *dagger.Secret) *dagger.
|
||||
return dag.Container().
|
||||
From("alpine:3.21").
|
||||
WithExec([]string{"apk", "--no-cache", "add", "rsync", "openssh-client", "python3", "tar"}).
|
||||
// Mount at a raw path so we can normalise before use: strip any CRLF line
|
||||
// endings that appear when the key is stored or exported on Windows, which
|
||||
// cause "error in libcrypto" in Alpine's LibreSSL-backed openssh.
|
||||
WithMountedSecret("/root/.ssh/id_ed25519.raw", sshKey, dagger.ContainerWithMountedSecretOpts{Mode: 0600}).
|
||||
WithExec([]string{"sh", "-c",
|
||||
"tr -d '\\r' < /root/.ssh/id_ed25519.raw > /root/.ssh/id_ed25519 && chmod 600 /root/.ssh/id_ed25519"}).
|
||||
// Create .ssh with strict permissions before Dagger mounts anything there,
|
||||
// so the directory is 700 (not Dagger's default 755).
|
||||
WithExec([]string{"sh", "-c", "mkdir -p /root/.ssh && chmod 700 /root/.ssh"}).
|
||||
// Mount the raw key outside .ssh so Dagger cannot override the directory
|
||||
// permissions we just set above.
|
||||
WithMountedSecret("/tmp/id_ed25519.raw", sshKey, dagger.ContainerWithMountedSecretOpts{Mode: 0600}).
|
||||
// Normalise with Python3: strip CRLF/bare-CR, ensure trailing newline.
|
||||
// Using Python3 (not tr) changes the Dagger cache key so stale cached
|
||||
// results from the old tr-based step are not reused.
|
||||
WithExec([]string{"python3", "-c",
|
||||
"import os; raw=open('/tmp/id_ed25519.raw','rb').read(); key=raw.replace(b'\\r\\n',b'\\n').replace(b'\\r',b'\\n'); key=key if key.endswith(b'\\n') else key+b'\\n'; open('/root/.ssh/id_ed25519','wb').write(key); os.chmod('/root/.ssh/id_ed25519',0o600)"}).
|
||||
WithMountedSecret("/root/.ssh/known_hosts", knownHosts, dagger.ContainerWithMountedSecretOpts{Mode: 0644}).
|
||||
WithEnvVariable("RSYNC_RSH", "ssh -i /root/.ssh/id_ed25519")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user