-
Notifications
You must be signed in to change notification settings - Fork 4.1k
chore: move installation scripts from docs repo to here #1951
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,247 @@ | ||||||||||
| import argparse | ||||||||||
| import os | ||||||||||
| import platform | ||||||||||
| import signal | ||||||||||
| import shutil | ||||||||||
| import subprocess | ||||||||||
| import tarfile | ||||||||||
| import urllib.request | ||||||||||
| from pathlib import Path | ||||||||||
|
|
||||||||||
|
|
||||||||||
| DEFAULT_ACTION = "install" | ||||||||||
| START_PICOCLAW = True | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def parse_args() -> argparse.Namespace: | ||||||||||
| parser = argparse.ArgumentParser(description="Install or uninstall picoclaw.") | ||||||||||
| parser.add_argument( | ||||||||||
| "--action", | ||||||||||
| choices=["install", "uninstall"], | ||||||||||
| default=DEFAULT_ACTION, | ||||||||||
| help=f"Action to perform, defaults to '{DEFAULT_ACTION}'.", | ||||||||||
| ) | ||||||||||
| return parser.parse_args() | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def detect_arch() -> str: | ||||||||||
| machine = platform.machine().lower() | ||||||||||
|
|
||||||||||
| if machine in {"aarch64", "arm64"}: | ||||||||||
| return "arm64" | ||||||||||
| if machine in {"riscv64"}: | ||||||||||
| return "riscv64" | ||||||||||
|
|
||||||||||
| return f"unknown ({machine})" | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def ensure_picoclaw_dir() -> Path: | ||||||||||
| target_dir = Path("/root/picoclaw") | ||||||||||
| target_dir.mkdir(parents=True, exist_ok=True) | ||||||||||
| return target_dir | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def get_download_url(arch: str) -> str: | ||||||||||
| if arch == "riscv64": | ||||||||||
| return "https://picoclaw-downloads.tos-cn-beijing.volces.com/latest/picoclaw_Linux_riscv64.tar.gz" | ||||||||||
| if arch == "arm64": | ||||||||||
| return "https://picoclaw-downloads.tos-cn-beijing.volces.com/latest/picoclaw_aarch64.deb" | ||||||||||
|
|
||||||||||
| raise ValueError(f"Unsupported architecture: {arch}") | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def download_package(url: str, target_dir: Path) -> Path: | ||||||||||
| file_name = Path(url).name | ||||||||||
| target_path = target_dir / file_name | ||||||||||
| urllib.request.urlretrieve(url, target_path) | ||||||||||
| return target_path | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def install_arm64(deb_file: Path) -> None: | ||||||||||
| subprocess.run(["dpkg", "-i", str(deb_file)], check=True) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def find_file_recursive(root: Path, file_name: str) -> Path: | ||||||||||
| matches = list(root.rglob(file_name)) | ||||||||||
| if not matches: | ||||||||||
| raise FileNotFoundError(f"Required file not found: {file_name}") | ||||||||||
| return matches[0] | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def install_riscv64(tar_file: Path, work_dir: Path) -> None: | ||||||||||
|
||||||||||
| def install_riscv64(tar_file: Path, work_dir: Path) -> None: | |
| def install_riscv64(tar_file: Path, work_dir: Path) -> None: | |
| # Ensure the provided work directory exists so it can be used as a staging area if needed. | |
| work_dir.mkdir(parents=True, exist_ok=True) |
Copilot
AI
Mar 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tar.extractall() is used on a downloaded archive without validating member paths. A malicious tarball can write files outside /opt/picoclaw via ../ or absolute paths (path traversal). Use a safe extraction routine that validates each member’s resolved path stays within the destination directory before extracting.
Copilot
AI
Mar 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cleanup_dir() deletes the entire /root/picoclaw directory. Since ensure_picoclaw_dir() uses exist_ok=True, this directory may pre-exist and contain unrelated user data; running the installer would then delete it. Use a unique temporary download directory (e.g., under /tmp), or only delete the specific downloaded file(s) created by this run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This installer writes into
/root,/opt, and/usr/binbut doesn't check for root privileges up front. When run without sufficient permissions it will fail mid-way with a less clear exception (e.g.,PermissionError). Consider asserting effective UID==0 early (or documenting that it must be run as root) and exiting with a clear message.