[Overview] Establish a single, git-based deployment pipeline for DrusaBoT so the VPS no longer drifts from the local repo.
The repository already contains scripts/update.sh, a complete, battle-tested bash deploy script that: fetches origin, diffs local vs remote, stops services, pulls, reinstalls deps, conditionally rebuilds the frontend, and restarts services. It is git-native. However, historical deploys bypassed it entirely via Paramiko file uploads (vps_deploy.py, vps_diag.py, manual sftp_put.py). That bypass produced the documented "VPS runs an older commit; local repo has many untracked patch files" drift in project memory.
Context: the working tree on master is one commit ahead pattern; VPS creds (root@152.239.122.211, password clear-text in D:\Vault\Projects\DiscBot\vps-scripts\vps_deploy.py) are real and verified by earlier sessions. There is an active remote https://github.com/devilforcex/discbot.git. The fix is not "write a new deploy tool" — it is to make scripts/update.sh the only deploy path, delete/retire the plaintext-credential paramiko scripts, and harden the credential storage so secrets never live in a script again.
[Types]
No application type-system changes are required; this is infrastructure. The only "type" is the credential model in .env:
VPS_HOST(str) — VPS IP/hostname, e.g.152.239.122.211.VPS_SSH_USER(str) — defaultroot.VPS_KEY_PATH(str) — path to the SSH private key used for git pull auth and deploy SSH (recommended, replaces password auth).- No password field is added — passwords move out of scripts entirely.
Config precedence follows the existing config.py pydantic-settings pattern: env vars in .env (gitignored), documented in .env.example.
[Files] This change touches deploy tooling and docs, not bot/dashboard application code.
- New files:
scripts/deploy.sh— thin local wrapper that: (1) pushes the currentmasterto origin, (2) invokes the VPSscripts/update.sh --branch masterover SSH using the VPS SSH key from envVPS_KEY_PATH. Keeps the workflow "local push → VPS pulls" symmetrical with git semantics.
- Modified files:
.env.example— add the threeVPS_*documented vars from [Types].docs/HOSTINGER_VPS_INSTALL.md— replace the "smart manual update" section with a new "Git-based deploy" section documentingscripts/deploy.sh, and the one-time setup: add a deploy-only SSH key on the VPS, configureVPS_KEY_PATH, and make the local repo push to origin.AGENTS.md— add a "Deployment" section stating the canonical path isscripts/deploy.sh; explicitly forbid raw file uploads / sftp_put as a deploy mechanism.MEMORY.md/TODO.md(repo stubs) — mark the "Decide VPS sync strategy" TODO as resolved with this plan.
- Deleted files:
D:\Vault\Projects\DiscBot\vps-scripts\vps_deploy.pyD:\Vault\Projects\DiscBot\vps-scripts\vps_deploy2.pyD:\Vault\Projects\DiscBot\vps-scripts\vps_diag.py- (These contain the plaintext root password; deleting them is the security hardening part. They are already gitignored per prior cleanup, so deletion is safe from the repo.)
- Configuration updates:
.env(local, gitignored) — addVPS_HOST,VPS_SSH_USER,VPS_KEY_PATH.- VPS side (run via SSH once): generate a deploy-only SSH keypair; add the public key to the VPS
~/.ssh/authorized_keys; ensure thediscbotuser (notroot) owns the deploy path per least-privilege.
[Functions] No Python application functions change. Two bash scripts carry the logic.
- New function (script):
scripts/deploy.sh- Name:
deploy.sh(executable bash, run from project root on the local machine). - Purpose: coalesce push + remote pull into one reproducible command.
- Logic:
set -e; readVPS_HOST/VPS_SSH_USER/VPS_KEY_PATHfrom env (or.envvia a small parser);git push origin master; thenssh -i "$VPS_KEY_PATH" "$VPS_SSH_USER@$VPS_HOST" "cd /home/discbot/discbot && bash scripts/update.sh --branch master". Surf the exit code so CI/terminal can detect failure.
- Name:
- Modified function behavior (script):
scripts/update.sh- Already correct. No code change required. It stays the canonical VPS-side updater;
deploy.shsimply calls it. Optionally add a guard at the top: abort ifgit status --porcelainshows uncommitted changes onmaster, to keep deploys deterministic.
- Already correct. No code change required. It stays the canonical VPS-side updater;
- Removed functions: the
phasedispatch insidevps_deploy.py/vps_diag.py(check/update/manual/logs/smoke/verify) — retired with the script deletion. Migration strategy: themanualandupdatephases map 1:1 tobash scripts/update.sh --branch master; thecheck/smoke/logsphases are trivially reproduced via the SSH command indeploy.sh(journalctl/systemctl). Document this mapping in the VPS install doc.
[Classes]
No class changes. The only structural units are the bash scripts above; the Python VPS helper classes (Paramiko connect()/run()) are deleted with their scripts. No replacement class is introduced — SSH via native ssh client replaces Paramiko, removing a dependency and the plaintext-password vector.
[Dependencies] No new runtime packages.
- Python: removes
paramikousage from active tooling (it stays only in the legacy sshvenv, unused). Norequirements.txtchange. - System: requires
ssh/giton the local machine (already present per detected CLI tools) andgit/bashon the VPS (present). A deploy-only SSH key is the new secure auth primitive, replacing password auth.
[Testing] Validation is operational, not unit-test.
- Local dry-run of
deploy.shwith--no-restartsemantics honored on the remote viaupdate.shflags. - One live deploy cycle against the VPS: run
deploy.sh; confirmscripts/update.shreports "Already up to date" on a second run. - Post-deploy smoke:
ssh ... "systemctl is-active discbot discbot-dashboard lavalink"allactive;curl -s http://localhost:18080/api/healthand:12333/versionrespond. - Security check: grep the workspace and
D:\Vault\Projects\DiscBot\for the root password string → zero matches after deletion.
[Implementation Order] Single coherent sequence to avoid a half-migrated state.
- Add
VPS_HOST,VPS_SSH_USER,VPS_KEY_PATHto.env.exampleand to local.env. - Write
scripts/deploy.shwith the push + remote-update logic and set executable bit. - Hardening prep on VPS: create deploy-only SSH key, install public key into authorized_keys, scope to
discbotuser. - Retire and delete the three plaintext-credential VPS scripts from
D:\Vault\Projects\DiscBot\vps-scripts\. - Update
docs/HOSTINGER_VPS_INSTALL.md: replace file-upload guidance with git-based deploy, document the old-phase →update.shmapping. - Update
AGENTS.mddeployment section + resolve the VPS-sync TODO in repo memory stubs. - Run
deploy.shend-to-end; verify services + smoke endpoints; re-run to confirm idempotent "already up to date". - Grep to confirm the plaintext password is gone from workspace + Vault scripts; rotate the VPS root password to close the exposed-credential gap regardless.