github-agent 2.4.2__tar.gz → 2.4.4__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 (137) hide show
  1. {github_agent-2.4.2 → github_agent-2.4.4}/PKG-INFO +3 -4
  2. {github_agent-2.4.2 → github_agent-2.4.4}/README.md +1 -1
  3. github_agent-2.4.4/github_agent/__init__.py +1 -0
  4. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/github_gql.py +15 -34
  5. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/github_http.py +11 -7
  6. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp_server.py +1 -1
  7. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent.egg-info/PKG-INFO +3 -4
  8. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent.egg-info/requires.txt +1 -2
  9. {github_agent-2.4.2 → github_agent-2.4.4}/pyproject.toml +2 -2
  10. github_agent-2.4.4/tests/test_github_gql.py +73 -0
  11. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_github_http.py +65 -0
  12. github_agent-2.4.2/github_agent/__init__.py +0 -1
  13. github_agent-2.4.2/tests/test_github_gql.py +0 -55
  14. {github_agent-2.4.2 → github_agent-2.4.4}/LICENSE +0 -0
  15. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/__main__.py +0 -0
  16. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/__init__.py +0 -0
  17. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_base.py +0 -0
  18. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_branches.py +0 -0
  19. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_comments.py +0 -0
  20. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_commits.py +0 -0
  21. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_contents.py +0 -0
  22. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_dependabot.py +0 -0
  23. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_issues.py +0 -0
  24. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_orgs.py +0 -0
  25. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_pages.py +0 -0
  26. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_pulls.py +0 -0
  27. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_releases.py +0 -0
  28. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_repos.py +0 -0
  29. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_search.py +0 -0
  30. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api/api_client_workflows.py +0 -0
  31. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/api_client.py +0 -0
  32. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/auth.py +0 -0
  33. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/connectors/__init__.py +0 -0
  34. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/connectors/mcp_source_presets.json +0 -0
  35. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/connectors/tool_schema_fingerprints.json +0 -0
  36. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/github_input_models.py +0 -0
  37. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/github_response_models.py +0 -0
  38. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/kg_ingest.py +0 -0
  39. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/__init__.py +0 -0
  40. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_action.py +0 -0
  41. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_branch.py +0 -0
  42. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_collaborator.py +0 -0
  43. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_commit.py +0 -0
  44. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_content.py +0 -0
  45. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_dependabot.py +0 -0
  46. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_issue.py +0 -0
  47. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_org.py +0 -0
  48. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_pull.py +0 -0
  49. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_release.py +0 -0
  50. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_repo.py +0 -0
  51. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp/mcp_search.py +0 -0
  52. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/mcp_config.json +0 -0
  53. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/ontology/__init__.py +0 -0
  54. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/ontology/certification.json +0 -0
  55. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/ontology/fixtures/records.json +0 -0
  56. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/ontology/github.ttl +0 -0
  57. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/ontology/mappings/source.yaml +0 -0
  58. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/ontology/migrations/manifest.json +0 -0
  59. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/ontology/shapes/connector.shacl.ttl +0 -0
  60. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/prompts/__init__.py +0 -0
  61. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/__init__.py +0 -0
  62. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-actions-ci-review/SKILL.md +0 -0
  63. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-actions-ci-review/WORKFLOW.md +0 -0
  64. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-agent-operations/SKILL.md +0 -0
  65. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-agent-operations/agents/openai.yaml +0 -0
  66. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-agent-operations/references/catalog.md +0 -0
  67. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-backlog-planner/SKILL.md +0 -0
  68. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-backlog-planner/WORKFLOW.md +0 -0
  69. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-backlog-planner/references/addressed-heuristics.md +0 -0
  70. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-backlog-planner/scripts/build_plan.py +0 -0
  71. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-ci-failure-sweep/SKILL.md +0 -0
  72. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-ci-failure-sweep/WORKFLOW.md +0 -0
  73. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-ci-failure-sweep/references/actions-tool-cheatsheet.md +0 -0
  74. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-ci-failure-sweep/scripts/summarize_runs.py +0 -0
  75. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-dependabot-review/SKILL.md +0 -0
  76. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-dependabot-review/WORKFLOW.md +0 -0
  77. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-issue-tracking/SKILL.md +0 -0
  78. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-issue-tracking/WORKFLOW.md +0 -0
  79. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-org-remediation-loop/SKILL.md +0 -0
  80. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-org-remediation-loop/WORKFLOW.md +0 -0
  81. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-org-remediation-loop/scripts/classify_fix_risk.py +0 -0
  82. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pr-review-sweep/SKILL.md +0 -0
  83. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pr-review-sweep/WORKFLOW.md +0 -0
  84. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pr-review-sweep/references/pulls-tool-cheatsheet.md +0 -0
  85. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pr-review-sweep/scripts/summarize_prs.py +0 -0
  86. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-project-provisioner/SKILL.md +0 -0
  87. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-project-provisioner/WORKFLOW.md +0 -0
  88. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-project-provisioner/scripts/enable_pages.py +0 -0
  89. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pull-request-create/SKILL.md +0 -0
  90. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pull-request-create/WORKFLOW.md +0 -0
  91. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pull-request-review/SKILL.md +0 -0
  92. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-pull-request-review/WORKFLOW.md +0 -0
  93. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-repository-management/SKILL.md +0 -0
  94. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-repository-management/WORKFLOW.md +0 -0
  95. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-tools/SKILL.md +0 -0
  96. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-tools/WORKFLOW.md +0 -0
  97. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-tools/code-reviewer.md +0 -0
  98. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-tools/scripts/fetch_comments.py +0 -0
  99. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-tools/scripts/inspect_pr_checks.py +0 -0
  100. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-triage-resolver/SKILL.md +0 -0
  101. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-triage-resolver/WORKFLOW.md +0 -0
  102. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-triage-resolver/references/resolution-rules.md +0 -0
  103. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-triage-resolver/scripts/classify_safe.py +0 -0
  104. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent/skills/github-triage-resolver/scripts/gh_write.py +0 -0
  105. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent.egg-info/SOURCES.txt +0 -0
  106. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent.egg-info/dependency_links.txt +0 -0
  107. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent.egg-info/entry_points.txt +0 -0
  108. {github_agent-2.4.2 → github_agent-2.4.4}/github_agent.egg-info/top_level.txt +0 -0
  109. {github_agent-2.4.2 → github_agent-2.4.4}/scripts/security_sanitizer.py +0 -0
  110. {github_agent-2.4.2 → github_agent-2.4.4}/scripts/verify_api_integration.py +0 -0
  111. {github_agent-2.4.2 → github_agent-2.4.4}/setup.cfg +0 -0
  112. {github_agent-2.4.2 → github_agent-2.4.4}/tests/conftest.py +0 -0
  113. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_action_discovery.py +0 -0
  114. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_api_client_endpoints.py +0 -0
  115. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_api_validation.py +0 -0
  116. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_auth_client_edge_cases.py +0 -0
  117. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_comment_crud.py +0 -0
  118. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_fleet_name.py +0 -0
  119. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_github_agent_api_brute_force_coverage.py +0 -0
  120. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_github_agent_brute_force_coverage.py +0 -0
  121. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_hardening.py +0 -0
  122. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_init_dynamics.py +0 -0
  123. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_kg_ingest.py +0 -0
  124. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_mcp_coverage.py +0 -0
  125. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_mcp_package_dispatch.py +0 -0
  126. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_model_fields.py +0 -0
  127. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_org_crud.py +0 -0
  128. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_pages.py +0 -0
  129. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_repo_secrets_characterization.py +0 -0
  130. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_skill_backlog_build_plan.py +0 -0
  131. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_skill_ci_failure_sweep_summarize_runs.py +0 -0
  132. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_skill_github_tools_fetch_comments.py +0 -0
  133. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_skill_github_tools_inspect_pr_checks.py +0 -0
  134. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_skill_org_remediation_classify_fix_risk.py +0 -0
  135. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_skill_pr_review_sweep_summarize_prs.py +0 -0
  136. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_skill_triage_resolver_classify_safe.py +0 -0
  137. {github_agent-2.4.2 → github_agent-2.4.4}/tests/test_startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 2.4.2
3
+ Version: 2.4.4
4
4
  Summary: GitHub Agent for MCP
5
5
  Author-email: Project Maintainers <maintainers@users.noreply.github.com>
6
6
  License: MIT
@@ -12,9 +12,8 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: gql[requests]>=4.4.0
16
15
  Requires-Dist: requests>=2.34.2
17
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.11
16
+ Requires-Dist: agent-connector-sdk[graphql,mcp]<1.0.0,>=0.3.13
18
17
  Provides-Extra: mcp
19
18
  Provides-Extra: all
20
19
  Provides-Extra: test
@@ -45,7 +44,7 @@ Dynamic: license-file
45
44
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
46
45
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
47
46
 
48
- *Version: 2.4.2*
47
+ *Version: 2.4.4*
49
48
 
50
49
  > **Documentation** — Installation, deployment, and usage across the MCP, API, and
51
50
  > [official documentation](https://knuckles-team.github.io/github-agent/).
@@ -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: 2.4.2*
23
+ *Version: 2.4.4*
24
24
 
25
25
  > **Documentation** — Installation, deployment, and usage across the MCP, API, and
26
26
  > [official documentation](https://knuckles-team.github.io/github-agent/).
@@ -0,0 +1 @@
1
+ __version__ = "2.4.4"
@@ -4,11 +4,10 @@
4
4
  import logging
5
5
  from typing import Any
6
6
 
7
- from agent_connector_sdk.exceptions import MissingParameterError, ParameterError
7
+ from agent_connector_sdk.exceptions import MissingParameterError
8
8
  from agent_connector_sdk.tls.profile import ResolvedTLSProfile
9
9
  from agent_connector_sdk.tls.resolve import resolve_tls_profile
10
- from gql import Client, gql
11
- from gql.transport.requests import RequestsHTTPTransport
10
+ from agent_connector_sdk.transports.graphql import GraphQLAuth, GraphQLClient
12
11
 
13
12
 
14
13
  class GraphQL:
@@ -44,29 +43,21 @@ class GraphQL:
44
43
  # GitHub GraphQL authenticates with a bearer token (classic PAT,
45
44
  # fine-grained PAT, or OAuth/GitHub-App installation token).
46
45
  self.headers = {"Authorization": f"Bearer {token}"}
47
- self.transport = RequestsHTTPTransport(
48
- url=self.url,
49
- headers=self.headers,
50
- **self.tls_profile.requests_kwargs(),
51
- )
52
- self.client = Client(
53
- transport=self.transport, fetch_schema_from_transport=False
46
+ self._gql = GraphQLClient(
47
+ self.url,
48
+ auth=GraphQLAuth.bearer(token),
49
+ tls_profile=self.tls_profile,
50
+ tls_service="github",
54
51
  )
55
52
 
53
+ @property
54
+ def client(self) -> Any:
55
+ """The underlying protocol client, built on first use."""
56
+ return self._gql.client
57
+
56
58
  def close(self) -> None:
57
- """Release GraphQL transport state and runtime-only TLS material.
58
-
59
- ``Client.close_sync()`` unconditionally asserts ``self.session`` is a
60
- ``SyncClientSession`` — but under gql 4.0 that attribute is only ever
61
- set by ``connect_sync()`` (called implicitly by ``execute_gql`` /
62
- ``client.execute``). If this ``GraphQL`` was constructed but never
63
- used to run a query, the underlying ``Client`` has no ``session``
64
- attribute yet and ``close_sync()`` raises ``AttributeError`` instead
65
- of being a no-op. Only close a session that was actually opened.
66
- """
67
- if hasattr(self.client, "session"):
68
- self.client.close_sync()
69
- self.tls_profile.cleanup()
59
+ """Release GraphQL transport state and runtime-only TLS material."""
60
+ self._gql.close()
70
61
 
71
62
  @staticmethod
72
63
  def _graphql_endpoint(url: str) -> str:
@@ -91,17 +82,7 @@ class GraphQL:
91
82
  Raises:
92
83
  ParameterError: If the query fails or the response carries errors.
93
84
  """
94
- try:
95
- query = gql(query_str)
96
- result = self.client.execute(
97
- query, variable_values=variables, operation_name=operation_name
98
- )
99
- if "errors" in result:
100
- raise ParameterError(f"GraphQL errors: {result['errors']}")
101
- return result
102
- except Exception as e:
103
- logging.error("GraphQL execution failed: error_type=%s", type(e).__name__)
104
- raise ParameterError(f"Query execution failed: {type(e).__name__}") from e
85
+ return self._gql.execute(query_str, variables, operation_name)
105
86
 
106
87
  def enable_pull_request_auto_merge(
107
88
  self, pull_request_id: str, merge_method: str = "MERGE"
@@ -4,21 +4,23 @@ from __future__ import annotations
4
4
 
5
5
  import http.client
6
6
  import json
7
- import os
8
7
  import ssl
9
8
  from typing import Any
10
9
 
10
+ from agent_connector_sdk.tls.errors import TransportSecurityError
11
+ from agent_connector_sdk.tls.profile import ResolvedTLSProfile
12
+ from agent_connector_sdk.tls.resolve import resolve_tls_profile
13
+
11
14
  GITHUB_API_HOST = "api.github.com"
12
15
  MAX_REQUEST_BYTES = 1 * 1024 * 1024
13
16
  MAX_RESPONSE_BYTES = 8 * 1024 * 1024
14
17
 
15
18
 
16
- def _tls_context() -> ssl.SSLContext:
17
- cafile = os.environ.get("SSL_CERT_FILE") or os.environ.get("REQUESTS_CA_BUNDLE")
18
- capath = os.environ.get("SSL_CERT_DIR")
19
+ def _tls_profile() -> ResolvedTLSProfile:
20
+ """Resolve the GitHub TLS profile from the SDK (SDK-CONNECTOR-CONTROL-R017)."""
19
21
  try:
20
- return ssl.create_default_context(cafile=cafile or None, capath=capath or None)
21
- except (OSError, ssl.SSLError):
22
+ return resolve_tls_profile("github")
23
+ except TransportSecurityError:
22
24
  raise RuntimeError("runtime TLS trust configuration is invalid") from None
23
25
 
24
26
 
@@ -103,11 +105,12 @@ def github_json_request(
103
105
  _validate_token_shape(token)
104
106
  body = _encode_request_body(payload)
105
107
  headers = _request_headers(token)
108
+ profile = _tls_profile()
106
109
  connection = http.client.HTTPSConnection(
107
110
  GITHUB_API_HOST,
108
111
  443,
109
112
  timeout=30,
110
- context=_tls_context(),
113
+ context=profile.ssl_context,
111
114
  )
112
115
  try:
113
116
  connection.request(method, path, body=body, headers=headers)
@@ -118,3 +121,4 @@ def github_json_request(
118
121
  raise RuntimeError("GitHub service is unavailable") from None
119
122
  finally:
120
123
  connection.close()
124
+ profile.cleanup()
@@ -39,7 +39,7 @@ from github_agent.auth import (
39
39
  )
40
40
  from github_agent.github_response_models import PagesAlreadyEnabled, PagesNotEnabled
41
41
 
42
- __version__ = "2.4.2"
42
+ __version__ = "2.4.4"
43
43
  logger = get_logger("GithubMCPServer")
44
44
  logger.setLevel(logging.INFO)
45
45
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 2.4.2
3
+ Version: 2.4.4
4
4
  Summary: GitHub Agent for MCP
5
5
  Author-email: Project Maintainers <maintainers@users.noreply.github.com>
6
6
  License: MIT
@@ -12,9 +12,8 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: gql[requests]>=4.4.0
16
15
  Requires-Dist: requests>=2.34.2
17
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.11
16
+ Requires-Dist: agent-connector-sdk[graphql,mcp]<1.0.0,>=0.3.13
18
17
  Provides-Extra: mcp
19
18
  Provides-Extra: all
20
19
  Provides-Extra: test
@@ -45,7 +44,7 @@ Dynamic: license-file
45
44
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/github-agent)
46
45
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/github-agent)
47
46
 
48
- *Version: 2.4.2*
47
+ *Version: 2.4.4*
49
48
 
50
49
  > **Documentation** — Installation, deployment, and usage across the MCP, API, and
51
50
  > [official documentation](https://knuckles-team.github.io/github-agent/).
@@ -1,6 +1,5 @@
1
- gql[requests]>=4.4.0
2
1
  requests>=2.34.2
3
- agent-connector-sdk[mcp]<1.0.0,>=0.3.11
2
+ agent-connector-sdk[graphql,mcp]<1.0.0,>=0.3.13
4
3
 
5
4
  [all]
6
5
 
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "github-agent"
7
- version = "2.4.2"
7
+ version = "2.4.4"
8
8
  readme = "README.md"
9
9
  description = "GitHub Agent for MCP"
10
10
  requires-python = ">=3.12"
11
11
  classifiers = [ "Development Status :: 5 - Production/Stable", "License :: Public Domain", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
12
- dependencies = [ "gql[requests]>=4.4.0", "requests>=2.34.2", "agent-connector-sdk[mcp]>=0.3.11,<1.0.0",]
12
+ dependencies = [ "requests>=2.34.2", "agent-connector-sdk[mcp,graphql]>=0.3.13,<1.0.0",]
13
13
  [[project.authors]]
14
14
  name = "Project Maintainers"
15
15
  email = "maintainers@users.noreply.github.com"
@@ -0,0 +1,73 @@
1
+ """GitHub GraphQL client — endpoint derivation + construction (no network)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pytest
6
+ from agent_connector_sdk.exceptions import MissingParameterError
7
+
8
+ from github_agent.github_gql import GraphQL
9
+
10
+
11
+ def test_endpoint_github_com():
12
+ assert GraphQL._graphql_endpoint("https://api.github.com") == (
13
+ "https://api.github.com/graphql"
14
+ )
15
+ assert GraphQL._graphql_endpoint("https://api.github.com/") == (
16
+ "https://api.github.com/graphql"
17
+ )
18
+
19
+
20
+ def test_endpoint_enterprise():
21
+ assert GraphQL._graphql_endpoint("https://github.example/api/v3") == (
22
+ "https://github.example/api/graphql"
23
+ )
24
+
25
+
26
+ def test_requires_url_and_token():
27
+ with pytest.raises(MissingParameterError):
28
+ GraphQL(url=None, token="x")
29
+ with pytest.raises(MissingParameterError):
30
+ GraphQL(url="https://api.github.com", token=None)
31
+
32
+
33
+ def test_construction_sets_bearer_header():
34
+ g = GraphQL(url="https://api.github.com", token="tok123")
35
+ assert g.headers["Authorization"] == "Bearer tok123"
36
+ assert g.url.endswith("/graphql")
37
+
38
+
39
+ def test_close_without_session_does_not_raise():
40
+ """close() on a never-used client is a safe no-op."""
41
+ GraphQL(url="https://api.github.com", token="tok123").close()
42
+
43
+
44
+ @pytest.mark.spec("CONN-GITHUB-AGENT-CONNECTOR-IDENTITY-R002")
45
+ def test_wrapper_delegates_to_shared_graphql_client():
46
+ from unittest.mock import patch
47
+
48
+ from agent_connector_sdk.tls.resolve import resolve_tls_profile
49
+ from agent_connector_sdk.transports.graphql import GraphQLClient
50
+
51
+ profile = resolve_tls_profile("github")
52
+ g = GraphQL(url="https://github.example/api/v3", token="tok123", tls_profile=profile)
53
+ assert isinstance(g._gql, GraphQLClient)
54
+ assert g._gql.endpoint == "https://github.example/api/graphql"
55
+ assert g._gql.headers["Authorization"] == "Bearer tok123"
56
+ assert g._gql.tls_profile is profile
57
+ with patch.object(GraphQLClient, "execute", return_value={"viewer": {}}) as ex:
58
+ assert g.execute_gql("query { viewer { login } }", {"a": 1}, "Op") == {
59
+ "viewer": {}
60
+ }
61
+ ex.assert_called_once_with("query { viewer { login } }", {"a": 1}, "Op")
62
+
63
+
64
+ def test_execute_failure_message_is_redacted_class_name():
65
+ from unittest.mock import patch
66
+
67
+ from agent_connector_sdk.exceptions import ParameterError
68
+ from agent_connector_sdk.transports.graphql import GraphQLClient
69
+
70
+ g = GraphQL(url="https://api.github.com", token="tok123")
71
+ with patch.object(GraphQLClient, "_attempt", side_effect=ValueError("boom")):
72
+ with pytest.raises(ParameterError, match="Query execution failed: ValueError"):
73
+ g.execute_gql("query { viewer { login } }")
@@ -163,3 +163,68 @@ def test_github_json_request_encodes_payload_as_compact_json():
163
163
  assert value == {"created": True}
164
164
  sent_kwargs = connection.request.call_args.kwargs
165
165
  assert sent_kwargs["body"] == json.dumps({"title": "hi"}, separators=(",", ":")).encode()
166
+
167
+
168
+ @pytest.mark.spec("CONN-GITHUB-AGENT-TRANSPORT-TLS-R001")
169
+ def test_request_uses_sdk_tls_profile_context():
170
+ """CONN-GITHUB-AGENT-TRANSPORT-TLS-R001: the connection uses the profile's context."""
171
+ connection, _ = _mock_connection()
172
+ profile = MagicMock()
173
+ with (
174
+ patch("github_agent.github_http.resolve_tls_profile", return_value=profile) as resolve,
175
+ patch("github_agent.github_http.http.client.HTTPSConnection", return_value=connection) as conn_cls,
176
+ ):
177
+ github_json_request("GET", "/repos/x/y", "tok")
178
+ resolve.assert_called_once_with("github")
179
+ assert conn_cls.call_args.kwargs["context"] is profile.ssl_context
180
+ profile.cleanup.assert_called_once()
181
+
182
+
183
+ @pytest.mark.spec("CONN-GITHUB-AGENT-TRANSPORT-TLS-R001")
184
+ def test_private_ca_is_carried_through_the_profile(tmp_path, monkeypatch):
185
+ """CONN-GITHUB-AGENT-TRANSPORT-TLS-R001: a configured CA bundle reaches the profile."""
186
+ from cryptography import x509
187
+ from cryptography.hazmat.primitives import hashes, serialization
188
+ from cryptography.hazmat.primitives.asymmetric import ec
189
+ import datetime
190
+
191
+ from github_agent.github_http import _tls_profile
192
+
193
+ key = ec.generate_private_key(ec.SECP256R1())
194
+ name = x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "test-ca")])
195
+ now = datetime.datetime.now(datetime.timezone.utc)
196
+ cert = (
197
+ x509.CertificateBuilder()
198
+ .subject_name(name)
199
+ .issuer_name(name)
200
+ .public_key(key.public_key())
201
+ .serial_number(1)
202
+ .not_valid_before(now)
203
+ .not_valid_after(now + datetime.timedelta(days=1))
204
+ .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
205
+ .sign(key, hashes.SHA256())
206
+ )
207
+ ca = tmp_path / "ca.pem"
208
+ ca.write_bytes(cert.public_bytes(serialization.Encoding.PEM))
209
+ monkeypatch.setenv("GITHUB_CA_BUNDLE", str(ca))
210
+ profile = _tls_profile()
211
+ try:
212
+ assert profile.ca_bundle_path == ca
213
+ assert profile.verify_enabled
214
+ finally:
215
+ profile.cleanup()
216
+
217
+
218
+ @pytest.mark.spec("CONN-GITHUB-AGENT-TRANSPORT-TLS-R001")
219
+ def test_no_hand_built_ssl_context_remains():
220
+ """CONN-GITHUB-AGENT-TRANSPORT-TLS-R001: no package code builds its own context."""
221
+ from pathlib import Path
222
+
223
+ import github_agent
224
+
225
+ root = Path(github_agent.__file__).parent
226
+ for path in root.rglob("*.py"):
227
+ text = path.read_text(encoding="utf-8")
228
+ assert "create_default_context" not in text, path
229
+ assert "verify=False" not in text, path
230
+ assert "disable_warnings" not in text, path
@@ -1 +0,0 @@
1
- __version__ = "2.4.2"
@@ -1,55 +0,0 @@
1
- """GitHub GraphQL client — endpoint derivation + construction (no network)."""
2
-
3
- from __future__ import annotations
4
-
5
- import pytest
6
- from agent_connector_sdk.exceptions import MissingParameterError
7
-
8
- from github_agent.github_gql import GraphQL
9
-
10
-
11
- def test_endpoint_github_com():
12
- assert GraphQL._graphql_endpoint("https://api.github.com") == (
13
- "https://api.github.com/graphql"
14
- )
15
- assert GraphQL._graphql_endpoint("https://api.github.com/") == (
16
- "https://api.github.com/graphql"
17
- )
18
-
19
-
20
- def test_endpoint_enterprise():
21
- assert GraphQL._graphql_endpoint("https://github.example/api/v3") == (
22
- "https://github.example/api/graphql"
23
- )
24
-
25
-
26
- def test_requires_url_and_token():
27
- with pytest.raises(MissingParameterError):
28
- GraphQL(url=None, token="x")
29
- with pytest.raises(MissingParameterError):
30
- GraphQL(url="https://api.github.com", token=None)
31
-
32
-
33
- def test_construction_sets_bearer_header():
34
- g = GraphQL(url="https://api.github.com", token="tok123")
35
- assert g.headers["Authorization"] == "Bearer tok123"
36
- assert g.url.endswith("/graphql")
37
-
38
-
39
- def test_close_without_session_does_not_raise():
40
- """Regression guard: under gql 4.0, Client.close_sync() unconditionally
41
- asserts ``self.session`` — an attribute only ever set by connect_sync()
42
- (called implicitly the first time a query executes). A GraphQL client
43
- that was constructed but never used to run a query has no such session
44
- yet, so close() must be a safe no-op rather than raising AttributeError.
45
- """
46
- g = GraphQL(url="https://api.github.com", token="tok123")
47
- g.close()
48
-
49
-
50
- def test_close_after_session_opened_closes_cleanly():
51
- """Once a sync session has actually been opened, close() still closes it."""
52
- g = GraphQL(url="https://api.github.com", token="tok123")
53
- g.client.connect_sync()
54
- assert hasattr(g.client, "session")
55
- g.close()
File without changes
File without changes