github-agent 2.4.15__py3-none-any.whl → 2.5.0__py3-none-any.whl

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.
@@ -2,6 +2,7 @@
2
2
  from typing import Any
3
3
 
4
4
  from scion_sdk.exceptions import require_auth
5
+ from scion_sdk.mcp.destructive import destructive_operation
5
6
 
6
7
  from github_agent.api.api_client_base import BaseApiClient
7
8
  from github_agent.github_response_models import Response
@@ -59,6 +60,7 @@ class Api(BaseApiClient):
59
60
  response.raise_for_status()
60
61
  return Response(response=response, data=response.json())
61
62
 
63
+ @destructive_operation
62
64
  @require_auth
63
65
  def update_dependabot_alert(
64
66
  self,
@@ -111,8 +111,8 @@ class Api(BaseApiClient):
111
111
  """Schedule an organization for deletion. IRREVERSIBLE.
112
112
 
113
113
  GitHub responds 202 Accepted and deletes the organization, all of its
114
- repositories, and all of its data asynchronously. The MCP layer gates
115
- this action behind allow_destructive / GITHUB_ALLOW_DESTRUCTIVE.
114
+ repositories, and all of its data asynchronously. The SDK asks
115
+ the caller to confirm this action.
116
116
 
117
117
  DELETE /orgs/{org}
118
118
  https://docs.github.com/en/rest/orgs/orgs#delete-an-organization
@@ -240,8 +240,8 @@ class Api(BaseApiClient):
240
240
  def remove_organization_member(self, org: str, username: str) -> Response:
241
241
  """Remove a user from an organization (repositories access included).
242
242
 
243
- Destructive: the MCP layer gates this action behind
244
- allow_destructive / GITHUB_ALLOW_DESTRUCTIVE. GitHub responds 204.
243
+ Destructive: the SDK asks the caller to confirm this
244
+ action. GitHub responds 204.
245
245
 
246
246
  DELETE /orgs/{org}/members/{username}
247
247
  https://docs.github.com/en/rest/orgs/members#remove-an-organization-member
@@ -150,8 +150,8 @@ class Api(BaseApiClient):
150
150
  def delete_pages(self, owner: str, repo: str) -> Response:
151
151
  """Disable GitHub Pages for a repository and delete the site.
152
152
 
153
- Destructive: the MCP layer gates this action behind
154
- allow_destructive / GITHUB_ALLOW_DESTRUCTIVE. GitHub responds 204.
153
+ Destructive: the SDK asks the caller to confirm this
154
+ action. GitHub responds 204.
155
155
 
156
156
  DELETE /repos/{owner}/{repo}/pages
157
157
  https://docs.github.com/en/rest/pages/pages#delete-a-apiname-pages-site
@@ -5,6 +5,7 @@ from scion_sdk.exceptions import (
5
5
  ParameterError,
6
6
  require_auth,
7
7
  )
8
+ from scion_sdk.mcp.destructive import destructive_operation
8
9
 
9
10
  from github_agent.api.api_client_base import BaseApiClient
10
11
  from github_agent.github_input_models import (
@@ -107,6 +108,7 @@ class Api(BaseApiClient):
107
108
  response.raise_for_status()
108
109
  return Response(response=response, data=response.json())
109
110
 
111
+ @destructive_operation
110
112
  @require_auth
111
113
  def merge_pull_request(
112
114
  self,
github_agent/auth.py CHANGED
@@ -21,16 +21,6 @@ from github_agent.api_client import Api
21
21
  logger = get_logger(__name__)
22
22
 
23
23
 
24
- def allow_destructive_default() -> bool:
25
- """Fleet-wide default for the destructive-action gate.
26
-
27
- Destructive MCP actions (e.g. organization delete, member removal) are
28
- blocked unless the caller passes allow_destructive=true or the
29
- GITHUB_ALLOW_DESTRUCTIVE environment variable is set truthy.
30
- """
31
- return setting("GITHUB_ALLOW_DESTRUCTIVE", False)
32
-
33
-
34
24
  def _exchange_delegated_token(settings: DelegationSettings) -> str:
35
25
  """Exchange the caller's verified MCP token for a downstream GitHub token."""
36
26
  logger.info(
@@ -29,6 +29,7 @@ from scion_sdk.config import load_config
29
29
  from scion_sdk.connector_identity import connector_version
30
30
  from scion_sdk.mcp.concurrency import run_blocking
31
31
  from scion_sdk.mcp.content import ConnectorContent
32
+ from scion_sdk.mcp.destructive import guard_destructive
32
33
  from scion_sdk.mcp.server import create_mcp_server
33
34
  from scion_sdk.mcp.tool_surface import register_tool_surface
34
35
 
@@ -218,7 +219,7 @@ def register_auto_merge_tools(mcp: FastMCP):
218
219
  """Register the GraphQL-only pull request auto-merge tools."""
219
220
 
220
221
  @mcp.tool(
221
- tags={"pulls"}, annotations={"readOnlyHint": False, "destructiveHint": False}
222
+ tags={"pulls"}, annotations={"readOnlyHint": False, "destructiveHint": True}
222
223
  )
223
224
  async def github_pulls_enable_auto_merge(
224
225
  owner: str = Field(description="Repository owner."),
@@ -228,9 +229,21 @@ def register_auto_merge_tools(mcp: FastMCP):
228
229
  default="MERGE", description="MERGE, SQUASH or REBASE."
229
230
  ),
230
231
  client=Depends(get_client),
232
+ confirm: bool = Field(
233
+ default=False,
234
+ description="Confirm this destructive call when the client cannot be asked.",
235
+ ),
231
236
  ctx: Context | None = Field(default=None, description="MCP context"),
232
237
  ) -> Any:
233
238
  """Turn on auto-merge for a pull request: it merges once required checks pass."""
239
+ refused = await guard_destructive(
240
+ ctx,
241
+ "enable_auto_merge",
242
+ {"owner": owner, "repo": repo, "number": number},
243
+ confirm=confirm,
244
+ )
245
+ if refused is not None:
246
+ return refused
234
247
  try:
235
248
  gql_client = await run_blocking(get_graphql_client)
236
249
  except Exception as e:
@@ -2,10 +2,10 @@
2
2
  "api_version": "graphos.io/v1",
3
3
  "artifacts": {
4
4
  "github_agent/ontology/fixtures/records.json": "12f5b54b0ae98770f279f99e136788d063340042a9d6ff4bac0c22a886d2dc7b",
5
- "github_agent/ontology/github.ttl": "3558c43835211ddcf7d2af622a37c0c370a7e8fe6b40a111b9bc98dd7e91f2ac",
5
+ "github_agent/ontology/github.ttl": "70c68c0ae5cc8b056bd6f21af44eb3cbdf6d3bf213e0764e5c3341ea536fbd20",
6
6
  "github_agent/ontology/mappings/source.yaml": "5142f75b88634aeac6850fe6de5b176958d63073daab2c573cf9c03daa46021c",
7
7
  "github_agent/ontology/migrations/manifest.json": "adf16022502dd031dd303a52abae7a0677ece1135e1e05c21dba24c9ae51935c",
8
- "github_agent/ontology/shapes/connector.shacl.ttl": "709f555b7b8cc6b1e0adddfeb8e077834f5db548bed4a904afd2a195e49aab1c"
8
+ "github_agent/ontology/shapes/connector.shacl.ttl": "0972b7e3b5f56fb0452f070800cd1f7ee790f6cf183f308f1cf69e5a0db716e0"
9
9
  },
10
10
  "checks": {
11
11
  "declared_tool_schema": "passed",
@@ -29,5 +29,5 @@
29
29
  "signer": "UNSIGNED-PREVIEW",
30
30
  "signing_public_key": "",
31
31
  "status": "source-validated",
32
- "validated_at": "2026-11-06T18:41:25Z"
32
+ "validated_at": "2026-11-12T19:19:41Z"
33
33
  }
@@ -2,6 +2,7 @@
2
2
  @prefix foaf: <http://xmlns.com/foaf/0.1/> .
3
3
  @prefix dc: <http://purl.org/dc/terms/> .
4
4
  @prefix : <http://knuckles.team/kg#> .
5
+ @prefix core: <https://knuckles-team.github.io/ontology/core#> .
5
6
  @prefix owl: <http://www.w3.org/2002/07/owl#> .
6
7
  @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
7
8
  @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@@ -15,24 +16,26 @@
15
16
  # Shared concepts owned by the epistemic-graph ontology and referenced here, never redeclared:
16
17
  # Repository, PullRequest, Release, Branch, Commit, PipelineRun. Only the GitHub-specific subclasses and properties are declared in this pack.
17
18
 
18
- :Organization a owl:Class .
19
+ :Organization a owl:Class ;
20
+ rdfs:subClassOf core:Organization .
19
21
 
20
22
 
21
23
  :Issue a owl:Class ;
22
- rdfs:subClassOf :WorkItem ;
24
+ rdfs:subClassOf core:WorkItem ;
23
25
  rdfs:label "Issue" ;
24
26
  rdfs:comment "A tracked work item, bug, or discussion in a repository (github_get_issues)." .
25
27
 
26
- :Workflow a owl:Class .
28
+ :Workflow a owl:Class ;
29
+ rdfs:subClassOf core:Workflow .
27
30
 
28
31
 
29
32
  :WorkflowRun a owl:Class ;
30
- rdfs:subClassOf :PipelineRun ;
33
+ rdfs:subClassOf core:PipelineRun ;
31
34
  rdfs:label "Workflow Run" ;
32
35
  rdfs:comment "A single execution of a GitHub Actions workflow for a ref/commit (github_get_workflow_runs)." .
33
36
 
34
37
  :CheckRun a owl:Class ;
35
- rdfs:subClassOf :PipelineRun ;
38
+ rdfs:subClassOf core:PipelineRun ;
36
39
  rdfs:label "Check Run" ;
37
40
  rdfs:comment """A single job/check within a PipelineRun (github_get_workflow_run_jobs workflow-run job or
38
41
  GitHub Checks-API check run). Shares its class name with the twin gitlab-api producer.""" .
@@ -1,5 +1,5 @@
1
- @prefix : <http://knuckles.team/kg#> .
2
- @prefix shape: <http://knuckles.team/kg/github/shape#> .
1
+ @prefix : <https://knuckles-team.github.io/ontology/core#> .
2
+ @prefix shape: <https://knuckles-team.github.io/ontology/connector/github-shapes#> .
3
3
  @prefix sh: <http://www.w3.org/ns/shacl#> .
4
4
  @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
5
5
 
@@ -65,8 +65,7 @@ with local copies or bypass a failing check.
65
65
  - Credentials come from `GITHUB_TOKEN`; the endpoint is derived from `GITHUB_URL`
66
66
  (`api.github.com`, or a GitHub Enterprise `/api/v3` host whose GraphQL endpoint
67
67
  is `/api/graphql`). Mock all GitHub calls; never use a real token in a gate.
68
- - Destructive operations stay behind `GITHUB_ALLOW_DESTRUCTIVE`; keep it false
69
- by default and test both states.
68
+ - Destructive operations are declared once with the SDK `destructive_operation` decorator; the SDK asks the caller to confirm (`confirm=true`), and `SCION_ALLOW_DESTRUCTIVE` is the one operator setting. Never add a connector-local knob.
70
69
  - Prefer one aliased `github_graphql` query over many REST calls for cross-repo
71
70
  reads; keep REST and GraphQL parity when adding a tool domain.
72
71
  - Packaged skills under `github_agent/skills/` have their own helper tests
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-agent
3
- Version: 2.4.15
3
+ Version: 2.5.0
4
4
  Summary: GitHub Agent for MCP
5
5
  Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
@@ -13,7 +13,7 @@ Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: requests>=2.34.2
16
- Requires-Dist: scion-sdk[graphql,mcp]>=0.9.0
16
+ Requires-Dist: scion-sdk[graphql,mcp]<0.11,>=0.10.2
17
17
  Provides-Extra: mcp
18
18
  Provides-Extra: all
19
19
  Provides-Extra: test
@@ -247,7 +247,6 @@ When query strings or parameters are supplied, an LLM-free **Knowledge Graph res
247
247
  "COMMITTOOL": "True",
248
248
  "CONTENTTOOL": "True",
249
249
  "DEPENDABOTTOOL": "True",
250
- "GITHUB_ALLOW_DESTRUCTIVE": "False",
251
250
  "GITHUB_HTTP_CONNECT_TIMEOUT": "10",
252
251
  "GITHUB_HTTP_READ_TIMEOUT": "30",
253
252
  "GITHUB_TOKEN": "your_github_token_here",
@@ -298,7 +297,6 @@ own runtime secret boundary.
298
297
  "COMMITTOOL": "True",
299
298
  "CONTENTTOOL": "True",
300
299
  "DEPENDABOTTOOL": "True",
301
- "GITHUB_ALLOW_DESTRUCTIVE": "False",
302
300
  "GITHUB_HTTP_CONNECT_TIMEOUT": "10",
303
301
  "GITHUB_HTTP_READ_TIMEOUT": "30",
304
302
  "GITHUB_TOKEN": "your_github_token_here",
@@ -348,7 +346,6 @@ docker run -i --rm \
348
346
  -e COMMITTOOL=True \
349
347
  -e CONTENTTOOL=True \
350
348
  -e DEPENDABOTTOOL=True \
351
- -e GITHUB_ALLOW_DESTRUCTIVE=False \
352
349
  -e GITHUB_HTTP_CONNECT_TIMEOUT=10 \
353
350
  -e GITHUB_HTTP_READ_TIMEOUT=30 \
354
351
  -e GITHUB_TOKEN=your_github_token_here \
@@ -412,7 +409,6 @@ the detailed transport contract.
412
409
  | `TLS_PROFILE` | `private-ca` | AgentConfig named transport profile |
413
410
  | `TLS_PROFILE_REF` | `secret://transport/provider` | Direct runtime profile reference |
414
411
  | `TLS_PROFILES_REF` | `secret://transport/catalog` | Named runtime profile catalog |
415
- | `GITHUB_ALLOW_DESTRUCTIVE` | `False` | Allow destructive (delete/force) operations |
416
412
  | `GITHUB_HTTP_CONNECT_TIMEOUT` | `10` | HTTP client timeouts (seconds) |
417
413
  | `GITHUB_HTTP_READ_TIMEOUT` | `30` | |
418
414
  | `DEBUG` | `False` | |
@@ -1,7 +1,7 @@
1
1
  github_agent/__init__.py,sha256=C7pWvMKXqVTxI5_jZAr1KWEYADZurn5is0VOx5l5CbM,474
2
2
  github_agent/__main__.py,sha256=O4Xg__fMvKfUsA6m61pLV56jlYY6EORiLhgDLlp0vJ8,92
3
3
  github_agent/api_client.py,sha256=O69YfkXBKyVd59EC8szaMlw3_ZxwEEvsLSvhWlfYnvk,1581
4
- github_agent/auth.py,sha256=W26J0N34mXIvq5ipYokJ7eJcInfnvxaGvqOiGWyWUp0,4611
4
+ github_agent/auth.py,sha256=pB3jUeP7qvLdzzpYeZZ8o7FTS3GMsBpuaIIzWx1daLs,4239
5
5
  github_agent/connector_contracts.py,sha256=2plbwsw6d4mMuxRx-kksD4EamYDgf03HOqBFd8ixCAQ,41936
6
6
  github_agent/connector_sources.py,sha256=00mzXqC9KPSi15QIIE20UkmgS0QLd7wnYAatdWAjRoQ,6329
7
7
  github_agent/github_gql.py,sha256=23_sJnv037WE2CvG93bXFHob8oiw1VShnevLi78BiTU,4282
@@ -10,18 +10,18 @@ github_agent/github_input_models.py,sha256=yqqPGHb206th736MZvbnxq9F1JRsBUBODNeNV
10
10
  github_agent/github_response_models.py,sha256=mllSt0frBgzklUtfuHywJ2Ald3m99So948Xikt3H2Tc,8859
11
11
  github_agent/kg_ingest.py,sha256=aXVYbK8RDlE39wBJxgxc73OoqEdgNJLGUCFCl5hbNd8,17958
12
12
  github_agent/mcp_config.json,sha256=2OOXrwO1sDLyHQqpZwhvDHizPIe3by6YmK4KFE333gI,23
13
- github_agent/mcp_server.py,sha256=wgI99lAUtzsIaazgSDH7g5HnXKgg8bSHj3bS5jDvxp8,15317
13
+ github_agent/mcp_server.py,sha256=LmtrpwEWZJGILrgmkeQs0_-Y8RtrDPplhc4MWtqNGN8,15784
14
14
  github_agent/api/__init__.py,sha256=ntaEPqk-dsAV3HyyDLc2hYpc9nTTyG5CKI-SVDDjc24,27
15
15
  github_agent/api/api_client_base.py,sha256=UdVOUPPRnfVo8IeZxpHXn7VbrHm-4vsXTKk3ZAv8wgQ,7445
16
16
  github_agent/api/api_client_branches.py,sha256=Lj3eCwNxuyR564YV4Lh00Zm4xjsJDfN20q463ON5qDg,3930
17
17
  github_agent/api/api_client_comments.py,sha256=lfUveMt5m3-ZPrIY2UV-j3huEm1nThllz1uPp2QxVnw,13192
18
18
  github_agent/api/api_client_commits.py,sha256=1p8XOPnlGAtNvhG3JqoediHnCANK-z0B066AY0NiahY,1471
19
19
  github_agent/api/api_client_contents.py,sha256=3dwNkGzl_Nk5PlGKsdlmw2lKf9HQUOOxChZfpnRgD-Q,3916
20
- github_agent/api/api_client_dependabot.py,sha256=IKSwk8Qkb0ME6uqNLwWNB2EnjZEy7cv9VCSw2RSViV4,3521
20
+ github_agent/api/api_client_dependabot.py,sha256=0JE2xe3bJjAx5gJYkGCad1-ak3o6eKP0De86qEFlHu4,3608
21
21
  github_agent/api/api_client_issues.py,sha256=yOmzu1bFd2s_FOdQpuq5J4ob6h-a33R4JjtqQ4AWrsk,2952
22
- github_agent/api/api_client_orgs.py,sha256=rm5fbM0DvGbE-XYFOD8T25tFHHyzAMtXS8TtZ2XTlOI,11114
23
- github_agent/api/api_client_pages.py,sha256=D7AiKMKAQhBJvMU0v7dBO2aUhmF9gnzW0QBe5DFch-A,8827
24
- github_agent/api/api_client_pulls.py,sha256=R1DZnx-oQ2FV0-nTe74WPZJJTOms6KsJPzSXjYa3kxQ,5801
22
+ github_agent/api/api_client_orgs.py,sha256=OVJ3qWwgXt6YBbfjAAdSS3xqiWhhvFhsbiVmZcdB8BY,11040
23
+ github_agent/api/api_client_pages.py,sha256=9-4yM4dbsqxn9VUD6k2Jezzn4AfVxhNnUMnAStaL5L0,8790
24
+ github_agent/api/api_client_pulls.py,sha256=8q2s2Ir-Ci_y4PwPSsFonxipH9llpOK-HkFyd42mzrU,5888
25
25
  github_agent/api/api_client_releases.py,sha256=q3XrePe9KW3_tyjzpagnGIU4KOJB4wo3Ek-g4yxsGCY,3661
26
26
  github_agent/api/api_client_repos.py,sha256=zBpuc4WeslH7Pw0PKeh9XpveE4eGmoSXsUniED8hCHE,8420
27
27
  github_agent/api/api_client_search.py,sha256=-lOrVHjSncZ4us2tr4Keo3ygUdOABJxCWikpbsmTwJo,2222
@@ -29,12 +29,12 @@ github_agent/api/api_client_workflows.py,sha256=_ukxS6rnezp33Zk6bmAyNv4RIjwZvkUf
29
29
  github_agent/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  github_agent/mcp/__init__.py,sha256=9aOfl64J5oMSnaUZVwnpo3XO7GykLM2D11_4Kt761go,31
31
31
  github_agent/ontology/__init__.py,sha256=dy7lE5jChNOHXMHm7ZfGfT8bH8ZhCZMSuGgu3G-Q3mM,532
32
- github_agent/ontology/certification.json,sha256=JRRsPwnTiQOAAnWaMWgWNoWo5nxoCpdJ-squxKokY4M,1313
33
- github_agent/ontology/github.ttl,sha256=NVjEODUhHdz30q9iKjfAw3Cn6P5rQKERubyY3X6R8qw,8209
32
+ github_agent/ontology/certification.json,sha256=JRrxEABdVSLxZW8Kj7hWdwpoUX386qAF0H_4r6dCUss,1313
33
+ github_agent/ontology/github.ttl,sha256=cMaMCuXMiwVr1vIa9E6zy99tO_IT4HZOXDNB6lNvvSA,8362
34
34
  github_agent/ontology/fixtures/records.json,sha256=EvW1Swrph3DyefmeE2eI0GM0AEKp1v9LrAwiqIbS3Hs,543
35
35
  github_agent/ontology/mappings/source.yaml,sha256=UUL3W4hjSurGhQ_m3lsXaVjWMHPaqyxXPPnAPapGAhw,529
36
36
  github_agent/ontology/migrations/manifest.json,sha256=rfFgIlAt0DHdMDpSq656Bnfs4RNeHgXCHbokya5Rk1w,118
37
- github_agent/ontology/shapes/connector.shacl.ttl,sha256=cJ9VW3uMxrHgrd3-uOB3g09dtUi-1KkEr9KhleSaqxw,3234
37
+ github_agent/ontology/shapes/connector.shacl.ttl,sha256=CXK347X1b7BFLwcIAM0ffueQ9s8YPzCPHPaeWg23FuA,3284
38
38
  github_agent/prompts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  github_agent/prompts/github-mcp-operator.json,sha256=HZVcyK-7TdWT7XKnjmJL2V1XsNhha9PHtJMVj0wT_uo,12687
40
40
  github_agent/prompts/github-mcp-release-manager.json,sha256=Vi4NwiDjI4O_VLntSXzSFidcu_eL4fsI0a41pv6QlvA,6990
@@ -42,7 +42,7 @@ github_agent/prompts/github-mcp-repository-administrator.json,sha256=rkPXgrh3UN5
42
42
  github_agent/prompts/github-mcp-triage-lead.json,sha256=-PZ_ycFLeQRN5hPEBmkqr6WJQQhPmOECUUrzRKXkGF8,4581
43
43
  github_agent/skills/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  github_agent/skills/github-actions-ci-review/SKILL.md,sha256=v_g7ilOldIotyzvizEbgiQqUszNBqcP4BSdtUxxroy4,1998
45
- github_agent/skills/github-agent-development/SKILL.md,sha256=77dGiA9HNulJ0nWu81ppCac7VCP9cpzRi0P5ZUL32yU,3924
45
+ github_agent/skills/github-agent-development/SKILL.md,sha256=5Rd_v1QmXbMo_DC2nQXB2BGQgOUQoEhogyFWvKROuK0,4047
46
46
  github_agent/skills/github-agent-operations/SKILL.md,sha256=sPwGdgGfXZLFsCttOaEaJ7zTzttgNeFItgmB6gcFdPE,2739
47
47
  github_agent/skills/github-backlog-planner/SKILL.md,sha256=xzP7Iyvm9huKF4-XR1JjwIuIjYpJoHfi5PNvW5BqzMU,2631
48
48
  github_agent/skills/github-backlog-planner/references/addressed-heuristics.md,sha256=GoW7Adzm43p7pKlh6U_g2mHtNHrrgdM60EY917384gQ,3413
@@ -68,13 +68,14 @@ github_agent/skills/github-triage-resolver/SKILL.md,sha256=o8EIk-rrDSmeTBn2gl_Qd
68
68
  github_agent/skills/github-triage-resolver/references/resolution-rules.md,sha256=lGPvfLCSHpNIeh2rKWcH2k_2lla3ovgBxzwvtMmyQ-0,4133
69
69
  github_agent/skills/github-triage-resolver/scripts/classify_safe.py,sha256=peh1R5oksZfTwlzWEvKuBLmMBdNwHucwAJYWYA9fVDU,9548
70
70
  github_agent/skills/github-triage-resolver/scripts/gh_write.py,sha256=ZA9xXbjzM-jq1dSFzcZVd1_fKyGeU4mZSAfmX4LeqxY,4129
71
- github_agent-2.4.15.dist-info/licenses/LICENSE,sha256=5ALbh4fIALWVsUhO7q1nFT1bQb-CL9sWKf7p3GgLEG8,1070
71
+ github_agent-2.5.0.dist-info/licenses/LICENSE,sha256=5ALbh4fIALWVsUhO7q1nFT1bQb-CL9sWKf7p3GgLEG8,1070
72
72
  tests/conftest.py,sha256=wbbxNvJTHj5_Ma2ewxkI0--A_CM9KtlMzI_rWN-F82Q,3533
73
73
  tests/test_api_client_endpoints.py,sha256=ykF9UMx3hIbf_dCpecl9uE57FJ-VQH5yw51dUQ1WlVc,6572
74
74
  tests/test_api_validation.py,sha256=eXAKGdqzGyoKFoN4-RmZzCwKBtyK43pVEFliwzQDH2Q,3291
75
75
  tests/test_auth_client_edge_cases.py,sha256=OZjqgLoOQPxDVwqQZMxPG7VIfS6szKUMgABNpvLgKuQ,6440
76
- tests/test_cq_paths.py,sha256=ypZSbpB0gQv8-FT1jtw-ZVwJ5JP2pXaSl2ocRhhT1Mw,1485
76
+ tests/test_cq_paths.py,sha256=yMFO2dayYrBGXPdhqdQfvDlxr7DgboTCSqA9vvhNIK0,1489
77
77
  tests/test_default_content_surfaces.py,sha256=UmgtO78MWki9qmTzZtnNxy47SNVmsjZjz_8dQKQQe58,2455
78
+ tests/test_destructive_declaration.py,sha256=yBDf2HJ9rvVk9skrBR9hTmWVcJNTfjlSsBeEqauPsI0,2751
78
79
  tests/test_fleet_name.py,sha256=L1SuM4w05dbQvyj-eBiw01lKfvI-p2o1oj6dpQxsPIY,1409
79
80
  tests/test_github_agent_api_brute_force_coverage.py,sha256=5jWW6oVU7cmXL2sS3OZ-3gbYGhyjlYPIWqH2rsdF2fw,7347
80
81
  tests/test_github_agent_brute_force_coverage.py,sha256=n5RJyxWfOeZEMXRRx_c48pF9ntN_ai67qyzUKtzoiKQ,4849
@@ -84,7 +85,7 @@ tests/test_ingest_sources.py,sha256=SQFPhf0qqgX_R5sn2NP_5qVzT3x2rqQIATbvHBM7IFs,
84
85
  tests/test_init_dynamics.py,sha256=qX7QPHvM9T7-1fE9clZWHZz2NHG9PddsEu4WmO7dwm8,1840
85
86
  tests/test_kg_ingest.py,sha256=98VEL2pog_8xl_lQa8qGwcPmeszt0BAxJp5AjlcvVUk,9466
86
87
  tests/test_model_fields.py,sha256=NboFxPOtLN-uevE9TLbS4Al-55RbF63PFFTa318gJ40,3374
87
- tests/test_ontology_parent_link.py,sha256=1VZrOLDQAmpXT9Sv1Bc4Q9EA2uC5q6WW1N3pvujcJZU,4062
88
+ tests/test_ontology_parent_link.py,sha256=jE_arQxO9yG0q9B6Hqiwu6K7hCmIx6FWXhysd6KFFDc,4344
88
89
  tests/test_pages.py,sha256=ow_qLRo4IytkSGdQxjxJGoZOnTY0s8MebHFZn_ggElg,10815
89
90
  tests/test_skill_backlog_build_plan.py,sha256=DdvwgZKQnQ-d_SxErxKoTpjOROuCijr4q7CVAqB82BI,4569
90
91
  tests/test_skill_ci_failure_sweep_summarize_runs.py,sha256=lFHXWuIzGHCzHQpBBqF4VSHIfzO6cKVgstZHdXqE7U0,3933
@@ -94,8 +95,8 @@ tests/test_skill_org_remediation_classify_fix_risk.py,sha256=CK43UuLA9ZomajH7EMO
94
95
  tests/test_skill_pr_review_sweep_summarize_prs.py,sha256=NrNaucQvM7K-k1WBcOBKtTGjxJbW16VgTHbC7dSsjm4,3821
95
96
  tests/test_skill_triage_resolver_classify_safe.py,sha256=CNXXf98xa6UYk1xoQyDM6ZSbW_G_WLNMb-oNYUFErcI,9535
96
97
  tests/test_startup.py,sha256=Ix_g69k0tsZbY0-Vkeh8ADWojUdbYwTwwmnM4_hVuCc,1245
97
- github_agent-2.4.15.dist-info/METADATA,sha256=KVjNepnTBdyh4lJds2cMeBP70yT_83GD7TlgHuwxVKs,31841
98
- github_agent-2.4.15.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
99
- github_agent-2.4.15.dist-info/entry_points.txt,sha256=Xs66xjLEy6t408ysVybR_GA4blcThForMZfxAMw4oAw,125
100
- github_agent-2.4.15.dist-info/top_level.txt,sha256=rF1I0e3JiEUPistmGCg9UI1zYzTjg-bzVJ61YgbPrjU,42
101
- github_agent-2.4.15.dist-info/RECORD,,
98
+ github_agent-2.5.0.dist-info/METADATA,sha256=qqjXxLS6Qcmbn4zUWMfAZbl5EXCXyu4HqmU0puBS0gs,31632
99
+ github_agent-2.5.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
100
+ github_agent-2.5.0.dist-info/entry_points.txt,sha256=Xs66xjLEy6t408ysVybR_GA4blcThForMZfxAMw4oAw,125
101
+ github_agent-2.5.0.dist-info/top_level.txt,sha256=rF1I0e3JiEUPistmGCg9UI1zYzTjg-bzVJ61YgbPrjU,42
102
+ github_agent-2.5.0.dist-info/RECORD,,
tests/test_cq_paths.py CHANGED
@@ -35,7 +35,7 @@ def test_state_is_declared_on_the_issue_type() -> None:
35
35
 
36
36
 
37
37
  def test_check_run_extends_pipeline_run() -> None:
38
- assert "rdfs:subClassOf :PipelineRun" in _block("CheckRun")
38
+ assert "rdfs:subClassOf core:PipelineRun" in _block("CheckRun")
39
39
 
40
40
 
41
41
  def test_no_mapping_has_a_null_ontology_class() -> None:
@@ -0,0 +1,86 @@
1
+ """CONN-GITHUB-AGENT-CONNECTOR-CONTENT-R008: destructive operations use the SDK's one declaration and guard."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import importlib
7
+ from unittest.mock import patch
8
+
9
+ import pytest
10
+ import requests
11
+ from fastmcp import Client, FastMCP
12
+
13
+ pytestmark = pytest.mark.spec("CONN-GITHUB-AGENT-CONNECTOR-CONTENT-R008")
14
+
15
+ DECLARED = {
16
+ "github_merge_pull_request",
17
+ "github_update_dependabot_alert",
18
+ "github_pulls_enable_auto_merge",
19
+ }
20
+ CLASSIFIED = {"github_delete_repository", "github_delete_branch"}
21
+
22
+
23
+ def _server() -> FastMCP:
24
+ module = importlib.import_module("github_agent.mcp_server")
25
+ with patch(
26
+ "sys.argv", ["github-mcp", "--transport", "stdio", "--auth-type", "none"]
27
+ ):
28
+ result = module.get_mcp_instance()
29
+ if isinstance(result, FastMCP):
30
+ return result
31
+ return next(value for value in result if isinstance(value, FastMCP))
32
+
33
+
34
+ def test_declared_and_classified_operations_are_destructive_tools_that_ask_first(
35
+ monkeypatch,
36
+ ):
37
+ monkeypatch.delenv("SCION_ALLOW_DESTRUCTIVE", raising=False)
38
+
39
+ async def _run():
40
+ async with Client(_server()) as client:
41
+ tools = {t.name: t for t in await client.list_tools()}
42
+ for name in DECLARED | CLASSIFIED:
43
+ assert tools[name].annotations.destructive_hint is True, name
44
+ assert "confirm" in tools[name].input_schema["properties"], name
45
+ for name, tool in tools.items():
46
+ assert "allow_destructive" not in tool.input_schema["properties"], name
47
+
48
+ asyncio.run(_run())
49
+
50
+
51
+ @pytest.mark.parametrize(
52
+ "name,arguments",
53
+ [
54
+ (
55
+ "github_merge_pull_request",
56
+ {"owner": "o", "repo": "r", "number": 1},
57
+ ),
58
+ (
59
+ "github_delete_branch",
60
+ {"owner": "o", "repo": "r", "branch": "b"},
61
+ ),
62
+ ],
63
+ )
64
+ def test_unconfirmed_call_sends_no_request(name, arguments, monkeypatch):
65
+ monkeypatch.delenv("SCION_ALLOW_DESTRUCTIVE", raising=False)
66
+ monkeypatch.setenv("GITHUB_TOKEN", "test-token")
67
+ sent: list[str] = []
68
+
69
+ def record(self, method, url, **kwargs):
70
+ sent.append(f"{method} {url}")
71
+ raise AssertionError("no request may be made without confirmation")
72
+
73
+ monkeypatch.setattr(requests.Session, "request", record)
74
+
75
+ async def _run():
76
+ async with Client(_server()) as client:
77
+ refused = await client.call_tool(name, arguments, raise_on_error=False)
78
+ assert refused.structured_content["cancelled"] is True
79
+
80
+ asyncio.run(_run())
81
+ assert sent == []
82
+
83
+
84
+ def test_no_connector_local_knob_remains():
85
+ auth = importlib.import_module("github_agent.auth")
86
+ assert not hasattr(auth, "allow_destructive_default")
@@ -30,6 +30,11 @@ PARENT_CLASSES = frozenset(
30
30
  "http://knuckles.team/kg#Workflow",
31
31
  )
32
32
  )
33
+ # The core ontology is addressed under its one HTTPS base; a pack class rolls up to a core class by that IRI.
34
+ CORE_BASE = "https://knuckles-team.github.io/ontology/core#"
35
+ PARENT_CLASSES = PARENT_CLASSES | frozenset(
36
+ CORE_BASE + iri.rsplit("#", 1)[1] for iri in PARENT_CLASSES
37
+ )
33
38
  # Classes for which the parent ontology has no fitting class yet. Each is a candidate for a new
34
39
  # parent class (see the orphan mapping report); a class leaves this set when it gains a parent.
35
40
  PENDING_NEW_PARENT: frozenset[str] = frozenset()