diff --git a/server/internal/api/handlers.go b/server/internal/api/handlers.go index 8dcc526..beda91b 100644 --- a/server/internal/api/handlers.go +++ b/server/internal/api/handlers.go @@ -13,6 +13,7 @@ import ( func RegisterRoutes(r *gin.Engine) { r.GET("/install", handleInstallScript) + r.GET("/update", handleUpdateScript) // Auth endpoints (no session required) r.GET("/auth/login", auth.HandleLogin) @@ -236,6 +237,62 @@ func revokeAssignment(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"revoked": true}) } +func handleUpdateScript(c *gin.Context) { + giteaHost := os.Getenv("GITEA_HOST") + if giteaHost == "" { + giteaHost = "gitea.example.com" + } + + script := fmt.Sprintf(`#!/usr/bin/env bash +set -euo pipefail + +GITEA_HOST="%s" + +ARCH=$(uname -m) +case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; +esac + +# Get latest agent release tag +LATEST=$(curl -fsSL "https://${GITEA_HOST}/api/v1/repos/mrhid6/keymanager/releases?limit=10" \ + | grep -o '"tag_name":"agent/v[^"]*"' | head -1 | sed 's/"tag_name":"//;s/"//') + +if [ -z "$LATEST" ]; then + echo "Could not determine latest agent version" >&2 + exit 1 +fi + +VERSION="${LATEST#agent/}" +LATEST_ENCODED="${LATEST/\//%%2F}" +BINARY_URL="https://${GITEA_HOST}/mrhid6/keymanager/releases/download/${LATEST_ENCODED}/keymanager-agent-linux-${ARCH}" +CHECKSUM_URL="https://${GITEA_HOST}/mrhid6/keymanager/releases/download/${LATEST_ENCODED}/checksums.txt" + +echo "Updating keymanager-agent to ${VERSION} (${ARCH})..." + +curl -fsSL -o /tmp/keymanager-agent "${BINARY_URL}" +curl -fsSL -o /tmp/checksums.txt "${CHECKSUM_URL}" + +cd /tmp +EXPECTED=$(grep "keymanager-agent-linux-${ARCH}" checksums.txt | awk '{print $1}') +ACTUAL=$(sha256sum keymanager-agent | awk '{print $1}') +if [ "$EXPECTED" != "$ACTUAL" ]; then + echo "Checksum mismatch!" >&2 + exit 1 +fi + +systemctl stop keymanager-agent || true +install -m 0755 /tmp/keymanager-agent /usr/local/bin/keymanager-agent +systemctl start keymanager-agent + +echo "keymanager-agent updated to ${VERSION} and restarted." +`, giteaHost) + + c.Header("Content-Type", "text/x-shellscript") + c.String(http.StatusOK, script) +} + func handleInstallScript(c *gin.Context) { serverID := c.Query("server_id") token := c.Query("token") diff --git a/web/app/servers/[id]/page.tsx b/web/app/servers/[id]/page.tsx index 8bfa251..df986a8 100644 --- a/web/app/servers/[id]/page.tsx +++ b/web/app/servers/[id]/page.tsx @@ -26,6 +26,7 @@ export default function ServerDetailPage() { const queryClient = useQueryClient(); const serverId = params.id as string; const [confirmDelete, setConfirmDelete] = useState(false); + const [copiedUpdate, setCopiedUpdate] = useState(false); const { data: server, isLoading, error } = useQuery({ queryKey: ["servers", serverId], @@ -115,6 +116,33 @@ export default function ServerDetailPage() { +
+ Run this command on the server as root to update the agent to the latest version:
+
+ ${" "} + {api.getUpdateCommand()} ++ +