133 lines
4.6 KiBLFS
Python
133 lines
4.6 KiBLFS
Python
from __future__ import annotations
|
|
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
from skillsbench_agentbeats import ghcr_preflight as ghcr_preflight_module
|
|
from skillsbench_agentbeats.ghcr_preflight import (
|
|
active_account_scopes,
|
|
ensure_ghcr_package_scopes,
|
|
missing_ghcr_package_scopes,
|
|
run_gh_token_scope_status,
|
|
)
|
|
|
|
GH_AUTH_STATUS = """github.com
|
|
- Logged in to github.com account benchflow-bot (keyring)
|
|
- Active account: true
|
|
- Git operations protocol: https
|
|
- Token: gho_************************************
|
|
- Token scopes: 'gist', 'read:org', 'repo', 'workflow', 'read:packages', 'write:packages'
|
|
|
|
- Logged in to github.com account FayeZC (keyring)
|
|
- Active account: false
|
|
- Git operations protocol: https
|
|
- Token: gho_************************************
|
|
- Token scopes: 'gist', 'read:org', 'repo', 'workflow'
|
|
"""
|
|
|
|
|
|
def test_active_account_scopes_parses_only_active_account() -> None:
|
|
scopes = active_account_scopes(GH_AUTH_STATUS)
|
|
|
|
assert scopes == {"gist", "read:org", "repo", "workflow", "read:packages", "write:packages"}
|
|
|
|
|
|
def test_missing_ghcr_package_scopes_detects_required_package_scopes() -> None:
|
|
missing = missing_ghcr_package_scopes({"gist", "read:org", "repo", "workflow"})
|
|
|
|
assert missing == {"read:packages", "write:packages"}
|
|
|
|
|
|
def test_ensure_ghcr_package_scopes_accepts_complete_scope_set() -> None:
|
|
assert "write:packages" in ensure_ghcr_package_scopes(GH_AUTH_STATUS)
|
|
|
|
|
|
def test_ensure_ghcr_package_scopes_rejects_missing_package_scopes() -> None:
|
|
output = GH_AUTH_STATUS.replace(", 'read:packages', 'write:packages'", "")
|
|
|
|
with pytest.raises(ValueError, match="gh auth refresh"):
|
|
ensure_ghcr_package_scopes(output)
|
|
|
|
|
|
def test_active_account_scopes_rejects_missing_active_account() -> None:
|
|
with pytest.raises(ValueError, match="active GitHub account"):
|
|
active_account_scopes("github.com\n - no active account")
|
|
|
|
|
|
def test_run_gh_token_scope_status_reads_pat_from_environment(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
seen: dict[str, object] = {}
|
|
|
|
def fake_run(
|
|
cmd: list[str],
|
|
*,
|
|
check: bool,
|
|
capture_output: bool,
|
|
text: bool,
|
|
env: dict[str, str] | None = None,
|
|
) -> subprocess.CompletedProcess[str]:
|
|
seen["cmd"] = cmd
|
|
seen["env"] = env
|
|
return subprocess.CompletedProcess(cmd, 0, stdout="x-oauth-scopes: repo, read:packages, write:packages\n", stderr="")
|
|
|
|
monkeypatch.setenv("GH_TOKEN", "github_pat_secret_value")
|
|
monkeypatch.setattr(ghcr_preflight_module.subprocess, "run", fake_run)
|
|
|
|
assert run_gh_token_scope_status() == {"repo", "read:packages", "write:packages"}
|
|
assert seen["cmd"] == ["gh", "api", "-i", "user"]
|
|
assert seen["env"]["GH_TOKEN"] == "github_pat_secret_value"
|
|
|
|
|
|
def test_run_gh_token_scope_status_prefers_gh_token_over_github_token(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
seen_env: dict[str, str] = {}
|
|
|
|
def fake_run(
|
|
cmd: list[str],
|
|
*,
|
|
check: bool,
|
|
capture_output: bool,
|
|
text: bool,
|
|
env: dict[str, str] | None = None,
|
|
) -> subprocess.CompletedProcess[str]:
|
|
assert env is not None
|
|
seen_env.update(env)
|
|
return subprocess.CompletedProcess(cmd, 0, stdout="x-oauth-scopes: read:packages, write:packages\n", stderr="")
|
|
|
|
monkeypatch.setenv("GH_TOKEN", "gh_token_secret")
|
|
monkeypatch.setenv("GITHUB_TOKEN", "github_token_secret")
|
|
monkeypatch.setattr(ghcr_preflight_module.subprocess, "run", fake_run)
|
|
|
|
run_gh_token_scope_status()
|
|
|
|
assert seen_env["GH_TOKEN"] == "gh_token_secret"
|
|
assert "GITHUB_TOKEN" not in seen_env
|
|
|
|
|
|
def test_run_gh_token_scope_status_rejects_missing_env_token(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.delenv("GH_TOKEN", raising=False)
|
|
monkeypatch.delenv("GITHUB_TOKEN", raising=False)
|
|
|
|
with pytest.raises(ValueError, match="GH_TOKEN"):
|
|
run_gh_token_scope_status()
|
|
|
|
|
|
def test_run_gh_token_scope_status_redacts_token_on_error(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
def fake_run(
|
|
cmd: list[str],
|
|
*,
|
|
check: bool,
|
|
capture_output: bool,
|
|
text: bool,
|
|
env: dict[str, str] | None = None,
|
|
) -> subprocess.CompletedProcess[str]:
|
|
return subprocess.CompletedProcess(cmd, 1, stdout="", stderr="bad github_pat_secret_value")
|
|
|
|
monkeypatch.setenv("GH_TOKEN", "github_pat_secret_value")
|
|
monkeypatch.setattr(ghcr_preflight_module.subprocess, "run", fake_run)
|
|
|
|
with pytest.raises(RuntimeError) as exc_info:
|
|
run_gh_token_scope_status()
|
|
|
|
assert "github_pat_secret_value" not in str(exc_info.value)
|
|
assert "[REDACTED_TOKEN]" in str(exc_info.value)
|