Skip to content

Deploy over native ssh and scp instead of third-party actions - #836

Open
Jack-Edwards wants to merge 4 commits into
stablefrom
chore/native-ssh-deploy
Open

Deploy over native ssh and scp instead of third-party actions#836
Jack-Edwards wants to merge 4 commits into
stablefrom
chore/native-ssh-deploy

Conversation

@Jack-Edwards

@Jack-Edwards Jack-Edwards commented Aug 1, 2026

Copy link
Copy Markdown
Member

appleboy/scp-action and appleboy/ssh-action both download a binary from GitHub releases at run time with no checksum verification, so pinning them to a commit SHA does not cover the code that actually executes. This workflow holds the production SSH key, so it is the one place worth removing that dependency. The OpenSSH client already on the runner does everything the workflow needs.

A Configure SSH step writes the key, a known_hosts file, and a Host appserver alias, after which each step is a plain ssh or scp invocation.

Deployment steps: this needs a new APPSERVER_SSH_KNOWN_HOSTS secret in both the production and staging environments before the next deploy. Neither action was verifying the host key previously, since no fingerprint was ever configured; host key checking is now strict, and the workflow fails with instructions if the secret is missing. Capturing the key is documented under Record the host key in Web Server Setup. The host field of each known_hosts line has to match APPSERVER_SSH_HOST and APPSERVER_SSH_PORT, which means [host]:port on a non-default port.

A remote command that exits non-zero now fails the workflow. appleboy/ssh-action left script_stop unset, so a failed migration or image pull previously passed its step and the deploy carried on.

🤖 Generated with Claude Code

Jack-Edwards and others added 2 commits July 31, 2026 22:15
appleboy/scp-action and appleboy/ssh-action are composite actions that
download a drone-scp or drone-ssh binary from GitHub releases at run time,
with no checksum verification. Pinning those actions to a commit SHA does
not cover the code that actually runs, and this is the workflow that holds
the production SSH key.

The OpenSSH client on the hosted runners covers everything this workflow
needs: three single-file copies and five short remote commands. A host
alias in ~/.ssh/config keeps the per-step configuration out of the way.

Neither action was verifying the app server host key, since no fingerprint
was ever configured. Host key checking is now strict and reads from a
known_hosts file, so deploying requires a new APPSERVER_SSH_KNOWN_HOSTS
secret. The workflow fails early with instructions when it is missing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deploying now requires an APPSERVER_SSH_KNOWN_HOSTS secret per environment.
Capturing the host key belongs with the rest of the one-time server setup,
next to the SSH user it authenticates against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Jack-Edwards
Jack-Edwards force-pushed the chore/native-ssh-deploy branch from dfc30b7 to 06ce0b1 Compare August 1, 2026 03:16
Jack-Edwards and others added 2 commits July 31, 2026 22:42
The previous instructions checked a single Ed25519 fingerprint against the
server, but ssh-keyscan captures every key type the server offers unless it is
told otherwise, so the remaining keys went into the secret unverified. Not
every server has an Ed25519 key to begin with.

Reading fingerprints off the server was also circular. Reaching it means
connecting over ssh, at which point the workstation already holds the key that
step was meant to confirm.

known_hosts is indexed by host and port, and ssh writes a bare hostname only
for port 22. An entry copied from a workstation that connects on another port
is never consulted, and the deploy fails under strict host key checking as
though no key had been recorded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
appleboy/ssh-action applied a ten minute command_timeout that native ssh has
no equivalent for, so a wedged image pull or a migration blocked on a lock
would otherwise run until the six hour job default expires.

BatchMode stops ssh from falling back to password and keyboard-interactive
authentication when the key is rejected. Those attempts read an empty
passphrase from a closed stdin and fail three times over before the step
gives up, reporting a permission problem rather than the key problem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant