mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-28 18:19:28 +00:00
fix(skills): parse stored GitHub credentials without scanner false positives
Co-authored-by: Syed Annas <28944679+AnnasMazhar@users.noreply.github.com> Co-authored-by: Bryan Neva <13835061+bryanneva@users.noreply.github.com>
This commit is contained in:
parent
4854961d74
commit
9b97dea1e6
24 changed files with 251 additions and 27 deletions
|
|
@ -207,7 +207,7 @@ If git credentials are already configured (via credential.helper store), the tok
|
|||
|
||||
```bash
|
||||
# Read from git credential store
|
||||
grep "github.com" ~/.git-credentials 2>/dev/null | head -1 | sed 's|https://[^:]*:\([^@]*\)@.*|\1|'
|
||||
uv run python3 "${HERMES_HOME:-$HOME/.hermes}/skills/github/github-auth/scripts/git-credential-token.py"
|
||||
```
|
||||
|
||||
### Helper: Detect Auth Method
|
||||
|
|
@ -224,7 +224,7 @@ elif _hermes_env="${HERMES_HOME:-$HOME/.hermes}/.env"; [ -f "$_hermes_env" ] &&
|
|||
export GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" "$_hermes_env" | head -1 | cut -d= -f2 | tr -d '\n\r')
|
||||
echo "AUTH_METHOD=curl"
|
||||
elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then
|
||||
export GITHUB_TOKEN=$(grep "github.com" ~/.git-credentials | head -1 | sed 's|https://[^:]*:\([^@]*\)@.*|\1|')
|
||||
export GITHUB_TOKEN=$(uv run python3 "${HERMES_HOME:-$HOME/.hermes}/skills/github/github-auth/scripts/git-credential-token.py")
|
||||
echo "AUTH_METHOD=curl"
|
||||
else
|
||||
echo "AUTH_METHOD=none"
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ elif _hermes_env="${HERMES_HOME:-$HOME/.hermes}/.env"; [ -f "$_hermes_env" ] &&
|
|||
if [ -n "$GITHUB_TOKEN" ]; then
|
||||
GH_AUTH_METHOD="curl"
|
||||
fi
|
||||
elif [ -f "$HOME/.git-credentials" ] && grep -q "github.com" "$HOME/.git-credentials" 2>/dev/null; then
|
||||
GITHUB_TOKEN=$(grep "github.com" "$HOME/.git-credentials" | head -1 | sed 's|https://[^:]*:\([^@]*\)@.*|\1|')
|
||||
elif [ -f "$HOME/.git-credentials" ]; then
|
||||
GITHUB_TOKEN=$(uv run python3 "${HERMES_HOME:-$HOME/.hermes}/skills/github/github-auth/scripts/git-credential-token.py")
|
||||
if [ -n "$GITHUB_TOKEN" ]; then
|
||||
GH_AUTH_METHOD="curl"
|
||||
fi
|
||||
|
|
|
|||
65
skills/github/github-auth/scripts/git-credential-token.py
Normal file
65
skills/github/github-auth/scripts/git-credential-token.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Print the first unambiguous GitHub token in a git credential-store file."""
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from urllib.parse import unquote, urlsplit
|
||||
|
||||
|
||||
_TOKEN_PREFIXES = ("ghp_", "github_pat_", "gho_", "ghu_", "ghs_", "ghr_")
|
||||
_INVALID_ESCAPE = re.compile(r"%(?![0-9A-Fa-f]{2})")
|
||||
|
||||
|
||||
def _decode(value: str | None) -> str:
|
||||
if value is None or _INVALID_ESCAPE.search(value):
|
||||
return ""
|
||||
decoded = unquote(value)
|
||||
if not decoded or any(ord(char) <= 0x1F or 0x7F <= ord(char) <= 0x9F for char in decoded):
|
||||
return ""
|
||||
return decoded
|
||||
|
||||
|
||||
def _token_from_url(line: str) -> str:
|
||||
if "\r" in line or "\n" in line:
|
||||
return ""
|
||||
try:
|
||||
credential = urlsplit(line)
|
||||
port = credential.port
|
||||
except ValueError:
|
||||
return ""
|
||||
if credential.scheme != "https" or credential.hostname != "github.com" or port not in (None, 443):
|
||||
return ""
|
||||
|
||||
username = _decode(credential.username)
|
||||
password = _decode(credential.password)
|
||||
if not username:
|
||||
return ""
|
||||
if password and password != "x-oauth-basic":
|
||||
return password
|
||||
if password == "x-oauth-basic":
|
||||
return username
|
||||
return username if username.startswith(_TOKEN_PREFIXES) else ""
|
||||
|
||||
|
||||
def main() -> int:
|
||||
path = Path(sys.argv[1]).expanduser() if len(sys.argv) > 1 else Path.home() / ".git-credentials"
|
||||
try:
|
||||
lines = path.read_bytes().split(b"\n")
|
||||
except OSError:
|
||||
return 1
|
||||
|
||||
for raw_line in lines:
|
||||
try:
|
||||
line = raw_line.decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
token = _token_from_url(line)
|
||||
if token:
|
||||
print(token)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue