diff --git a/README.md b/README.md index 9758f4e..eeab8cb 100644 --- a/README.md +++ b/README.md @@ -49,20 +49,31 @@ path traversal vulnerabilities. ## Requirements * Python 3.10+ -* Dependencies: `httpx[socks]`, `rich`, `rich-argparse` +* Git +* Dependencies: `httpx[socks]`, `rich`, `rich-argparse`, and + `tomli` on Python 3.10 ## Installation ```bash git clone https://github.com/lightos/Panoptic.git cd Panoptic -pip install -e . +python3 -m venv .venv +source .venv/bin/activate +python -m pip install -e . +panoptic --version ``` +On Windows Command Prompt, activate with `.venv\Scripts\activate.bat`; +in PowerShell, use `.venv\Scripts\Activate.ps1`. The editable install keeps +Panoptic connected to this checkout for `--update`, so keep the directory +in place. Do not run `pip install panoptic`: that PyPI name belongs to an +unrelated project. + For development: ```bash -pip install -e ".[dev]" +python -m pip install -e ".[dev]" ``` ## Usage @@ -343,10 +354,16 @@ panoptic --update # fast-forward update from the official GitHub repo `--update` only works from a git checkout whose `origin` remote uses HTTPS or SSH and matches the official upstream (verified before pulling, to resist insecure or tampered remote configuration). It fast-forwards -the checked-out `main` branch from the explicit upstream `main` ref; for -pip installs it prints the correct -`pip install -U` command instead. When run from a checkout, the banner -also shows the current short git revision. +the checked-out `main` branch from the explicit upstream `main` ref. +Non-checkout installations can be refreshed safely from the official +GitHub archive: + +```bash +python -m pip install --upgrade https://github.com/lightos/Panoptic/archive/refs/heads/main.zip +``` + +When run from a checkout, the banner also shows the current short git +revision. ## Exit Codes diff --git a/panoptic/update.py b/panoptic/update.py index 5bdae18..6f0bc97 100644 --- a/panoptic/update.py +++ b/panoptic/update.py @@ -14,6 +14,8 @@ GIT_REPOSITORY_URL = "https://github.com/lightos/Panoptic.git" GIT_UPSTREAM_BRANCH = "main" GIT_UPSTREAM_REF = f"refs/heads/{GIT_UPSTREAM_BRANCH}" +PIP_UPDATE_URL = f"https://github.com/lightos/Panoptic/archive/refs/heads/{GIT_UPSTREAM_BRANCH}.zip" +PIP_UPDATE_COMMAND = f"python -m pip install --upgrade {PIP_UPDATE_URL}" _PACKAGE_DIR = os.path.dirname(os.path.abspath(__file__)) _PROJECT_ROOT = os.path.dirname(_PACKAGE_DIR) @@ -51,7 +53,7 @@ def do_update() -> int: if not os.path.exists(git_dir): print("[i] Panoptic appears to be installed via pip.") - print("[i] To update, run: pip install -U panoptic") + print(f"[i] To update, run: {PIP_UPDATE_COMMAND}") return 0 print("[i] Checking for updates...") @@ -67,7 +69,7 @@ def do_update() -> int: ) except FileNotFoundError: print("[!] 'git' is not installed or not in PATH.") - print("[i] Please install git or update via: pip install -U panoptic") + print(f"[i] Please install git or update via: {PIP_UPDATE_COMMAND}") return 2 except subprocess.TimeoutExpired: print("[!] Timed out while checking the git remote.") diff --git a/tests/test_update.py b/tests/test_update.py index 4e64663..22cc19a 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -44,7 +44,10 @@ def test_git_checkout_rejects_non_main_branch(self, mock_exists: Any, mock_run: def test_pip_installed_prints_guidance(self, mock_exists: Any, capsys: pytest.CaptureFixture[str]) -> None: assert do_update() == 0 captured = capsys.readouterr() - assert "pip" in captured.out.lower() + assert ( + "python -m pip install --upgrade https://github.com/lightos/Panoptic/archive/refs/heads/main.zip" + ) in captured.out + assert "pip install -U panoptic" not in captured.out def test_ssh_and_https_remotes_are_equivalent(self) -> None: assert _normalise_git_url("git@github.com:lightos/Panoptic.git") == _normalise_git_url(