github-agent 0.23.0__tar.gz → 0.23.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. {github_agent-0.23.0 → github_agent-0.23.2}/PKG-INFO +3 -3
  2. {github_agent-0.23.0 → github_agent-0.23.2}/README.md +1 -1
  3. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/agent_server.py +1 -1
  4. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent.egg-info/PKG-INFO +3 -3
  5. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent.egg-info/SOURCES.txt +1 -0
  6. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent.egg-info/requires.txt +1 -1
  7. {github_agent-0.23.0 → github_agent-0.23.2}/pyproject.toml +2 -2
  8. github_agent-0.23.2/scripts/security_sanitizer.py +160 -0
  9. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_auth_client_edge_cases.py +5 -5
  10. {github_agent-0.23.0 → github_agent-0.23.2}/LICENSE +0 -0
  11. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/__init__.py +0 -0
  12. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/__main__.py +0 -0
  13. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/__init__.py +0 -0
  14. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_base.py +0 -0
  15. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_branches.py +0 -0
  16. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_commits.py +0 -0
  17. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_contents.py +0 -0
  18. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_issues.py +0 -0
  19. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_orgs.py +0 -0
  20. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_pulls.py +0 -0
  21. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_releases.py +0 -0
  22. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_repos.py +0 -0
  23. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_search.py +0 -0
  24. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api/api_client_workflows.py +0 -0
  25. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/api_client.py +0 -0
  26. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/auth.py +0 -0
  27. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/github_input_models.py +0 -0
  28. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/github_response_models.py +0 -0
  29. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/__init__.py +0 -0
  30. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_action.py +0 -0
  31. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_branch.py +0 -0
  32. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_collaborator.py +0 -0
  33. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_commit.py +0 -0
  34. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_content.py +0 -0
  35. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_issue.py +0 -0
  36. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_org.py +0 -0
  37. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_pull.py +0 -0
  38. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_release.py +0 -0
  39. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_repo.py +0 -0
  40. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp/mcp_search.py +0 -0
  41. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp_config.json +0 -0
  42. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent/mcp_server.py +0 -0
  43. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent.egg-info/dependency_links.txt +0 -0
  44. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent.egg-info/entry_points.txt +0 -0
  45. {github_agent-0.23.0 → github_agent-0.23.2}/github_agent.egg-info/top_level.txt +0 -0
  46. {github_agent-0.23.0 → github_agent-0.23.2}/scripts/validate_a2a_agent.py +0 -0
  47. {github_agent-0.23.0 → github_agent-0.23.2}/scripts/verify_api_integration.py +0 -0
  48. {github_agent-0.23.0 → github_agent-0.23.2}/setup.cfg +0 -0
  49. {github_agent-0.23.0 → github_agent-0.23.2}/tests/conftest.py +0 -0
  50. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_api_client_endpoints.py +0 -0
  51. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_api_validation.py +0 -0
  52. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_concept_parity.py +0 -0
  53. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_github_agent_api_brute_force_coverage.py +0 -0
  54. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_github_agent_brute_force_coverage.py +0 -0
  55. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_init_dynamics.py +0 -0
  56. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_mcp_coverage.py +0 -0
  57. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_model_fields.py +0 -0
  58. {github_agent-0.23.0 → github_agent-0.23.2}/tests/test_startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 0.23.0
3
+ Version: 0.23.2
4
4
  Summary: GitHub Agent for MCP
5
5
  Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: <3.14,>=3.11
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: agent-utilities[agent,logfire]>=0.34.0
15
+ Requires-Dist: agent-utilities[agent,logfire]>=0.36.0
16
16
  Provides-Extra: test
17
17
  Requires-Dist: pytest-xdist>=3.6.0; extra == "test"
18
18
  Requires-Dist: pytest; extra == "test"
@@ -41,7 +41,7 @@ Dynamic: license-file
41
41
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
42
42
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
43
43
 
44
- *Version: 0.23.0*
44
+ *Version: 0.23.2*
45
45
 
46
46
  ---
47
47
 
@@ -20,7 +20,7 @@
20
20
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
21
21
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
22
22
 
23
- *Version: 0.23.0*
23
+ *Version: 0.23.2*
24
24
 
25
25
  ---
26
26
 
@@ -4,7 +4,7 @@ import os
4
4
  import sys
5
5
  import warnings
6
6
 
7
- __version__ = "0.23.0"
7
+ __version__ = "0.23.2"
8
8
 
9
9
  logging.basicConfig(
10
10
  level=logging.INFO,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 0.23.0
3
+ Version: 0.23.2
4
4
  Summary: GitHub Agent for MCP
5
5
  Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
6
  License: MIT
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: <3.14,>=3.11
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: agent-utilities[agent,logfire]>=0.34.0
15
+ Requires-Dist: agent-utilities[agent,logfire]>=0.36.0
16
16
  Provides-Extra: test
17
17
  Requires-Dist: pytest-xdist>=3.6.0; extra == "test"
18
18
  Requires-Dist: pytest; extra == "test"
@@ -41,7 +41,7 @@ Dynamic: license-file
41
41
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
42
42
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
43
43
 
44
- *Version: 0.23.0*
44
+ *Version: 0.23.2*
45
45
 
46
46
  ---
47
47
 
@@ -40,6 +40,7 @@ github_agent/mcp/mcp_pull.py
40
40
  github_agent/mcp/mcp_release.py
41
41
  github_agent/mcp/mcp_repo.py
42
42
  github_agent/mcp/mcp_search.py
43
+ scripts/security_sanitizer.py
43
44
  scripts/validate_a2a_agent.py
44
45
  scripts/verify_api_integration.py
45
46
  tests/conftest.py
@@ -1,4 +1,4 @@
1
- agent-utilities[agent,logfire]>=0.34.0
1
+ agent-utilities[agent,logfire]>=0.36.0
2
2
 
3
3
  [test]
4
4
  pytest-xdist>=3.6.0
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "github-agent"
7
- version = "0.23.0"
7
+ version = "0.23.2"
8
8
  readme = "README.md"
9
9
  description = "GitHub Agent for MCP"
10
10
  requires-python = ">=3.11, <3.14"
11
11
  classifiers = [ "Development Status :: 5 - Production/Stable", "License :: Public Domain", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
12
- dependencies = [ "agent-utilities[agent,logfire]>=0.34.0",]
12
+ dependencies = [ "agent-utilities[agent,logfire]>=0.36.0",]
13
13
  [[project.authors]]
14
14
  name = "Audel Rouhi"
15
15
  email = "knucklessg1@gmail.com"
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import re
4
+ import sys
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ # Config
9
+ ALLOWED_TXT_NAMES = {"requirements.txt", "requirements-dev.txt"}
10
+ TRANSIENT_PY_PATTERNS = [
11
+ re.compile(r"^test_.*\.py$"),
12
+ re.compile(r"^fix_.*\.py$"),
13
+ re.compile(r"^debug_.*\.py$"),
14
+ re.compile(r"^scratch_.*\.py$"),
15
+ re.compile(r"^temp_.*\.py$"),
16
+ ]
17
+
18
+ SECRET_PATTERNS = [
19
+ ("GitHub PAT", re.compile(r"ghp_[A-Za-z0-9_]{36,255}")),
20
+ ("GitHub Fine-grained PAT", re.compile(r"github_pat_[A-Za-z0-9_]{82,255}")),
21
+ ("GitLab PAT", re.compile(r"glpat-[A-Za-z0-9\-]{20,255}")),
22
+ ("Generic Secret Assignment", re.compile(r"secret[A-Za-z0-9_]*\s*[:=]\s*['\"][A-Za-z0-9_\-\.\~\*]{16,255}['\"]", re.IGNORECASE)),
23
+ ("Generic Token Assignment", re.compile(r"token\s*[:=]\s*['\"][A-Za-z0-9_\-\.\~\*]{16,255}['\"]", re.IGNORECASE))
24
+ ]
25
+
26
+ EXCLUDED_DIRS = {".git", ".venv", "venv", "node_modules", "build", "dist", "__pycache__", ".tox", ".specify"}
27
+ EXCLUDED_EXTENSIONS = {
28
+ ".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".pyc", ".db", ".kuzu",
29
+ ".sqlite", ".sqlite3", ".zip", ".tar.gz", ".tgz", ".bz2", ".xz", ".pdf",
30
+ ".bin", ".exe", ".dll", ".so", ".dylib", ".woff", ".woff2", ".eot", ".ttf",
31
+ ".mp4", ".mp3", ".wav", ".lock", ".svg"
32
+ }
33
+
34
+ # Placeholder / Mock indicators
35
+ PLACEHOLDER_SUBSTRINGS = [
36
+ "1234567890", "abcdef12345", "abc123youandme", "askdfalskdvjas", "your_", "YOUR_", "your-",
37
+ "dummy", "DUMMY", "example", "EXAMPLE", "mock", "MOCK", "test_token", "test_secret",
38
+ "glpat-askdfalskdvjas", "github_pat_12345", "glpat-abc123youandme", "github_pat_...",
39
+ "glpat-*************", "ghp_*************", "github_pat_*************", "token_*************",
40
+ "secret_*************", "glpat-abc", "ghp_abc", "github_pat_abc", "${env:"
41
+ ]
42
+
43
+ def is_placeholder(match_str: str) -> bool:
44
+ match_lower = match_str.lower()
45
+ for placeholder in PLACEHOLDER_SUBSTRINGS:
46
+ if placeholder in match_lower:
47
+ return True
48
+
49
+ # Check if match is mostly asterisks or single repeated char
50
+ cleaned = match_str.replace("'", "").replace('"', "").strip()
51
+ if not cleaned:
52
+ return True
53
+
54
+ # Check if there are sequences of asterisks indicating masked values
55
+ if "*" in cleaned:
56
+ # e.g., glpat-*************
57
+ return True
58
+
59
+ return False
60
+
61
+ def get_repo_files(repo_path: Path):
62
+ try:
63
+ result = subprocess.run(
64
+ ["git", "ls-files", "--cached", "--others", "--exclude-standard"],
65
+ cwd=str(repo_path),
66
+ capture_output=True,
67
+ text=True,
68
+ check=True
69
+ )
70
+ files = []
71
+ for line in result.stdout.splitlines():
72
+ if line.strip():
73
+ # Avoid files inside excluded directories
74
+ parts = Path(line.strip()).parts
75
+ if not any(part in EXCLUDED_DIRS for part in parts):
76
+ files.append(repo_path / line.strip())
77
+ return files
78
+ except Exception as e:
79
+ # Fallback to manual recursive scan
80
+ files = []
81
+ for root, dirs, walk_files in os.walk(str(repo_path)):
82
+ dirs[:] = [d for d in dirs if d not in EXCLUDED_DIRS and not d.startswith('.')]
83
+ for file in walk_files:
84
+ files.append(Path(root) / file)
85
+ return files
86
+
87
+ def scan_repository(repo_path: Path):
88
+ violations = []
89
+ files_to_scan = get_repo_files(repo_path)
90
+
91
+ for file_path in files_to_scan:
92
+ if not file_path.is_file():
93
+ continue
94
+
95
+ # 1. Check root level naming constraints
96
+ if file_path.parent == repo_path:
97
+ # Check txt files
98
+ if file_path.suffix == ".txt":
99
+ if file_path.name.lower() not in ALLOWED_TXT_NAMES:
100
+ violations.append(
101
+ f"Non-standard root-level text file detected: '{file_path.name}'. Only 'requirements.txt' and 'requirements-dev.txt' are allowed."
102
+ )
103
+ # Check transient py files
104
+ elif file_path.suffix == ".py":
105
+ for pattern in TRANSIENT_PY_PATTERNS:
106
+ if pattern.match(file_path.name):
107
+ violations.append(
108
+ f"Transient/temporary script detected in root: '{file_path.name}'. Please move it to a subfolder or delete it."
109
+ )
110
+ break
111
+
112
+ # 2. Check for secrets
113
+ if file_path.suffix.lower() in EXCLUDED_EXTENSIONS:
114
+ continue
115
+
116
+ if file_path.name == "security_sanitizer.py":
117
+ continue
118
+
119
+ try:
120
+ content = file_path.read_text(encoding="utf-8", errors="ignore")
121
+ lines = content.splitlines()
122
+
123
+ for idx, line in enumerate(lines, 1):
124
+ if any(bypass in line for bypass in ["# sanitizer:ignore", "# sanitizer-ignore", "# nosec"]):
125
+ continue
126
+
127
+ for label, pattern in SECRET_PATTERNS:
128
+ for match in pattern.findall(line):
129
+ match_str = match[0] if isinstance(match, tuple) else match
130
+ if not is_placeholder(match_str):
131
+ rel_path = file_path.relative_to(repo_path)
132
+ violations.append(
133
+ f"Potential unmasked secret ({label}) detected in {rel_path}:{idx}\n"
134
+ f" Line: {line.strip()}"
135
+
136
+ )
137
+ except Exception:
138
+ pass
139
+
140
+ return violations
141
+
142
+ def main():
143
+ repo_path = Path.cwd()
144
+
145
+ print("🔒 Running Security and Garbage Sanitizer...")
146
+ violations = scan_repository(repo_path)
147
+
148
+ if violations:
149
+ print("\n❌ SECURITY AND GARBAGE VALIDATION FAILED!")
150
+ print("Please correct the following issues before committing:")
151
+ for idx, violation in enumerate(violations, 1):
152
+ print(f"\n[{idx}] {violation}")
153
+ print("\nNote: To bypass secret checks on specific lines, append '# sanitizer:ignore' to the end of the line.")
154
+ sys.exit(1)
155
+
156
+ print("✅ All checks passed! No root garbage or unmasked secrets detected.")
157
+ sys.exit(0)
158
+
159
+ if __name__ == "__main__":
160
+ main()
@@ -93,7 +93,7 @@ def test_auth_get_client_delegation_missing_token():
93
93
 
94
94
  def test_auth_get_client_delegation_exchange_failure():
95
95
  # delegation enabled, user token present, but token exchange fails
96
- local.user_token = "some-subject-token"
96
+ local.user_token = "some-subject-token" # sanitizer:ignore
97
97
  config = {
98
98
  "enable_delegation": True,
99
99
  "audience": "github-audience",
@@ -115,7 +115,7 @@ def test_auth_get_client_delegation_exchange_failure():
115
115
 
116
116
  def test_auth_get_client_delegation_auth_error():
117
117
  # delegation enabled, user token present, token exchange succeeds, but Api throws AuthError
118
- local.user_token = "some-subject-token"
118
+ local.user_token = "some-subject-token" # sanitizer:ignore
119
119
  config = {
120
120
  "enable_delegation": True,
121
121
  "audience": "github-audience",
@@ -142,7 +142,7 @@ def test_auth_get_client_delegation_auth_error():
142
142
 
143
143
  def test_auth_get_client_delegation_success():
144
144
  # delegation enabled, user token present, token exchange succeeds, Api succeeds
145
- local.user_token = "some-subject-token"
145
+ local.user_token = "some-subject-token" # sanitizer:ignore
146
146
  config = {
147
147
  "enable_delegation": True,
148
148
  "audience": "github-audience",
@@ -165,7 +165,7 @@ def test_auth_get_client_delegation_success():
165
165
  assert client == mock_api_instance
166
166
  mock_api_class.assert_called_with(
167
167
  url="https://api.github.com",
168
- token="exchanged-github-token",
168
+ token="exchanged-github-token", # sanitizer:ignore
169
169
  verify=True,
170
170
  )
171
171
 
@@ -185,7 +185,7 @@ def test_auth_get_client_default_config():
185
185
 
186
186
  def test_auth_invalid_oauth_types():
187
187
  # delegation enabled, user token present, but one of the parameters is not a string
188
- local.user_token = "some-subject-token"
188
+ local.user_token = "some-subject-token" # sanitizer:ignore
189
189
  config = {
190
190
  "enable_delegation": True,
191
191
  "audience": 12345, # Invalid type (must be string)
File without changes
File without changes