Files
hermes-agent/tests/skills/test_github_credential_token.py
Teknium c49fa88b80 refactor(skills): shipped-set slim — 15 to optional, github 6-way merge, pdf absorbs OCR, channel-gated teams pipeline (index −26%) (#98539)
* refactor(skills): shipped-set slim — 15 skills to optional, github six-way merge, pdf absorbs OCR+nano-pdf, channel-gated teams pipeline

Maintainer-directed shipped-skills curation (skills index 1,900 -> ~1,400
tok/call on desktop; every session pays the index, so this is a per-call
diet on all installs):

- optional-skills moves (installable via skills hub, history preserved):
  creative comfyui/ascii-art/excalidraw/pretext/sketch/touchdesigner-mcp;
  ALL of mlops (huggingface-hub, llama-cpp, serving-llms-vllm,
  weights-and-biases, evaluating-llms-harness — subcategory structure
  kept); research-paper-writing (55 supporting files, 17.3K-tok load);
  openhue; blogwatcher (first taught the cronjob monitor-field watch
  pattern + web_extract instead of pre-cron manual workflows)
- DELETED session-librarian (Aug-12 'inspired by Perplexity Computer'
  port, never maintainer-intended; session_search covers discovery)
- github: six skills (auth, issues, pr-workflow, issue-to-pr,
  code-review, repo-management) merged into ONE software-development/
  github skill — routing body + complete per-workflow references;
  benbarclay authorship credited; codebase-inspection rides along;
  discipline pins from test_github_issue_to_pr_skill.py preserved
  against the reference body in the new test_github_skill.py
- pdf absorbs ocr-and-documents + nano-pdf as references/ + scripts
  (extract_pymupdf, extract_marker converted to the argparse house
  standard its contract test enforces)
- NEW session_platforms frontmatter gate (metadata.hermes): hides a
  skill from the index on gateway channels it is not for; fail-open on
  unknown platform; teams-meeting-pipeline gated to [teams, cron]
- blocked-page-recovery: research -> new web category; trigger-first
  description ('Use when a fetch fails: 403/429, paywall, WAF, bot
  wall.') so the model actually reaches for it on blocked fetches
- docs regenerated via generate-skill-docs.py (195 pages); related_skills
  swept repo-wide; tests: 1672 passed (2 openclaw failures pre-existing
  on clean main, Windows-local)

* chore: ignore .skills_prompt_snapshot.json (local index cache, accidentally committed)
2026-08-30 04:53:39 -07:00

102 lines
3.4 KiB
Python

"""Regression tests for Tirith-safe GitHub credential extraction (#22722)."""
from pathlib import Path
import subprocess
import sys
import pytest
REPO_ROOT = Path(__file__).resolve().parents[2]
HELPER = REPO_ROOT / "skills/software-development/github/scripts/git-credential-token.py"
LEGACY_SED = r"sed 's|https://[^:]*:\([^@]*\)@.*|\1|'"
SHIPPED_TREES = (
REPO_ROOT / "skills/software-development/github",
REPO_ROOT / "website/docs/user-guide/skills/bundled/software-development",
REPO_ROOT
/ "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/skills/bundled/software-development",
)
def _extract(path: Path) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(HELPER), str(path)],
capture_output=True,
text=True,
check=False,
)
def _credential_file(tmp_path: Path, value: str) -> Path:
credentials = tmp_path / "credentials"
credentials.write_text(value, encoding="utf-8", newline="")
return credentials
@pytest.mark.parametrize(
("credential", "token"),
[
("https://octocat:password-form-token@github.com\n", "password-form-token"),
("https://oauth-token:x-oauth-basic@github.com\n", "oauth-token"),
("https://ghp_token_only@github.com\n", "ghp_token_only"),
("https://github_pat_token_only@github.com\n", "github_pat_token_only"),
],
)
def test_extracts_supported_git_credential_url_forms(tmp_path, credential, token):
result = _extract(_credential_file(tmp_path, credential))
assert result.returncode == 0
assert result.stdout == f"{token}\n"
assert result.stderr == ""
def test_extracts_password_from_exact_github_https_credential(tmp_path):
credentials = _credential_file(
tmp_path,
"https://ignored:wrong@example.com\n"
"https://octocat:secret%2Ftoken@github.com\n",
)
result = _extract(credentials)
assert result.returncode == 0
assert result.stdout == "secret/token\n"
assert result.stderr == ""
@pytest.mark.parametrize(
"credential",
[
"https://octocat:stolen@github.com.attacker.example\n",
"https://octocat@github.com\n",
"https://%6fctocat@github.com\n",
"https://octocat:token@github.com%2eattacker.example\n",
"https://octocat:token%0D%0AX-Injected%3Ayes@github.com\n",
"https://ghp_token%0Ainjected@github.com\n",
"https://octocat:token%00suffix@github.com\n",
"https://octocat:token%09suffix@github.com\n",
"https://octocat:token%C2%85suffix@github.com\n",
"https://ghp_token%1Fsuffix@github.com\n",
"https://ghp_token%C2%9Fsuffix@github.com\n",
"https://octocat:bad%ZZtoken@github.com\n",
"https://octocat:token@github.com:bogus\n",
"http://octocat:token@github.com\n",
],
)
def test_rejects_ambiguous_lookalike_or_malformed_credentials(tmp_path, credential):
result = _extract(_credential_file(tmp_path, credential))
assert result.returncode == 1
assert result.stdout == ""
assert result.stderr == ""
def test_bundled_github_skills_and_docs_do_not_ship_legacy_sed_url_regex():
offenders = []
for tree in SHIPPED_TREES:
for path in tree.rglob("*"):
if path.suffix in {".md", ".sh", ".py"} and LEGACY_SED in path.read_text(encoding="utf-8"):
offenders.append(str(path.relative_to(REPO_ROOT)))
assert offenders == []