mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-04-29 20:39:29 +00:00
feat: ARM tarball builds + arch-aware download (#2248)
* feat: ARM tarball builds + arch-aware download - Add ARM64 matrix entries for native binary agents (zeroclaw, opencode, hermes, claude) in agent-tarballs.yml workflow - Update agent-tarball.ts to detect remote VM arch via uname -m and download the correct tarball (x86_64 or arm64) - Change release strategy to support multiple arch assets per tag - Document ARM build requirements in discovery.md for future agents - Bump CLI version to 0.15.2 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: use sudo for tarball extraction on non-root SSH clouds On AWS Lightsail, SSH connects as 'ubuntu' (not root), but tarballs extract to /root/. Without sudo, tar fails with "Permission denied". Conditionally use sudo when not running as root (id -u != 0). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5541295012
commit
141254c4e1
4 changed files with 70 additions and 22 deletions
|
|
@ -54,30 +54,48 @@ export async function tryTarballInstall(
|
|||
return false;
|
||||
}
|
||||
|
||||
// Find the .tar.gz asset
|
||||
const asset = parsed.output.assets.find((a) => a.name.endsWith(".tar.gz"));
|
||||
if (!asset) {
|
||||
// Find both arch-specific .tar.gz assets and let the remote VM pick the right one.
|
||||
// We try x86_64 first (most common), and include arm64 fallback in the remote script.
|
||||
const x86Asset = parsed.output.assets.find((a) => a.name.includes("-x86_64-") && a.name.endsWith(".tar.gz"));
|
||||
const armAsset = parsed.output.assets.find((a) => a.name.includes("-arm64-") && a.name.endsWith(".tar.gz"));
|
||||
|
||||
if (!x86Asset && !armAsset) {
|
||||
logWarn("No tarball asset found in release");
|
||||
return false;
|
||||
}
|
||||
|
||||
const url = asset.browser_download_url;
|
||||
// Build arch-aware download: remote VM detects its own arch and picks the right URL
|
||||
const x86Url = x86Asset?.browser_download_url || "";
|
||||
const armUrl = armAsset?.browser_download_url || "";
|
||||
const url = x86Url || armUrl;
|
||||
|
||||
// SECURITY: Validate URL matches expected GitHub releases pattern.
|
||||
// SECURITY: Validate URLs match expected GitHub releases pattern.
|
||||
// Prevents shell injection via crafted API responses.
|
||||
if (!/^https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/releases\/download\/[^\s'"`;|&$()]+$/.test(url)) {
|
||||
const urlPattern = /^https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/releases\/download\/[^\s'"`;|&$()]+$/;
|
||||
if ((x86Url && !urlPattern.test(x86Url)) || (armUrl && !urlPattern.test(armUrl))) {
|
||||
logWarn("Tarball URL failed safety validation");
|
||||
return false;
|
||||
}
|
||||
|
||||
logStep("Downloading pre-built agent tarball...");
|
||||
|
||||
// Build arch-aware download command: remote VM picks the right URL based on uname -m
|
||||
// Use sudo for tar extraction — on clouds like AWS Lightsail, SSH user is 'ubuntu' (non-root)
|
||||
// but tarballs extract to /root/. The ubuntu user has passwordless sudo.
|
||||
const sudo = '$([ "$(id -u)" != "0" ] && echo sudo || echo "")';
|
||||
let downloadCmd: string;
|
||||
if (x86Url && armUrl) {
|
||||
downloadCmd =
|
||||
"_arch=$(uname -m); " +
|
||||
`if [ "$_arch" = "aarch64" ] || [ "$_arch" = "arm64" ]; then ` +
|
||||
`_url='${armUrl}'; else _url='${x86Url}'; fi; ` +
|
||||
`curl -fsSL --connect-timeout 10 --max-time 120 "$_url" | ${sudo} tar xz -C / && ${sudo} test -f /root/.spawn-tarball`;
|
||||
} else {
|
||||
downloadCmd = `curl -fsSL --connect-timeout 10 --max-time 120 '${url}' | ${sudo} tar xz -C / && ${sudo} test -f /root/.spawn-tarball`;
|
||||
}
|
||||
|
||||
// Download and extract on the remote VM
|
||||
// --connect-timeout 10s, --max-time 120s, -L to follow redirects (GitHub releases redirect)
|
||||
await runner.runServer(
|
||||
`curl -fsSL --connect-timeout 10 --max-time 120 '${url}' | tar xz -C / && [ -f /root/.spawn-tarball ]`,
|
||||
150, // 2.5 min total timeout for the SSH command
|
||||
);
|
||||
await runner.runServer(downloadCmd, 150);
|
||||
|
||||
logInfo("Agent installed from pre-built tarball");
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue