mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-03 04:49:26 +00:00
Registry metadata (version, publisher, checksum) moves to a distinct fact strip. Decline button renamed to say the run continues; reason capped to one sentence.
163 lines
6.2 KiB
Python
163 lines
6.2 KiB
Python
"""Tool resolution + pinned managed installs (OPE-84).
|
|
|
|
The bug this guards against: a Finder-launched app gets launchd's minimal PATH, so every
|
|
brew/nvm-installed scanner is invisible and a security review silently loses checks.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import os
|
|
import stat
|
|
|
|
import pytest
|
|
|
|
from coworker import toolchain
|
|
|
|
|
|
def _make_exe(path, body: str = "#!/bin/sh\necho hi\n"):
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(body)
|
|
path.chmod(path.stat().st_mode | stat.S_IXUSR)
|
|
return path
|
|
|
|
|
|
def test_resolve_prefers_path(tmp_path, monkeypatch):
|
|
on_path = _make_exe(tmp_path / "bin" / "semgrep")
|
|
monkeypatch.setenv("PATH", str(tmp_path / "bin"))
|
|
assert toolchain.resolve("semgrep") == str(on_path.resolve())
|
|
|
|
|
|
def test_resolve_finds_tools_launchd_path_cannot_see(tmp_path, monkeypatch):
|
|
"""The actual production failure: PATH is bare, the tool is in a brew-style dir."""
|
|
brew = tmp_path / "opt" / "homebrew" / "bin"
|
|
gitleaks = _make_exe(brew / "gitleaks")
|
|
monkeypatch.setenv("PATH", "/usr/bin:/bin") # what a Finder launch really gets
|
|
monkeypatch.setattr(toolchain, "_KNOWN_DIRS", (str(brew),))
|
|
assert toolchain.resolve("gitleaks") == str(gitleaks.resolve())
|
|
|
|
|
|
def test_resolve_returns_absolute_path(tmp_path, monkeypatch):
|
|
"""Callers must be able to invoke without depending on PATH at all."""
|
|
_make_exe(tmp_path / "bin" / "trivy")
|
|
monkeypatch.setenv("PATH", str(tmp_path / "bin"))
|
|
assert os.path.isabs(toolchain.resolve("trivy") or "")
|
|
|
|
|
|
def test_missing_reports_only_absent_tools(tmp_path, monkeypatch):
|
|
_make_exe(tmp_path / "bin" / "gitleaks")
|
|
monkeypatch.setenv("PATH", str(tmp_path / "bin"))
|
|
monkeypatch.setattr(toolchain, "_KNOWN_DIRS", ())
|
|
monkeypatch.setattr(toolchain, "MANAGED", {})
|
|
assert toolchain.missing(["gitleaks", "semgrep"]) == ["semgrep"]
|
|
|
|
|
|
def test_unknown_tool_resolves_to_none(monkeypatch):
|
|
monkeypatch.setenv("PATH", "")
|
|
monkeypatch.setattr(toolchain, "_KNOWN_DIRS", ())
|
|
assert toolchain.resolve("definitely-not-a-real-tool") is None
|
|
|
|
|
|
def test_registry_entries_are_pinned_and_digested():
|
|
"""Every managed download must carry a version and a full SHA-256 — an unpinned
|
|
entry would mean 'download whatever is current', which is the thing we refuse."""
|
|
assert toolchain.MANAGED, "registry should not be empty"
|
|
for name, tool in toolchain.MANAGED.items():
|
|
assert tool.version and tool.version[0].isdigit(), name
|
|
assert tool.summary, f"{name} needs a summary for the consent card"
|
|
for key, dl in tool.downloads.items():
|
|
assert len(dl.sha256) == 64, f"{name}/{key} digest looks wrong"
|
|
assert int(dl.sha256, 16) >= 0 # hex
|
|
assert tool.version in dl.url, f"{name}/{key} url must pin the version"
|
|
assert dl.url.startswith("https://"), f"{name}/{key} must be https"
|
|
|
|
|
|
def test_trivy_is_pinned_for_every_platform_we_ship():
|
|
"""tfsec is deprecated upstream (folded into trivy); `trivy config` is the IaC scanner
|
|
the cloud-posture bundle drives, so its pin must exist wherever the app runs."""
|
|
tool = toolchain.MANAGED["trivy"]
|
|
assert set(tool.downloads) >= {"darwin_arm64", "darwin_amd64", "linux_amd64"}
|
|
for dl in tool.downloads.values():
|
|
assert dl.member == "trivy" # release assets are tarballs, not bare binaries
|
|
assert "tfsec" not in toolchain.MANAGED
|
|
|
|
|
|
def test_describe_surfaces_what_the_user_is_approving(monkeypatch):
|
|
monkeypatch.setattr(toolchain, "_platform_key", lambda: "darwin_arm64")
|
|
info = toolchain.describe("gitleaks")
|
|
assert info and info["version"] and info["sha256"] and info["url"]
|
|
assert "secret" in info["summary"].lower()
|
|
assert info["source"] == "github.com/gitleaks" # publisher, human-readable
|
|
|
|
|
|
def test_install_refuses_a_tampered_download(tmp_path, monkeypatch):
|
|
"""The whole point of pinning: a mismatched artifact never lands on disk."""
|
|
monkeypatch.setattr(toolchain, "managed_dir", lambda: tmp_path / "tools")
|
|
monkeypatch.setattr(toolchain, "_platform_key", lambda: "darwin_arm64")
|
|
|
|
class FakeResp:
|
|
def read(self):
|
|
return b"malicious payload"
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *a):
|
|
return False
|
|
|
|
monkeypatch.setattr(toolchain.urllib.request, "urlopen", lambda *a, **k: FakeResp())
|
|
|
|
with pytest.raises(ValueError, match="checksum mismatch"):
|
|
toolchain.install("gitleaks")
|
|
assert not (tmp_path / "tools").exists() or not list(
|
|
(tmp_path / "tools").rglob("gitleaks")
|
|
)
|
|
|
|
|
|
def test_install_writes_a_verified_binary(tmp_path, monkeypatch):
|
|
payload = b"#!/bin/sh\necho scanned\n"
|
|
digest = hashlib.sha256(payload).hexdigest()
|
|
|
|
monkeypatch.setattr(toolchain, "managed_dir", lambda: tmp_path / "tools")
|
|
monkeypatch.setattr(toolchain, "_platform_key", lambda: "darwin_arm64")
|
|
monkeypatch.setattr(
|
|
toolchain,
|
|
"MANAGED",
|
|
{
|
|
"osv-scanner": toolchain.ManagedTool(
|
|
name="osv-scanner",
|
|
version="2.5.0",
|
|
summary="checks lockfiles",
|
|
downloads={
|
|
"darwin_arm64": toolchain.Download(
|
|
url="https://example.invalid/osv-scanner", sha256=digest
|
|
)
|
|
},
|
|
)
|
|
},
|
|
)
|
|
|
|
class FakeResp:
|
|
def read(self):
|
|
return payload
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *a):
|
|
return False
|
|
|
|
monkeypatch.setattr(toolchain.urllib.request, "urlopen", lambda *a, **k: FakeResp())
|
|
|
|
path = toolchain.install("osv-scanner")
|
|
assert os.access(path, os.X_OK)
|
|
assert open(path, "rb").read() == payload
|
|
# Installed tools are resolvable afterwards, even with an empty PATH.
|
|
monkeypatch.setenv("PATH", "")
|
|
monkeypatch.setattr(toolchain, "_KNOWN_DIRS", ())
|
|
assert toolchain.resolve("osv-scanner") == path
|
|
# And linked under the stable bin dir, so a shell with that dir on PATH picks the
|
|
# tool up by name the moment the install finishes — no respawn, no full paths.
|
|
linked = toolchain.bin_dir() / "osv-scanner"
|
|
assert linked.exists() and open(linked, "rb").read() == payload
|