gitlab-api 27.3.13__tar.gz → 27.3.15__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 (88) hide show
  1. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/PKG-INFO +1 -1
  2. gitlab_api-27.3.15/gitlab_api/ontology/access_contracts.ttl +287 -0
  3. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/ontology/certification.json +1 -1
  4. gitlab_api-27.3.15/gitlab_api/skills/gitlab-api-development/SKILL.md +132 -0
  5. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api.egg-info/PKG-INFO +1 -1
  6. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api.egg-info/SOURCES.txt +5 -0
  7. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/pyproject.toml +1 -1
  8. gitlab_api-27.3.15/tests/test_access_contracts.py +75 -0
  9. gitlab_api-27.3.15/tests/test_gitlab_api_development_skill.py +54 -0
  10. gitlab_api-27.3.15/tests/test_pages_workflow.py +52 -0
  11. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/LICENSE +0 -0
  12. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/README.md +0 -0
  13. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/__init__.py +0 -0
  14. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/__main__.py +0 -0
  15. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/__init__.py +0 -0
  16. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_base.py +0 -0
  17. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_environments.py +0 -0
  18. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_issues.py +0 -0
  19. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_merge_requests.py +0 -0
  20. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_other.py +0 -0
  21. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_pipelines.py +0 -0
  22. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_projects.py +0 -0
  23. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_repositories.py +0 -0
  24. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_system.py +0 -0
  25. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_users_groups.py +0 -0
  26. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api/api_client_vulnerabilities.py +0 -0
  27. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/api_client.py +0 -0
  28. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/auth.py +0 -0
  29. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/connector_prep.py +0 -0
  30. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/connector_sources.py +0 -0
  31. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/gitlab_gql.py +0 -0
  32. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/gitlab_input_models.py +0 -0
  33. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/gitlab_response_models.py +0 -0
  34. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/instances.py +0 -0
  35. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/kg_ingest.py +0 -0
  36. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/mcp_config.json +0 -0
  37. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/mcp_server.py +0 -0
  38. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/ontology/__init__.py +0 -0
  39. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/ontology/fixtures/records.json +0 -0
  40. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/ontology/gitlab.ttl +0 -0
  41. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/ontology/mappings/source.yaml +0 -0
  42. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/ontology/migrations/manifest.json +0 -0
  43. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/ontology/shapes/connector.shacl.ttl +0 -0
  44. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/prompts/devops_specialist.json +0 -0
  45. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-api-operations/SKILL.md +0 -0
  46. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-api-operations/agents/openai.yaml +0 -0
  47. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-api-operations/references/catalog.md +0 -0
  48. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-issues/SKILL.md +0 -0
  49. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-issues/WORKFLOW.md +0 -0
  50. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-merge-request-create/SKILL.md +0 -0
  51. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-merge-request-create/WORKFLOW.md +0 -0
  52. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-merge-request-review/SKILL.md +0 -0
  53. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-merge-request-review/WORKFLOW.md +0 -0
  54. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-pipelines/SKILL.md +0 -0
  55. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-pipelines/WORKFLOW.md +0 -0
  56. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-vulnerabilities/SKILL.md +0 -0
  57. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api/skills/gitlab-vulnerabilities/WORKFLOW.md +0 -0
  58. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api.egg-info/dependency_links.txt +0 -0
  59. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api.egg-info/entry_points.txt +0 -0
  60. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api.egg-info/requires.txt +0 -0
  61. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/gitlab_api.egg-info/top_level.txt +0 -0
  62. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/scripts/check_import_safety.py +0 -0
  63. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/scripts/security_contract.py +0 -0
  64. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/setup.cfg +0 -0
  65. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/__init__.py +0 -0
  66. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/conftest.py +0 -0
  67. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_api_wrapper.py +0 -0
  68. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_auth.py +0 -0
  69. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_catalog_edges.py +0 -0
  70. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_connector_prep.py +0 -0
  71. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_cq_paths.py +0 -0
  72. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_fleet_name.py +0 -0
  73. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_gitlab_a2a_validation.py +0 -0
  74. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_gitlab_api_brute_force_coverage.py +0 -0
  75. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_gitlab_gql.py +0 -0
  76. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_gitlab_mcp_validation.py +0 -0
  77. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_gitlab_models.py +0 -0
  78. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_identity_context_scoping.py +0 -0
  79. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_ingest_sources.py +0 -0
  80. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_init_dynamics.py +0 -0
  81. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_instances.py +0 -0
  82. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_kg_ingest.py +0 -0
  83. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_mock_coverage.py +0 -0
  84. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_ontology_parent_link.py +0 -0
  85. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_startup.py +0 -0
  86. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_tool_modes.py +0 -0
  87. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/test_verify_agent.py +0 -0
  88. {gitlab_api-27.3.13 → gitlab_api-27.3.15}/tests/verify_a2a_queries.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitlab-api
3
- Version: 27.3.13
3
+ Version: 27.3.15
4
4
  Summary: GitLab API + MCP Server
5
5
  Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
@@ -0,0 +1,287 @@
1
+ @prefix ac: <https://knuckles-team.github.io/agent-connector-sdk/access#> .
2
+ @prefix gl: <http://knuckles.team/kg#> .
3
+
4
+ # Read contracts for the classes declared by gitlab.ttl. The MCP tools expose
5
+ # both read and write actions, but these mappings are read-only query routes:
6
+ # callers select the listed get action through the operation's action envelope.
7
+ # The source classes stay in GitLab's ontology namespace. No heuristic
8
+ # crosswalk to a hub class is asserted here.
9
+
10
+ gl:gitlabGroupAccess a ac:AccessContract ;
11
+ ac:classIri gl:GitLabGroup ;
12
+ ac:sourceId "gitlab-api" ;
13
+ ac:entity "group" ;
14
+ ac:keyField "id" ;
15
+ ac:accessKind "mcp_tool" ;
16
+ ac:operation "gitlab_groups" ;
17
+ ac:parameter "action", "params_json" ;
18
+ ac:pagination "page" ;
19
+ ac:pushdown "filter", "limit", "sort" ;
20
+ ac:authRef "env://GITLAB_TOKEN" ;
21
+ ac:rateLimitPerMinute 60 ;
22
+ ac:freshnessSeconds 300 ;
23
+ ac:costHint "medium" .
24
+
25
+ gl:gitlabGroupWebUrlBinding a ac:PropertyBinding ;
26
+ ac:contract gl:gitlabGroupAccess ; ac:property gl:webUrl ; ac:field "web_url" .
27
+
28
+ gl:projectAccess a ac:AccessContract ;
29
+ ac:classIri gl:Project ;
30
+ ac:sourceId "gitlab-api" ;
31
+ ac:entity "project" ;
32
+ ac:keyField "id" ;
33
+ ac:accessKind "mcp_tool" ;
34
+ ac:operation "gitlab_projects" ;
35
+ ac:parameter "action", "params_json" ;
36
+ ac:pagination "page" ;
37
+ ac:pushdown "filter", "limit", "sort" ;
38
+ ac:authRef "env://GITLAB_TOKEN" ;
39
+ ac:rateLimitPerMinute 60 ;
40
+ ac:freshnessSeconds 300 ;
41
+ ac:costHint "low" .
42
+
43
+ gl:projectWebUrlBinding a ac:PropertyBinding ;
44
+ ac:contract gl:projectAccess ; ac:property gl:webUrl ; ac:field "web_url" .
45
+
46
+ gl:mergeRequestAccess a ac:AccessContract ;
47
+ ac:classIri gl:MergeRequest ;
48
+ ac:sourceId "gitlab-api" ;
49
+ ac:entity "merge_request" ;
50
+ ac:keyField "id" ;
51
+ ac:accessKind "mcp_tool" ;
52
+ ac:operation "gitlab_merge_requests" ;
53
+ ac:parameter "action", "params_json" ;
54
+ ac:pagination "page" ;
55
+ ac:pushdown "filter", "limit", "sort" ;
56
+ ac:authRef "env://GITLAB_TOKEN" ;
57
+ ac:rateLimitPerMinute 60 ;
58
+ ac:freshnessSeconds 60 ;
59
+ ac:costHint "medium" .
60
+
61
+ gl:mergeRequestIidBinding a ac:PropertyBinding ;
62
+ ac:contract gl:mergeRequestAccess ; ac:property gl:iid ; ac:field "iid" .
63
+
64
+ gl:mergeRequestStateBinding a ac:PropertyBinding ;
65
+ ac:contract gl:mergeRequestAccess ; ac:property gl:state ; ac:field "state" .
66
+
67
+ gl:mergeRequestWebUrlBinding a ac:PropertyBinding ;
68
+ ac:contract gl:mergeRequestAccess ; ac:property gl:webUrl ; ac:field "web_url" .
69
+
70
+ gl:pipelineAccess a ac:AccessContract ;
71
+ ac:classIri gl:Pipeline ;
72
+ ac:sourceId "gitlab-api" ;
73
+ ac:entity "pipeline" ;
74
+ ac:keyField "id" ;
75
+ ac:accessKind "mcp_tool" ;
76
+ ac:operation "gitlab_pipelines" ;
77
+ ac:parameter "action", "params_json" ;
78
+ ac:pagination "page" ;
79
+ ac:pushdown "filter", "limit", "sort" ;
80
+ ac:authRef "env://GITLAB_TOKEN" ;
81
+ ac:rateLimitPerMinute 60 ;
82
+ ac:freshnessSeconds 60 ;
83
+ ac:costHint "medium" .
84
+
85
+ gl:pipelineStatusBinding a ac:PropertyBinding ;
86
+ ac:contract gl:pipelineAccess ; ac:property gl:pipelineStatus ; ac:field "status" .
87
+
88
+ gl:pipelineRefBinding a ac:PropertyBinding ;
89
+ ac:contract gl:pipelineAccess ; ac:property gl:ref ; ac:field "ref" .
90
+
91
+ gl:pipelineShaBinding a ac:PropertyBinding ;
92
+ ac:contract gl:pipelineAccess ; ac:property gl:sha ; ac:field "sha" .
93
+
94
+ gl:pipelineWebUrlBinding a ac:PropertyBinding ;
95
+ ac:contract gl:pipelineAccess ; ac:property gl:webUrl ; ac:field "web_url" .
96
+
97
+ gl:pipelineRunAccess a ac:AccessContract ;
98
+ ac:classIri gl:PipelineRun ;
99
+ ac:sourceId "gitlab-api" ;
100
+ ac:entity "pipeline" ;
101
+ ac:keyField "id" ;
102
+ ac:accessKind "mcp_tool" ;
103
+ ac:operation "gitlab_pipelines" ;
104
+ ac:parameter "action", "params_json" ;
105
+ ac:pagination "page" ;
106
+ ac:pushdown "filter", "limit", "sort" ;
107
+ ac:authRef "env://GITLAB_TOKEN" ;
108
+ ac:rateLimitPerMinute 60 ;
109
+ ac:freshnessSeconds 60 ;
110
+ ac:costHint "medium" .
111
+
112
+ gl:jobAccess a ac:AccessContract ;
113
+ ac:classIri gl:Job ;
114
+ ac:sourceId "gitlab-api" ;
115
+ ac:entity "job" ;
116
+ ac:keyField "id" ;
117
+ ac:accessKind "mcp_tool" ;
118
+ ac:operation "gitlab_jobs" ;
119
+ ac:parameter "action", "params_json" ;
120
+ ac:pagination "page" ;
121
+ ac:pushdown "filter", "limit", "sort" ;
122
+ ac:authRef "env://GITLAB_TOKEN" ;
123
+ ac:rateLimitPerMinute 60 ;
124
+ ac:freshnessSeconds 60 ;
125
+ ac:costHint "medium" .
126
+
127
+ gl:jobStatusBinding a ac:PropertyBinding ;
128
+ ac:contract gl:jobAccess ; ac:property gl:pipelineStatus ; ac:field "status" .
129
+
130
+ gl:jobRefBinding a ac:PropertyBinding ;
131
+ ac:contract gl:jobAccess ; ac:property gl:ref ; ac:field "ref" .
132
+
133
+ gl:jobWebUrlBinding a ac:PropertyBinding ;
134
+ ac:contract gl:jobAccess ; ac:property gl:webUrl ; ac:field "web_url" .
135
+
136
+ gl:checkRunAccess a ac:AccessContract ;
137
+ ac:classIri gl:CheckRun ;
138
+ ac:sourceId "gitlab-api" ;
139
+ ac:entity "job" ;
140
+ ac:keyField "id" ;
141
+ ac:accessKind "mcp_tool" ;
142
+ ac:operation "gitlab_jobs" ;
143
+ ac:parameter "action", "params_json" ;
144
+ ac:pagination "page" ;
145
+ ac:pushdown "filter", "limit", "sort" ;
146
+ ac:authRef "env://GITLAB_TOKEN" ;
147
+ ac:rateLimitPerMinute 60 ;
148
+ ac:freshnessSeconds 60 ;
149
+ ac:costHint "medium" .
150
+
151
+ gl:issueAccess a ac:AccessContract ;
152
+ ac:classIri gl:Issue ;
153
+ ac:sourceId "gitlab-api" ;
154
+ ac:entity "issue" ;
155
+ ac:keyField "id" ;
156
+ ac:accessKind "mcp_tool" ;
157
+ ac:operation "gitlab_issues" ;
158
+ ac:parameter "action", "params_json" ;
159
+ ac:pagination "page" ;
160
+ ac:pushdown "filter", "limit", "sort" ;
161
+ ac:authRef "env://GITLAB_TOKEN" ;
162
+ ac:rateLimitPerMinute 60 ;
163
+ ac:freshnessSeconds 60 ;
164
+ ac:costHint "medium" .
165
+
166
+ gl:issueIidBinding a ac:PropertyBinding ;
167
+ ac:contract gl:issueAccess ; ac:property gl:iid ; ac:field "iid" .
168
+
169
+ gl:issueStateBinding a ac:PropertyBinding ;
170
+ ac:contract gl:issueAccess ; ac:property gl:state ; ac:field "state" .
171
+
172
+ gl:issueWebUrlBinding a ac:PropertyBinding ;
173
+ ac:contract gl:issueAccess ; ac:property gl:webUrl ; ac:field "web_url" .
174
+
175
+ gl:epicAccess a ac:AccessContract ;
176
+ ac:classIri gl:Epic ;
177
+ ac:sourceId "gitlab-api" ;
178
+ ac:entity "epic" ;
179
+ ac:keyField "id" ;
180
+ ac:accessKind "mcp_tool" ;
181
+ ac:operation "gitlab_epics" ;
182
+ ac:parameter "action", "params_json" ;
183
+ ac:pagination "page" ;
184
+ ac:pushdown "filter", "limit", "sort" ;
185
+ ac:authRef "env://GITLAB_TOKEN" ;
186
+ ac:rateLimitPerMinute 60 ;
187
+ ac:freshnessSeconds 300 ;
188
+ ac:costHint "medium" .
189
+
190
+ gl:epicIidBinding a ac:PropertyBinding ;
191
+ ac:contract gl:epicAccess ; ac:property gl:iid ; ac:field "iid" .
192
+
193
+ gl:epicWebUrlBinding a ac:PropertyBinding ;
194
+ ac:contract gl:epicAccess ; ac:property gl:webUrl ; ac:field "web_url" .
195
+
196
+ gl:milestoneAccess a ac:AccessContract ;
197
+ ac:classIri gl:Milestone ;
198
+ ac:sourceId "gitlab-api" ;
199
+ ac:entity "milestone" ;
200
+ ac:keyField "id" ;
201
+ ac:accessKind "mcp_tool" ;
202
+ ac:operation "gitlab_milestones" ;
203
+ ac:parameter "action", "params_json" ;
204
+ ac:pagination "page" ;
205
+ ac:pushdown "filter", "limit", "sort" ;
206
+ ac:authRef "env://GITLAB_TOKEN" ;
207
+ ac:rateLimitPerMinute 60 ;
208
+ ac:freshnessSeconds 300 ;
209
+ ac:costHint "medium" .
210
+
211
+ gl:milestoneStateBinding a ac:PropertyBinding ;
212
+ ac:contract gl:milestoneAccess ; ac:property gl:state ; ac:field "state" .
213
+
214
+ gl:milestoneWebUrlBinding a ac:PropertyBinding ;
215
+ ac:contract gl:milestoneAccess ; ac:property gl:webUrl ; ac:field "web_url" .
216
+
217
+ gl:commitAccess a ac:AccessContract ;
218
+ ac:classIri gl:Commit ;
219
+ ac:sourceId "gitlab-api" ;
220
+ ac:entity "commit" ;
221
+ ac:keyField "id" ;
222
+ ac:accessKind "mcp_tool" ;
223
+ ac:operation "gitlab_commits" ;
224
+ ac:parameter "action", "params_json" ;
225
+ ac:pagination "page" ;
226
+ ac:pushdown "filter", "limit", "sort" ;
227
+ ac:authRef "env://GITLAB_TOKEN" ;
228
+ ac:rateLimitPerMinute 60 ;
229
+ ac:freshnessSeconds 60 ;
230
+ ac:costHint "medium" .
231
+
232
+ gl:commitShaBinding a ac:PropertyBinding ;
233
+ ac:contract gl:commitAccess ; ac:property gl:sha ; ac:field "sha" .
234
+
235
+ gl:commitWebUrlBinding a ac:PropertyBinding ;
236
+ ac:contract gl:commitAccess ; ac:property gl:webUrl ; ac:field "web_url" .
237
+
238
+ gl:branchAccess a ac:AccessContract ;
239
+ ac:classIri gl:Branch ;
240
+ ac:sourceId "gitlab-api" ;
241
+ ac:entity "branch" ;
242
+ ac:keyField "name" ;
243
+ ac:accessKind "mcp_tool" ;
244
+ ac:operation "gitlab_branches" ;
245
+ ac:parameter "action", "params_json" ;
246
+ ac:pagination "page" ;
247
+ ac:pushdown "filter", "limit", "sort" ;
248
+ ac:authRef "env://GITLAB_TOKEN" ;
249
+ ac:rateLimitPerMinute 60 ;
250
+ ac:freshnessSeconds 300 ;
251
+ ac:costHint "low" .
252
+
253
+ gl:branchWebUrlBinding a ac:PropertyBinding ;
254
+ ac:contract gl:branchAccess ; ac:property gl:webUrl ; ac:field "web_url" .
255
+
256
+ gl:releaseAccess a ac:AccessContract ;
257
+ ac:classIri gl:Release ;
258
+ ac:sourceId "gitlab-api" ;
259
+ ac:entity "release" ;
260
+ ac:keyField "tag_name" ;
261
+ ac:accessKind "mcp_tool" ;
262
+ ac:operation "gitlab_releases" ;
263
+ ac:parameter "action", "params_json" ;
264
+ ac:pagination "page" ;
265
+ ac:pushdown "filter", "limit", "sort" ;
266
+ ac:authRef "env://GITLAB_TOKEN" ;
267
+ ac:rateLimitPerMinute 60 ;
268
+ ac:freshnessSeconds 300 ;
269
+ ac:costHint "medium" .
270
+
271
+ gl:runnerAccess a ac:AccessContract ;
272
+ ac:classIri gl:Runner ;
273
+ ac:sourceId "gitlab-api" ;
274
+ ac:entity "runner" ;
275
+ ac:keyField "id" ;
276
+ ac:accessKind "mcp_tool" ;
277
+ ac:operation "gitlab_runners" ;
278
+ ac:parameter "action", "params_json" ;
279
+ ac:pagination "page" ;
280
+ ac:pushdown "filter", "limit", "sort" ;
281
+ ac:authRef "env://GITLAB_TOKEN" ;
282
+ ac:rateLimitPerMinute 60 ;
283
+ ac:freshnessSeconds 300 ;
284
+ ac:costHint "medium" .
285
+
286
+ gl:runnerStateBinding a ac:PropertyBinding ;
287
+ ac:contract gl:runnerAccess ; ac:property gl:state ; ac:field "status" .
@@ -29,5 +29,5 @@
29
29
  "signer": "UNSIGNED-PREVIEW",
30
30
  "signing_public_key": "",
31
31
  "status": "source-validated",
32
- "validated_at": "2026-10-24T15:46:04Z"
32
+ "validated_at": "2026-10-27T03:44:15Z"
33
33
  }
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: gitlab-api-development
3
+ skill_type: skill
4
+ domain: development
5
+ description: >-
6
+ Develop, test, gate, and release the GitLab REST and GraphQL connector. Use
7
+ this skill when changing API mappings, governed MCP tools, authentication,
8
+ tenant selection, KG ingestion, packaged content, or repository gates.
9
+ license: MIT
10
+ tags: [gitlab, rest, graphql, mcp, development, connector, test, gates]
11
+ tier: repository
12
+ metadata:
13
+ author: Genius
14
+ version: '0.1.0'
15
+ ---
16
+
17
+ # gitlab-api development
18
+
19
+ This repository owns the GitLab REST and GraphQL API facades, tenant and
20
+ authentication boundary, action-routed MCP tools, GitLab ontology and KG
21
+ ingestion mappings, and packaged connector content. Shared connector
22
+ contracts, transports, TLS profiles, and credential helpers belong to
23
+ `agent-connector-sdk`; admission, serving, and durable graph state belong to
24
+ their owning repositories. Read `AGENTS.md` before changing code and keep
25
+ credentials, private endpoints, tenant data, and customer records out of
26
+ source, logs, fixtures, and skill content.
27
+
28
+ ## Rapid delivery: the 5-minute contract
29
+
30
+ Specs are already designed. Deliver small, reviewable slices and cite the
31
+ owning spec row in the commit trailer.
32
+
33
+ - Find the owning row first with `git grep -n "<term>" -- specs` and extend the
34
+ existing spec before adding requirement text.
35
+ - Reuse the single `Connector` in `gitlab_api/__init__.py`, the `Api` facade in
36
+ `gitlab_api/api_client.py`, the modular clients under `gitlab_api/api/`, and
37
+ the action dispatch tables in `gitlab_api/mcp_server.py`. Keep GraphQL
38
+ operations in `gitlab_api/gitlab_gql.py`; do not create a second API, MCP,
39
+ authentication, or transport plane.
40
+ - Preserve the multi-tenant resolution in `gitlab_api/instances.py`. A named
41
+ instance, bare URL, or default selection must retain caller entitlement
42
+ checks and the `GITLAB_INSTANCES` shared setting. The legacy
43
+ `GITLAB_URL`/`GITLAB_TOKEN` fallback remains supported.
44
+ - Preserve `GITLAB_URL`, `GITLAB_TOKEN`, `GITLAB_TLS_PROFILE`, and
45
+ `ENABLE_DELEGATION` handling in `gitlab_api/auth.py`. Delegated RFC 8693
46
+ token exchange and fixed credentials stay behind the SDK identity/TLS
47
+ helpers. Never print tokens or add a TLS verification bypass.
48
+ - Keep the REST resource paths, GraphQL typed-operation boundary, action names,
49
+ pagination, and response models stable. Use `run_blocking` for blocking API
50
+ calls from MCP tools and return typed refusal/error envelopes instead of
51
+ bypassing the shared dispatcher. Keep `MCP_TOOL_MODE` (`condensed`,
52
+ `verbose`, or `both`) and each action group's toggle behavior aligned with
53
+ the generated tool surface.
54
+ - Preserve typed KG ingestion through `gitlab_api/kg_ingest.py`, source
55
+ declarations in `gitlab_api/connector_sources.py`, and neutral ontology
56
+ mappings. Project, issue, merge-request, pipeline, job, runner, group, and
57
+ person records use the existing stable IDs and relationship names.
58
+ - Mock HTTP, GraphQL, and authentication responses in local tests; never call a
59
+ live GitLab instance or use live credentials in a gate. Every delivered
60
+ requirement needs a bound focused test. Generated `specs/*/status.json` files
61
+ come from shared hooks; never hand-edit them.
62
+ - Keep `skills/**`, `ontology/**`, `connectors/**`, prompts, and
63
+ `mcp_config.json` coherent with package data and the
64
+ `agent_connector_sdk.connector` entry point (`gitlab-mcp =
65
+ gitlab_api:connector`). Do not add a second publisher or runtime plane.
66
+
67
+ ## Setup and gates
68
+
69
+ Use the pinned environment from `uv sync --locked`, then run the shared gates:
70
+
71
+ ```bash
72
+ uv sync --locked
73
+ uvx pre-commit run --all-files
74
+ uvx pre-commit run --all-files --hook-stage pre-push
75
+ ```
76
+
77
+ For focused feedback, run the smallest affected tests with the locked
78
+ environment, for example:
79
+
80
+ ```bash
81
+ uv run --locked --extra test pytest -q tests/test_gitlab_api_development_skill.py
82
+ uv run --locked --extra test pytest -q tests/test_pages_workflow.py
83
+ uv run --locked --extra test pytest -q tests/test_auth.py tests/test_gitlab_mcp_validation.py
84
+ ```
85
+
86
+ The canonical `.pre-commit-config.yaml` delegates connector-standard, secrets,
87
+ spec, tests-fast, and dependency-readiness to `Knuckles-Team/pipelines`. Do not
88
+ copy those hooks locally or bypass a failing check.
89
+
90
+ ## Connector-specific checks
91
+
92
+ - Keep REST resource paths, GraphQL operation names, action selectors,
93
+ pagination, and Pydantic response normalization stable. Add focused mocked
94
+ request tests for a changed provider path.
95
+ - Keep OIDC token exchange and fixed-token fallback at the existing
96
+ authentication boundary. Resolve TLS policy through the SDK and never bake
97
+ static bearer tokens into the client.
98
+ - Preserve identity-scoped tenant discovery and refusal of an instance the
99
+ caller is not entitled to use. Discovery returns names, URLs, and profile
100
+ state only; it never returns tokens.
101
+ - Keep projects, issues, merge requests, pipelines, jobs, runners, groups, and
102
+ people as the typed records already mapped by `gitlab_api/kg_ingest.py`.
103
+ Ingestion stays best-effort when the graph engine is unavailable.
104
+ - Keep `gitlab_api/skills/`, `gitlab_api/ontology/`,
105
+ `gitlab_api/connectors/`, prompts, and `gitlab_api/mcp_config.json` in package
106
+ data. Keep source metadata tenant-neutral.
107
+ - Documentation is published by the existing Pages workflow and checked-in
108
+ dashboard configuration; source status records under `specs/` are generated
109
+ by shared hooks.
110
+
111
+ ## Packaging and publication
112
+
113
+ `pyproject.toml` declares the `agent_connector_sdk.connector` entry point
114
+ `gitlab-mcp = "gitlab_api:connector"` and packages `skills/**`, `ontology/**`,
115
+ `connectors/**`, prompts, and `mcp_config.json`. When packaged content changes,
116
+ use `uv version --bump patch` and let the lockfile update with the project; add
117
+ the release note to `CHANGELOG.md`. Inspect `uv build` output for
118
+ `gitlab_api/skills/gitlab-api-development/SKILL.md`.
119
+
120
+ The canonical release caller delegates publication and connector rendering to
121
+ the shared pipelines. Do not commit generated Docker artifacts or claim
122
+ package, container, or Pages publication from a local build; require exact
123
+ source hosted evidence and the public artifact.
124
+
125
+ ## Delivery discipline
126
+
127
+ Work in a real Git worktree based on `origin/main`. Inspect the complete diff,
128
+ stage only reviewed paths, and verify `git status --short` after every gate. Do
129
+ not use `git stash`, `git add -A`, or `git add .`; preserve unrelated working
130
+ tree changes. Keep runtime, ontology, status, and generated artifacts outside
131
+ this bounded skill slice unless the owning requirement explicitly requires
132
+ them.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitlab-api
3
- Version: 27.3.13
3
+ Version: 27.3.15
4
4
  Summary: GitLab API + MCP Server
5
5
  Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
@@ -33,6 +33,7 @@ gitlab_api/api/api_client_system.py
33
33
  gitlab_api/api/api_client_users_groups.py
34
34
  gitlab_api/api/api_client_vulnerabilities.py
35
35
  gitlab_api/ontology/__init__.py
36
+ gitlab_api/ontology/access_contracts.ttl
36
37
  gitlab_api/ontology/certification.json
37
38
  gitlab_api/ontology/gitlab.ttl
38
39
  gitlab_api/ontology/fixtures/records.json
@@ -40,6 +41,7 @@ gitlab_api/ontology/mappings/source.yaml
40
41
  gitlab_api/ontology/migrations/manifest.json
41
42
  gitlab_api/ontology/shapes/connector.shacl.ttl
42
43
  gitlab_api/prompts/devops_specialist.json
44
+ gitlab_api/skills/gitlab-api-development/SKILL.md
43
45
  gitlab_api/skills/gitlab-api-operations/SKILL.md
44
46
  gitlab_api/skills/gitlab-api-operations/agents/openai.yaml
45
47
  gitlab_api/skills/gitlab-api-operations/references/catalog.md
@@ -57,6 +59,7 @@ scripts/check_import_safety.py
57
59
  scripts/security_contract.py
58
60
  tests/__init__.py
59
61
  tests/conftest.py
62
+ tests/test_access_contracts.py
60
63
  tests/test_api_wrapper.py
61
64
  tests/test_auth.py
62
65
  tests/test_catalog_edges.py
@@ -65,6 +68,7 @@ tests/test_cq_paths.py
65
68
  tests/test_fleet_name.py
66
69
  tests/test_gitlab_a2a_validation.py
67
70
  tests/test_gitlab_api_brute_force_coverage.py
71
+ tests/test_gitlab_api_development_skill.py
68
72
  tests/test_gitlab_gql.py
69
73
  tests/test_gitlab_mcp_validation.py
70
74
  tests/test_gitlab_models.py
@@ -75,6 +79,7 @@ tests/test_instances.py
75
79
  tests/test_kg_ingest.py
76
80
  tests/test_mock_coverage.py
77
81
  tests/test_ontology_parent_link.py
82
+ tests/test_pages_workflow.py
78
83
  tests/test_startup.py
79
84
  tests/test_tool_modes.py
80
85
  tests/test_verify_agent.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gitlab-api"
7
- version = "27.3.13"
7
+ version = "27.3.15"
8
8
  description = "GitLab API + MCP Server"
9
9
  readme = "README.md"
10
10
  classifiers = [ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: MIT License", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
@@ -0,0 +1,75 @@
1
+ """GitLab's read-only source access contracts stay source-local."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from agent_connector_sdk.access_contract import parse_access_contracts
8
+
9
+
10
+ ROOT = Path(__file__).resolve().parents[1]
11
+ CONTRACTS = ROOT / "gitlab_api" / "ontology" / "access_contracts.ttl"
12
+ KG = "http://knuckles.team/kg#"
13
+
14
+ EXPECTED = {
15
+ "GitLabGroup": ("gitlab_groups", "group", "id"),
16
+ "Project": ("gitlab_projects", "project", "id"),
17
+ "MergeRequest": ("gitlab_merge_requests", "merge_request", "id"),
18
+ "Pipeline": ("gitlab_pipelines", "pipeline", "id"),
19
+ "PipelineRun": ("gitlab_pipelines", "pipeline", "id"),
20
+ "Job": ("gitlab_jobs", "job", "id"),
21
+ "CheckRun": ("gitlab_jobs", "job", "id"),
22
+ "Issue": ("gitlab_issues", "issue", "id"),
23
+ "Epic": ("gitlab_epics", "epic", "id"),
24
+ "Milestone": ("gitlab_milestones", "milestone", "id"),
25
+ "Commit": ("gitlab_commits", "commit", "id"),
26
+ "Branch": ("gitlab_branches", "branch", "name"),
27
+ "Release": ("gitlab_releases", "release", "tag_name"),
28
+ "Runner": ("gitlab_runners", "runner", "id"),
29
+ }
30
+
31
+
32
+ def _contracts():
33
+ return parse_access_contracts(CONTRACTS.read_text(encoding="utf-8"))
34
+
35
+
36
+ def test_every_declared_gitlab_class_has_a_typed_read_contract() -> None:
37
+ contracts = _contracts()
38
+ by_class = {contract.class_iri.rsplit("#", 1)[-1]: contract for contract in contracts}
39
+
40
+ assert set(by_class) == set(EXPECTED)
41
+ for class_name, (operation, entity, key_field) in EXPECTED.items():
42
+ contract = by_class[class_name]
43
+ assert contract.class_iri == KG + class_name
44
+ assert contract.source_id == "gitlab-api"
45
+ assert contract.access_kind == "mcp_tool"
46
+ assert contract.operation == operation
47
+ assert contract.entity == entity
48
+ assert contract.key_field == key_field
49
+ assert contract.parameters == ("action", "params_json")
50
+ assert contract.auth_ref == "env://GITLAB_TOKEN"
51
+ assert contract.pagination == "page"
52
+ assert contract.pushdown == frozenset({"filter", "limit", "sort"})
53
+
54
+
55
+ def test_gitlab_contracts_do_not_promote_draft_crosswalks() -> None:
56
+ contracts = _contracts()
57
+
58
+ assert all(contract.class_iri.startswith(KG) for contract in contracts)
59
+ assert all(
60
+ contract.class_iri not in {KG + "Incident", KG + "SoftwareProject"}
61
+ for contract in contracts
62
+ )
63
+ assert all(contract.source_id == "gitlab-api" for contract in contracts)
64
+
65
+
66
+ def test_gitlab_contract_artifact_is_packaged_under_ontology() -> None:
67
+ assert CONTRACTS.is_file()
68
+
69
+
70
+ def test_gitlab_contract_bindings_use_declared_fields() -> None:
71
+ contracts = {contract.class_iri.rsplit("#", 1)[-1]: contract for contract in _contracts()}
72
+
73
+ assert (KG + "webUrl", "web_url") in contracts["Project"].predicates
74
+ assert (KG + "pipelineStatus", "status") in contracts["Pipeline"].predicates
75
+ assert (KG + "sha", "sha") in contracts["Commit"].predicates
@@ -0,0 +1,54 @@
1
+ """PIPE-CONNSPEC-R125.4: the GitLab API development skill is packaged."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import tomllib
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ ROOT = Path(__file__).resolve().parents[1]
12
+ SKILL = ROOT / "gitlab_api" / "skills" / "gitlab-api-development" / "SKILL.md"
13
+
14
+ pytestmark = pytest.mark.spec("PIPE-CONNSPEC-R125.4")
15
+
16
+
17
+ def test_development_skill_has_rapid_contract_and_package_binding() -> None:
18
+ text = SKILL.read_text(encoding="utf-8")
19
+ frontmatter = text.split("---", 2)[1]
20
+ project = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))
21
+
22
+ assert SKILL.is_file()
23
+ assert re.search(r"^name:\s*gitlab-api-development\s*$", frontmatter, re.M)
24
+ assert re.search(r"^skill_type:\s*skill\s*$", frontmatter, re.M)
25
+ assert "## Rapid delivery: the 5-minute contract" in text
26
+ for term in (
27
+ "gitlab_api/__init__.py",
28
+ "gitlab_api/api_client.py",
29
+ "gitlab_api/api/",
30
+ "gitlab_api/auth.py",
31
+ "gitlab_api/instances.py",
32
+ "gitlab_api/mcp_server.py",
33
+ "gitlab_api/gitlab_gql.py",
34
+ "gitlab_api/kg_ingest.py",
35
+ "gitlab_api/connector_sources.py",
36
+ "GITLAB_URL",
37
+ "GITLAB_TOKEN",
38
+ "GITLAB_TLS_PROFILE",
39
+ "GITLAB_INSTANCES",
40
+ "ENABLE_DELEGATION",
41
+ "MCP_TOOL_MODE",
42
+ "skills/**",
43
+ "ontology/**",
44
+ "uv run --locked --extra test pytest",
45
+ ):
46
+ assert term in text
47
+
48
+ assert "verify=False" not in text
49
+ assert "--no-verify" not in text
50
+ package_data = project["tool"]["setuptools"]["package-data"]["gitlab_api"]
51
+ assert "skills/**" in package_data
52
+ assert project["project"]["entry-points"]["agent_connector_sdk.connector"] == {
53
+ "gitlab-mcp": "gitlab_api:connector"
54
+ }
@@ -0,0 +1,52 @@
1
+ """PIPE-CONNSPEC-R125.3: GitLab API Pages and spec-dashboard contract."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ ROOT = Path(__file__).resolve().parents[1]
12
+ WORKFLOW = ROOT / ".github/workflows/pages.yml"
13
+ DASHBOARD = ROOT / ".github/spec-dashboard.json"
14
+
15
+ pytestmark = pytest.mark.spec("PIPE-CONNSPEC-R125.3")
16
+
17
+
18
+ def test_pages_caller_enables_dashboard_and_rebuilds_for_spec_changes() -> None:
19
+ assert not (ROOT / ".github/workflows/docs.yml").exists()
20
+
21
+ workflow = WORKFLOW.read_text(encoding="utf-8")
22
+
23
+ assert "uses: Knuckles-Team/pipelines/.github/workflows/pages_pipeline.yml@main" in workflow
24
+ assert re.search(r"^ content_source: docs$", workflow, re.MULTILINE)
25
+ assert re.search(r"^ spec_dashboard_enabled: true$", workflow, re.MULTILINE)
26
+ assert re.search(
27
+ r"^ spec_dashboard_config: \.github/spec-dashboard\.json$",
28
+ workflow,
29
+ re.MULTILINE,
30
+ )
31
+ assert re.search(r"^ workflow_dispatch: \{\}$", workflow, re.MULTILINE)
32
+ for path in (
33
+ "'docs/**'",
34
+ "'mkdocs.yml'",
35
+ "'README.md'",
36
+ "'specs/**'",
37
+ "'.github/spec-dashboard.json'",
38
+ "'.github/workflows/pages.yml'",
39
+ ):
40
+ assert path in workflow
41
+
42
+ assert re.search(r"(?m)^ pages: write$", workflow)
43
+ assert re.search(r"(?m)^ id-token: write$", workflow)
44
+
45
+
46
+ def test_dashboard_reads_only_canonical_spec_status_files() -> None:
47
+ config = json.loads(DASHBOARD.read_text(encoding="utf-8"))
48
+
49
+ assert config == {
50
+ "version": 1,
51
+ "sources": [{"glob": "specs/*/status.json", "kind": "spec"}],
52
+ }
File without changes
File without changes
File without changes