Disclosure up front: I maintain easySFTP, so this is me proposing my own action. Close it without ceremony if you would rather not switch. I kept the diff to the deploy step and touched nothing else.
What changes
The deploy job of emscripten.yml uses eiserv/easySFTP@v3 instead of wlixcc/SFTP-Deploy-Action@v1.2.4.
Secret names are unchanged (USERNAME, SERVER, PORT, PRIVATE_KEY, REMOTE_PATH), so there is nothing to add or rename in repo settings before this can be merged.
Input mapping:
| before | after | note |
|---|---|---|
server | host | |
ssh_private_key | private-key | same PEM content, same secret |
local_path: './emscripten/*' | source: emscripten | contents land in target, same result as put -r ./emscripten/* |
remote_path | target | |
sftp_only: true | dropped | |
allow-any-host-key: true | see below |
sftp_only: true was there to stop the old action from opening a second SSH session just to run mkdir -p. easySFTP creates missing remote directories over the SFTP channel it already has, so there is no exec session to suppress and no flag to set.
About that allow-any-host-key
easySFTP refuses to connect unless you either pin the server's host key or state explicitly that you do not want to. The old action hardcoded -o StrictHostKeyChecking=no, so allow-any-host-key: true is what keeps today's behaviour exactly as it is. Merging this changes your trust model in neither direction.
If you want the upgrade later it is a one line swap. Run
ssh-keyscan -p <port> <host>put the output into a KNOWN_HOSTS secret, and replace allow-any-host-key: true with known-hosts: ${{ secrets.KNOWN_HOSTS }}. Multiple lines are accepted, so you can paste every key the server offers and not worry about which algorithm gets negotiated.
Why bother
Three things that are relevant to this specific job.
Uploads are atomic per file. sftp -b with put -r writes straight into the destination path. If the connection drops partway through tracy-profiler.wasm.zst, the file being served is now a truncated one, and it stays truncated until the next successful run. easySFTP streams each file to a temporary sibling and renames it over the target only once the transfer completed, so a broken connection leaves the previous version live.
It retries. Right now a dropped connection is a failed job and a half deployed site. easySFTP redials on connection level errors within a run wide retry budget and picks up where it stopped. It also has a stall watchdog for the less obvious case where the server accepts the connection and then goes quiet.
Less fixed cost per run. wlixcc/SFTP-Deploy-Action is a Docker action, so every run builds an Alpine image and apk adds rsync, sshpass, openssh and expect before the first byte moves. easySFTP is a composite action that pulls one static Go binary and checks it against the release checksums. On seven files that setup cost is most of the wall clock.
Throughput matters less here because the payload is small, but for the record: the old action pushes files one after another through a single sftp channel, easySFTP transfers files in parallel (4 by default) and keeps multiple write requests in flight per file (16 by default), which is what actually fills a high latency link.
Smaller things you may or may not care about: a dry-run input, files-uploaded / bytes-uploaded / duration-ms step outputs, a job summary table, and gitignore syntax exclude patterns.
Docs: https://github.com/eiserv/easySFTP. Benchmark method and stored results live in benchmarks/ in that repo.
I have not been able to test this against your actual server for obvious reasons, so the sanity check I can offer is that the input mapping above is mechanical and the deploy job is unchanged otherwise. Happy to adjust anything.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.