gitlab-skill 1.0.0
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.
- package/GITLAB_API_COMPREHENSIVE_GUIDE.md +3885 -0
- package/PRACTICAL_SCRIPTS.md +1351 -0
- package/QUICK_REFERENCE.md +682 -0
- package/README.md +461 -0
- package/SKILL.md +789 -0
- package/SKILL_SETUP.md +50 -0
- package/package.json +42 -0
- package/scripts/install-skill.mjs +119 -0
- package/skill-features/00-auth-and-bootstrap.md +81 -0
- package/skill-features/01-discovery-and-projects.md +73 -0
- package/skill-features/02-repository-and-code.md +101 -0
- package/skill-features/03-issues-and-merge-requests.md +69 -0
- package/skill-features/04-cicd-pipelines-jobs.md +86 -0
- package/skill-features/05-security-and-vulnerabilities.md +125 -0
- package/skill-features/06-graphql-and-glab-playbook.md +68 -0
package/SKILL.md
ADDED
|
@@ -0,0 +1,789 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gitlab-api-operations
|
|
3
|
+
description: Opera GitLab sin UI web usando REST API, GraphQL API y glab CLI. Usar cuando el usuario pida crear, consultar, actualizar o automatizar recursos de GitLab (projects, issues, merge requests, pipelines, repositorio, metadatos) con parametros exactos, tipos de datos y manejo de errores.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitLab API Operations Skill
|
|
7
|
+
|
|
8
|
+
## Contexto de la skill
|
|
9
|
+
|
|
10
|
+
Esta skill define una forma estandar para operar GitLab sin interfaz web, usando:
|
|
11
|
+
- REST API (`/api/v4/...`)
|
|
12
|
+
- GraphQL API (`/api/graphql`)
|
|
13
|
+
- GitLab CLI `glab`
|
|
14
|
+
|
|
15
|
+
Objetivo: responder y ejecutar operaciones con precision operativa (endpoint/metodo, parametros, schema de request, schema de response, tipos de datos y codigos HTTP).
|
|
16
|
+
|
|
17
|
+
Fuente de verdad local para REST: `openapi_v2.yaml`.
|
|
18
|
+
|
|
19
|
+
## Estructura modular recomendada
|
|
20
|
+
|
|
21
|
+
Para escalar contexto sin inflar este archivo, usar referencias por feature:
|
|
22
|
+
|
|
23
|
+
- `skill-features/00-auth-and-bootstrap.md`
|
|
24
|
+
- `skill-features/01-discovery-and-projects.md`
|
|
25
|
+
- `skill-features/02-repository-and-code.md`
|
|
26
|
+
- `skill-features/03-issues-and-merge-requests.md`
|
|
27
|
+
- `skill-features/04-cicd-pipelines-jobs.md`
|
|
28
|
+
- `skill-features/05-security-and-vulnerabilities.md`
|
|
29
|
+
- `skill-features/06-graphql-and-glab-playbook.md`
|
|
30
|
+
|
|
31
|
+
Regla: cargar primero el archivo del feature solicitado y mantener `SKILL.md` como índice operativo.
|
|
32
|
+
|
|
33
|
+
## Referencias extendidas (alto detalle)
|
|
34
|
+
|
|
35
|
+
Para maximizar contexto sin saturar el prompt principal, usar estas guías complementarias:
|
|
36
|
+
|
|
37
|
+
- `GITLAB_API_COMPREHENSIVE_GUIDE.md` (resumen por URL + 25+ ejemplos multi-feature)
|
|
38
|
+
- `QUICK_REFERENCE.md` (cheatsheet operacional)
|
|
39
|
+
- `PRACTICAL_SCRIPTS.md` (scripts end-to-end listos para ejecución)
|
|
40
|
+
- `README.md` (índice general)
|
|
41
|
+
|
|
42
|
+
Prioridad de lectura recomendada:
|
|
43
|
+
1. `SKILL.md` (orquestación)
|
|
44
|
+
2. `skill-features/*.md` (feature específico)
|
|
45
|
+
3. `QUICK_REFERENCE.md` (comandos rápidos)
|
|
46
|
+
4. `GITLAB_API_COMPREHENSIVE_GUIDE.md` y `PRACTICAL_SCRIPTS.md` (profundidad y automatización)
|
|
47
|
+
|
|
48
|
+
## Regla base de exactitud
|
|
49
|
+
|
|
50
|
+
Para cualquier endpoint REST solicitado:
|
|
51
|
+
1. Ubica el path exacto en `openapi_v2.yaml`.
|
|
52
|
+
2. Usa el metodo correcto (`get`, `post`, `put`, `delete`, etc.).
|
|
53
|
+
3. Lista parametros por ubicacion (`path`, `query`, `body`) con `type`, `required`, `enum`, `format`.
|
|
54
|
+
4. Si hay body, sigue su `$ref` en `definitions`.
|
|
55
|
+
5. Para cada respuesta, reporta codigo y schema (`$ref` o tipo inline).
|
|
56
|
+
6. No inventes campos no presentes en OpenAPI.
|
|
57
|
+
|
|
58
|
+
## 1) Autenticacion (siempre primero)
|
|
59
|
+
|
|
60
|
+
### 1.1 REST API
|
|
61
|
+
|
|
62
|
+
Base: `https://<gitlab-host>/api/v4`
|
|
63
|
+
|
|
64
|
+
Metodos soportados por doc:
|
|
65
|
+
- Header: `PRIVATE-TOKEN: <token>`
|
|
66
|
+
- Query: `private_token=<token>`
|
|
67
|
+
|
|
68
|
+
Ejemplo:
|
|
69
|
+
```bash
|
|
70
|
+
curl --request GET \
|
|
71
|
+
--header "PRIVATE-TOKEN: <token>" \
|
|
72
|
+
--url "https://gitlab.example.com/api/v4/projects"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 1.2 GraphQL API
|
|
76
|
+
|
|
77
|
+
Endpoint: `https://<gitlab-host>/api/graphql`
|
|
78
|
+
|
|
79
|
+
Autenticacion soportada:
|
|
80
|
+
- `Authorization: Bearer <token>`
|
|
81
|
+
- `access_token=<oauth_token>` o `private_token=<access_token>` en query string
|
|
82
|
+
|
|
83
|
+
Scopes:
|
|
84
|
+
- `read_api`: consultas (queries)
|
|
85
|
+
- `api`: mutaciones (mutations) y escritura
|
|
86
|
+
|
|
87
|
+
Ejemplo:
|
|
88
|
+
```bash
|
|
89
|
+
curl --request POST \
|
|
90
|
+
--url "https://gitlab.com/api/graphql" \
|
|
91
|
+
--header "Authorization: Bearer <token>" \
|
|
92
|
+
--header "Content-Type: application/json" \
|
|
93
|
+
--data "{\"query\":\"query { currentUser { name } }\"}"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 1.3 CLI (`glab`)
|
|
97
|
+
|
|
98
|
+
Login interactivo:
|
|
99
|
+
```bash
|
|
100
|
+
glab auth login
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Variables utiles:
|
|
104
|
+
- `GITLAB_HOST` o `GL_HOST`
|
|
105
|
+
- `GITLAB_TOKEN`
|
|
106
|
+
- `NO_PROMPT=true` para ejecucion no interactiva
|
|
107
|
+
|
|
108
|
+
Regla: si `glab` no esta autenticado, autenticar antes de cualquier comando operativo.
|
|
109
|
+
|
|
110
|
+
## 2) Convenciones operativas globales
|
|
111
|
+
|
|
112
|
+
- `id` vs `iid`: en REST, muchos recursos se consultan por `iid` dentro del proyecto (issues, merge requests).
|
|
113
|
+
- Paths namespaced deben ir URL-encoded (`group/project` -> `group%2Fproject`).
|
|
114
|
+
- Para fechas ISO con `+`, codificar `%2B`.
|
|
115
|
+
- Paginacion:
|
|
116
|
+
- Offset: `page`, `per_page`
|
|
117
|
+
- Keyset: `pagination=keyset&order_by=...&sort=...` y seguir header `Link`.
|
|
118
|
+
- Troubleshooting: reportar siempre codigo HTTP + mensaje + headers relevantes.
|
|
119
|
+
|
|
120
|
+
## 3) Mapa de capacidades por dominio
|
|
121
|
+
|
|
122
|
+
### A. Instancia y metadatos
|
|
123
|
+
|
|
124
|
+
#### `GET /api/v4/metadata`
|
|
125
|
+
- Path/query params: ninguno.
|
|
126
|
+
- Response:
|
|
127
|
+
- `200` -> `API_Entities_Metadata`
|
|
128
|
+
- `401` -> Unauthorized
|
|
129
|
+
- Tipo `API_Entities_Metadata`:
|
|
130
|
+
- `version: string`
|
|
131
|
+
- `revision: string`
|
|
132
|
+
- `kas: object { enabled: boolean, externalUrl: string, externalK8sProxyUrl: string, version: string }`
|
|
133
|
+
- `enterprise: boolean`
|
|
134
|
+
|
|
135
|
+
#### `GET /api/v4/version` (deprecado)
|
|
136
|
+
- Response:
|
|
137
|
+
- `200` -> `API_Entities_Metadata`
|
|
138
|
+
- `401` -> Unauthorized
|
|
139
|
+
- Nota: preferir `GET /api/v4/metadata`.
|
|
140
|
+
|
|
141
|
+
### B. Proyectos
|
|
142
|
+
|
|
143
|
+
#### `GET /api/v4/projects`
|
|
144
|
+
- Query params clave:
|
|
145
|
+
- `order_by: string` enum `id|name|path|created_at|updated_at|last_activity_at|similarity|star_count|storage_size|repository_size|wiki_size|packages_size`
|
|
146
|
+
- `sort: string` enum `asc|desc`
|
|
147
|
+
- `visibility: string` enum `private|internal|public`
|
|
148
|
+
- `search: string`
|
|
149
|
+
- `min_access_level: integer`
|
|
150
|
+
- `topic: array[string]`
|
|
151
|
+
- `page: integer`, `per_page: integer`
|
|
152
|
+
- Response:
|
|
153
|
+
- `200` -> `array[API_Entities_BasicProjectDetails]`
|
|
154
|
+
- `400` -> Bad request
|
|
155
|
+
- Tipo `API_Entities_BasicProjectDetails` (campos relevantes):
|
|
156
|
+
- `id: integer`
|
|
157
|
+
- `name: string`
|
|
158
|
+
- `path_with_namespace: string`
|
|
159
|
+
- `default_branch: string`
|
|
160
|
+
- `topics: array[string]`
|
|
161
|
+
- `web_url: string`
|
|
162
|
+
- `visibility: string`
|
|
163
|
+
- `created_at: string(date-time)`
|
|
164
|
+
|
|
165
|
+
#### `POST /api/v4/projects`
|
|
166
|
+
- Body schema: `postApiV4Projects`
|
|
167
|
+
- Campos base recomendados:
|
|
168
|
+
- `name: string` (recomendado)
|
|
169
|
+
- `path: string`
|
|
170
|
+
- `default_branch: string`
|
|
171
|
+
- `description: string`
|
|
172
|
+
- `visibility/accesos`: varios enums (`issues_access_level`, `repository_access_level`, etc.)
|
|
173
|
+
- Response:
|
|
174
|
+
- `201` -> `API_Entities_Project`
|
|
175
|
+
- `400|403|404`
|
|
176
|
+
|
|
177
|
+
#### `GET /api/v4/projects/{id}`
|
|
178
|
+
- Path params:
|
|
179
|
+
- `id: string` (ID o path URL-encoded)
|
|
180
|
+
- Query opcionales:
|
|
181
|
+
- `statistics: boolean`
|
|
182
|
+
- `with_custom_attributes: boolean`
|
|
183
|
+
- `license: boolean`
|
|
184
|
+
- Response:
|
|
185
|
+
- `200` -> `API_Entities_ProjectWithAccess`
|
|
186
|
+
|
|
187
|
+
### C. Issues de proyecto
|
|
188
|
+
|
|
189
|
+
#### `GET /api/v4/projects/{id}/issues`
|
|
190
|
+
- Path params:
|
|
191
|
+
- `id: string` requerido
|
|
192
|
+
- Query comunes:
|
|
193
|
+
- `state: string` enum `opened|closed|all`
|
|
194
|
+
- `order_by: string` enum incluye `created_at|updated_at|due_date|priority|weight|title|...`
|
|
195
|
+
- `sort: string` enum `asc|desc`
|
|
196
|
+
- `labels: array[string]`
|
|
197
|
+
- `iids: array[integer]`
|
|
198
|
+
- `author_id: integer`, `assignee_id: integer`
|
|
199
|
+
- `created_after|created_before|updated_after|updated_before: string(date-time)`
|
|
200
|
+
- `page`, `per_page`, `cursor`
|
|
201
|
+
- Response:
|
|
202
|
+
- `200` -> `API_Entities_Issue`
|
|
203
|
+
|
|
204
|
+
#### `POST /api/v4/projects/{id}/issues`
|
|
205
|
+
- Path params:
|
|
206
|
+
- `id: string`
|
|
207
|
+
- Body schema: `postApiV4ProjectsIdIssues`
|
|
208
|
+
- Campos:
|
|
209
|
+
- Requerido: `title: string`
|
|
210
|
+
- Opcionales: `description: string`, `assignee_ids: array[integer]`, `milestone_id: integer`, `labels: array[string]`, `confidential: boolean`, `due_date: string`, `issue_type: string enum (issue|incident|test_case|requirement|task|ticket)`, `weight: integer`
|
|
211
|
+
- Response:
|
|
212
|
+
- `201` -> `API_Entities_Issue`
|
|
213
|
+
|
|
214
|
+
Tipo `API_Entities_Issue` (campos relevantes):
|
|
215
|
+
- `id: integer`, `iid: integer`, `project_id: integer`
|
|
216
|
+
- `title: string`, `description: string`, `state: string`
|
|
217
|
+
- `created_at|updated_at|closed_at: string(date-time)`
|
|
218
|
+
- `labels: array[string]`
|
|
219
|
+
- `web_url: string`
|
|
220
|
+
- `issue_type: string`
|
|
221
|
+
|
|
222
|
+
### D. Merge Requests
|
|
223
|
+
|
|
224
|
+
#### `GET /api/v4/projects/{id}/merge_requests`
|
|
225
|
+
- Path params:
|
|
226
|
+
- `id: string`
|
|
227
|
+
- Query comunes:
|
|
228
|
+
- `state: string` enum `opened|closed|locked|merged|all`
|
|
229
|
+
- `author_id: integer` / `author_username: string`
|
|
230
|
+
- `assignee_id: integer` / `assignee_username: array[string]`
|
|
231
|
+
- `reviewer_id: integer` / `reviewer_username: string`
|
|
232
|
+
- `source_branch: string`, `target_branch: string`
|
|
233
|
+
- `order_by: string`, `sort: string`
|
|
234
|
+
- `search: string`, `iids: array[integer]`
|
|
235
|
+
- `page`, `per_page`
|
|
236
|
+
- Response:
|
|
237
|
+
- `200` -> `array[API_Entities_MergeRequestBasic]`
|
|
238
|
+
- `401|404|422`
|
|
239
|
+
|
|
240
|
+
#### `POST /api/v4/projects/{id}/merge_requests`
|
|
241
|
+
- Body schema: `postApiV4ProjectsIdMergeRequests`
|
|
242
|
+
- Requeridos:
|
|
243
|
+
- `title: string`
|
|
244
|
+
- `source_branch: string`
|
|
245
|
+
- `target_branch: string`
|
|
246
|
+
- Opcionales:
|
|
247
|
+
- `target_project_id: integer`
|
|
248
|
+
- `assignee_ids: array[integer]`
|
|
249
|
+
- `reviewer_ids: array[integer]`
|
|
250
|
+
- `description: string`
|
|
251
|
+
- `labels/add_labels/remove_labels: array[string]`
|
|
252
|
+
- `remove_source_branch: boolean`
|
|
253
|
+
- `allow_collaboration: boolean`
|
|
254
|
+
- `squash: boolean`
|
|
255
|
+
- `merge_after: string`
|
|
256
|
+
- Response:
|
|
257
|
+
- `201` -> `API_Entities_MergeRequest`
|
|
258
|
+
- `400|401|404|409|422`
|
|
259
|
+
|
|
260
|
+
Tipo `API_Entities_MergeRequestBasic` (campos relevantes):
|
|
261
|
+
- `id: integer`, `iid: integer`, `project_id: integer`
|
|
262
|
+
- `title: string`, `description: string`, `state: string`
|
|
263
|
+
- `source_branch: string`, `target_branch: string`
|
|
264
|
+
- `author: object`, `assignees: object`, `reviewers: object`
|
|
265
|
+
- `web_url: string`, `merge_status: string`, `detailed_merge_status: string`
|
|
266
|
+
|
|
267
|
+
### E. Pipelines y Jobs (CI/CD)
|
|
268
|
+
|
|
269
|
+
#### `GET /api/v4/projects/{id}/pipelines`
|
|
270
|
+
- Path params:
|
|
271
|
+
- `id: string`
|
|
272
|
+
- Query comunes:
|
|
273
|
+
- `scope: string` enum `running|pending|finished|branches|tags`
|
|
274
|
+
- `status: string` enum incluye `created|running|success|failed|canceled|...`
|
|
275
|
+
- `ref: string`, `sha: string`, `username: string`
|
|
276
|
+
- `updated_before/after`, `created_before/after: string(date-time)`
|
|
277
|
+
- `order_by: string` enum `id|status|ref|updated_at|user_id`
|
|
278
|
+
- `sort: string` enum `asc|desc`
|
|
279
|
+
- `source: string` enum (`push|web|trigger|schedule|api|...`)
|
|
280
|
+
- `page`, `per_page`
|
|
281
|
+
- Response:
|
|
282
|
+
- `200` -> `array[API_Entities_Ci_PipelineBasic]`
|
|
283
|
+
- `401|403`
|
|
284
|
+
|
|
285
|
+
#### `POST /api/v4/projects/{id}/pipeline`
|
|
286
|
+
- Body schema: `postApiV4ProjectsIdPipeline`
|
|
287
|
+
- Requerido:
|
|
288
|
+
- `ref: string`
|
|
289
|
+
- Opcionales:
|
|
290
|
+
- `variables: array[object { key: string, value: string, variable_type: enum(env_var|file) }]`
|
|
291
|
+
- `inputs: object`
|
|
292
|
+
- Response:
|
|
293
|
+
- `201` -> `API_Entities_Ci_Pipeline`
|
|
294
|
+
- `400|401|403|404`
|
|
295
|
+
|
|
296
|
+
#### `GET /api/v4/projects/{id}/jobs`
|
|
297
|
+
- Query:
|
|
298
|
+
- `scope: array[string]` enum estados de job
|
|
299
|
+
- `ref: string`
|
|
300
|
+
- `page`, `per_page`
|
|
301
|
+
- Response:
|
|
302
|
+
- `200` -> `array[API_Entities_Ci_Job]`
|
|
303
|
+
- `401|403|404`
|
|
304
|
+
|
|
305
|
+
Tipo `API_Entities_Ci_PipelineBasic`:
|
|
306
|
+
- `id: integer`, `iid: integer`, `project_id: integer`
|
|
307
|
+
- `sha: string`, `ref: string`, `status: string`, `source: string`
|
|
308
|
+
- `created_at|updated_at: string(date-time)`
|
|
309
|
+
- `web_url: string`
|
|
310
|
+
|
|
311
|
+
Tipo `API_Entities_Ci_Job`:
|
|
312
|
+
- `id: integer`, `status: string`, `stage: string`, `name: string`, `ref: string`
|
|
313
|
+
- `tag: boolean`, `coverage: number(float)`, `allow_failure: boolean`
|
|
314
|
+
- `created_at|started_at|finished_at: string(date-time)`
|
|
315
|
+
- `duration|queued_duration: number(float)`
|
|
316
|
+
- `pipeline: API_Entities_Ci_PipelineBasic`
|
|
317
|
+
- `web_url: string`
|
|
318
|
+
|
|
319
|
+
### F. Repositorio y archivos
|
|
320
|
+
|
|
321
|
+
#### `GET /api/v4/projects/{id}/repository/tree`
|
|
322
|
+
- Path params:
|
|
323
|
+
- `id: string`
|
|
324
|
+
- Query:
|
|
325
|
+
- `ref: string`
|
|
326
|
+
- `path: string`
|
|
327
|
+
- `recursive: boolean`
|
|
328
|
+
- `pagination: string enum legacy|keyset|none`
|
|
329
|
+
- `page_token: string` (keyset)
|
|
330
|
+
- `page`, `per_page`
|
|
331
|
+
- Response:
|
|
332
|
+
- `200` -> `API_Entities_TreeObject`
|
|
333
|
+
|
|
334
|
+
Tipo `API_Entities_TreeObject`:
|
|
335
|
+
- `id: string`, `name: string`, `type: string`, `path: string`, `mode: string`
|
|
336
|
+
|
|
337
|
+
#### `GET|HEAD|POST|PUT|DELETE /api/v4/projects/{id}/repository/files/{file_path}`
|
|
338
|
+
- Path params:
|
|
339
|
+
- `id: string`
|
|
340
|
+
- `file_path: string` URL-encoded
|
|
341
|
+
- `GET/HEAD`:
|
|
342
|
+
- Query: `ref: string` (requerido)
|
|
343
|
+
- `POST`:
|
|
344
|
+
- Body schema: `postApiV4ProjectsIdRepositoryFilesFilePath`
|
|
345
|
+
- Response `201`
|
|
346
|
+
- `PUT`:
|
|
347
|
+
- Body schema: `putApiV4ProjectsIdRepositoryFilesFilePath`
|
|
348
|
+
- Response `200`
|
|
349
|
+
- `DELETE`:
|
|
350
|
+
- Query requeridos: `branch: string`, `commit_message: string`
|
|
351
|
+
- Query opcionales: `start_branch`, `author_email`, `author_name`, `last_commit_id`
|
|
352
|
+
- Response `204`
|
|
353
|
+
|
|
354
|
+
## 4) GraphQL operativo
|
|
355
|
+
|
|
356
|
+
### Endpoint y forma de uso
|
|
357
|
+
- Endpoint: `/api/graphql`
|
|
358
|
+
- Metodo: `POST`
|
|
359
|
+
- Payload:
|
|
360
|
+
- `query: string`
|
|
361
|
+
- `variables: object` (recomendado para evitar limite de tamano)
|
|
362
|
+
|
|
363
|
+
### Identificadores y tipos
|
|
364
|
+
- `id` en GraphQL normalmente es Global ID (`gid://gitlab/...`)
|
|
365
|
+
- Para project/group/namespace suele usarse `fullPath`
|
|
366
|
+
- Para recursos con IID, usar `projectPath + iid`
|
|
367
|
+
|
|
368
|
+
### Limites relevantes
|
|
369
|
+
- Complejidad maxima: 200 no autenticado, 250 autenticado
|
|
370
|
+
- Tamano maximo de query/mutation: 10,000 caracteres
|
|
371
|
+
- Timeout de request: 30s
|
|
372
|
+
|
|
373
|
+
### Patrones minimos
|
|
374
|
+
|
|
375
|
+
Query por proyecto:
|
|
376
|
+
```graphql
|
|
377
|
+
query($fullPath: ID!) {
|
|
378
|
+
project(fullPath: $fullPath) {
|
|
379
|
+
id
|
|
380
|
+
fullPath
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Mutation por IID:
|
|
386
|
+
```graphql
|
|
387
|
+
mutation($projectPath: ID!, $iid: String!, $locked: Boolean!) {
|
|
388
|
+
issueSetLocked(input: { projectPath: $projectPath, iid: $iid, locked: $locked }) {
|
|
389
|
+
issue { id iid }
|
|
390
|
+
errors
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## 5) CLI (`glab`) operativo
|
|
396
|
+
|
|
397
|
+
Usar `glab` para flujos de terminal sin UI web.
|
|
398
|
+
|
|
399
|
+
### Comandos base
|
|
400
|
+
- Login: `glab auth login`
|
|
401
|
+
- Estado auth: `glab auth status`
|
|
402
|
+
- REST genrico: `glab api /projects`
|
|
403
|
+
- REST con paginacion: `glab api /projects --paginate`
|
|
404
|
+
- GraphQL: `glab api graphql -f query='query { currentUser { username } }'`
|
|
405
|
+
|
|
406
|
+
### Comandos funcionales por dominio
|
|
407
|
+
- Issues: `glab issue ...`
|
|
408
|
+
- Merge Requests: `glab mr ...`
|
|
409
|
+
- Pipelines/Jobs CI: `glab ci ...`, `glab job ...`
|
|
410
|
+
- Releases: `glab release ...`
|
|
411
|
+
- Variables: `glab variable ...`
|
|
412
|
+
|
|
413
|
+
Regla: preferir comandos de alto nivel (`glab mr`, `glab issue`) y usar `glab api` cuando se necesite control exacto de endpoint/payload.
|
|
414
|
+
|
|
415
|
+
## 6) Manejo de errores y troubleshooting
|
|
416
|
+
|
|
417
|
+
Siempre reportar:
|
|
418
|
+
1. Metodo + endpoint exacto
|
|
419
|
+
2. Payload enviado (sin secretos)
|
|
420
|
+
3. Codigo HTTP
|
|
421
|
+
4. Mensaje de error parseado
|
|
422
|
+
5. Siguiente accion sugerida
|
|
423
|
+
|
|
424
|
+
Codigos clave: `400`, `401`, `403`, `404`, `409`, `412`, `422`, `429`, `500`, `503`.
|
|
425
|
+
|
|
426
|
+
Buenas practicas de depuracion:
|
|
427
|
+
- Usar `--include` para headers.
|
|
428
|
+
- Usar `--fail` para detectar error por exit code en curl.
|
|
429
|
+
- Si hay reverse proxy y 404 con paths codificados, validar configuracion para no decodificar `%2F`.
|
|
430
|
+
|
|
431
|
+
## 7) Fuentes de referencia
|
|
432
|
+
|
|
433
|
+
- REST API: https://docs.gitlab.com/api/rest/
|
|
434
|
+
- REST troubleshooting: https://docs.gitlab.com/api/rest/troubleshooting/
|
|
435
|
+
- OpenAPI interactivo: https://docs.gitlab.com/api/openapi/openapi_interactive/
|
|
436
|
+
- GraphQL API: https://docs.gitlab.com/api/graphql/
|
|
437
|
+
- GraphQL examples: https://docs.gitlab.com/api/graphql/examples/
|
|
438
|
+
- GraphQL reference: https://docs.gitlab.com/api/graphql/reference/
|
|
439
|
+
- GitLab CLI: https://docs.gitlab.com/cli/
|
|
440
|
+
- Especificacion local REST: `openapi_v2.yaml`
|
|
441
|
+
|
|
442
|
+
## 8) Portabilidad de la skill (sin subir OpenAPI al repo)
|
|
443
|
+
|
|
444
|
+
Esta skill debe funcionar en dos modos:
|
|
445
|
+
|
|
446
|
+
### Modo A: con `openapi_v2.yaml` local
|
|
447
|
+
- Usar `openapi_v2.yaml` como fuente exacta para endpoint, parametros, tipos y respuestas.
|
|
448
|
+
- No es obligatorio versionarlo en Git.
|
|
449
|
+
|
|
450
|
+
### Modo B: sin `openapi_v2.yaml` en el repo
|
|
451
|
+
- Operar con:
|
|
452
|
+
- este catalogo embebido de endpoints por feature
|
|
453
|
+
- REST docs oficiales
|
|
454
|
+
- GraphQL reference + introspeccion
|
|
455
|
+
- `glab api` para validacion rapida
|
|
456
|
+
- Regla: cuando falte schema exacto, reportar explicitamente `schema no verificado en OpenAPI local` y continuar con endpoint + parametros documentados.
|
|
457
|
+
|
|
458
|
+
### Estructura de distribucion (ambos enfoques)
|
|
459
|
+
- En carpeta compartida: `.cursor/skills/gitlab-api-operations/SKILL.md`
|
|
460
|
+
- En paquete Node: incluir `SKILL.md` en el paquete y copiarlo en postinstall al directorio de skills del usuario/proyecto.
|
|
461
|
+
|
|
462
|
+
## 9) Variables runtime minimas para agentes
|
|
463
|
+
|
|
464
|
+
Definir estas variables antes de operar:
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
export GITLAB_HOST="https://gitlab.com"
|
|
468
|
+
export GITLAB_TOKEN="<personal_access_token>"
|
|
469
|
+
export GITLAB_USER="<username>"
|
|
470
|
+
export TARGET_PROJECT_PATH="grupo/proyecto"
|
|
471
|
+
export TARGET_GROUP_PATH="grupo"
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
Helpers:
|
|
475
|
+
```bash
|
|
476
|
+
export PROJECT_ENC="$(python - <<'PY'
|
|
477
|
+
import os, urllib.parse
|
|
478
|
+
print(urllib.parse.quote(os.environ['TARGET_PROJECT_PATH'], safe=''))
|
|
479
|
+
PY
|
|
480
|
+
)"
|
|
481
|
+
export GROUP_ENC="$(python - <<'PY'
|
|
482
|
+
import os, urllib.parse
|
|
483
|
+
print(urllib.parse.quote(os.environ['TARGET_GROUP_PATH'], safe=''))
|
|
484
|
+
PY
|
|
485
|
+
)"
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## 10) Catalogo ampliado de endpoints por features (ejemplos listos)
|
|
489
|
+
|
|
490
|
+
Nota: todos los ejemplos usan header `PRIVATE-TOKEN`.
|
|
491
|
+
|
|
492
|
+
### 10.1 Descubrimiento y alcance
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
# Proyectos visibles
|
|
496
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
497
|
+
--url "$GITLAB_HOST/api/v4/projects?membership=true&per_page=100"
|
|
498
|
+
|
|
499
|
+
# Proyecto por path
|
|
500
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
501
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC?statistics=true"
|
|
502
|
+
|
|
503
|
+
# Proyectos de un grupo
|
|
504
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
505
|
+
--url "$GITLAB_HOST/api/v4/groups/$GROUP_ENC/projects?include_subgroups=true&per_page=100"
|
|
506
|
+
|
|
507
|
+
# Issues globales accesibles por el usuario autenticado
|
|
508
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
509
|
+
--url "$GITLAB_HOST/api/v4/issues?scope=all&state=opened&per_page=100"
|
|
510
|
+
|
|
511
|
+
# Merge requests globales
|
|
512
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
513
|
+
--url "$GITLAB_HOST/api/v4/merge_requests?scope=all&state=opened&per_page=100"
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### 10.2 Repositorio y codigo
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
# Tree de repositorio
|
|
520
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
521
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/tree?ref=main&recursive=true&pagination=keyset&per_page=100"
|
|
522
|
+
|
|
523
|
+
# Listar ramas
|
|
524
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
525
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/branches?search=feature&per_page=100"
|
|
526
|
+
|
|
527
|
+
# Detalle de rama
|
|
528
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
529
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/branches/main"
|
|
530
|
+
|
|
531
|
+
# Proteger/desproteger rama
|
|
532
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
533
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/branches/main/protect"
|
|
534
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
535
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/branches/main/unprotect"
|
|
536
|
+
|
|
537
|
+
# Commits
|
|
538
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
539
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/commits?ref_name=main&per_page=100"
|
|
540
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
541
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/commits/<sha>"
|
|
542
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
543
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/commits/<sha>/diff"
|
|
544
|
+
|
|
545
|
+
# Comparar ramas
|
|
546
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
547
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/compare?from=main&to=develop&straight=false"
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### 10.3 Archivos en repositorio
|
|
551
|
+
|
|
552
|
+
```bash
|
|
553
|
+
export FILE_PATH_ENC="src%2FREADME.md"
|
|
554
|
+
|
|
555
|
+
# Metadata (HEAD)
|
|
556
|
+
curl --head --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
557
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/files/$FILE_PATH_ENC?ref=main"
|
|
558
|
+
|
|
559
|
+
# Obtener archivo (base64 en response)
|
|
560
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
561
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/files/$FILE_PATH_ENC?ref=main"
|
|
562
|
+
|
|
563
|
+
# Raw
|
|
564
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
565
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/files/$FILE_PATH_ENC/raw?ref=main"
|
|
566
|
+
|
|
567
|
+
# Crear archivo
|
|
568
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
569
|
+
--header "Content-Type: application/json" \
|
|
570
|
+
--data '{"branch":"main","commit_message":"create file","content":"hola","encoding":"text"}' \
|
|
571
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/files/new%2Ffile.txt"
|
|
572
|
+
|
|
573
|
+
# Actualizar archivo
|
|
574
|
+
curl --request PUT --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
575
|
+
--header "Content-Type: application/json" \
|
|
576
|
+
--data '{"branch":"main","commit_message":"update file","content":"nuevo contenido","encoding":"text"}' \
|
|
577
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/files/new%2Ffile.txt"
|
|
578
|
+
|
|
579
|
+
# Eliminar archivo
|
|
580
|
+
curl --request DELETE --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
581
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/repository/files/new%2Ffile.txt?branch=main&commit_message=delete"
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### 10.4 Issues y merge requests
|
|
585
|
+
|
|
586
|
+
```bash
|
|
587
|
+
# Issues de proyecto
|
|
588
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
589
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/issues?state=opened&order_by=updated_at&sort=desc&per_page=100"
|
|
590
|
+
|
|
591
|
+
# Crear issue
|
|
592
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
593
|
+
--header "Content-Type: application/json" \
|
|
594
|
+
--data '{"title":"Bug movil","description":"Detalle tecnico","labels":["bug","mobile"],"issue_type":"issue"}' \
|
|
595
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/issues"
|
|
596
|
+
|
|
597
|
+
# MRs de proyecto
|
|
598
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
599
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/merge_requests?state=opened&scope=all&per_page=100"
|
|
600
|
+
|
|
601
|
+
# Crear MR
|
|
602
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
603
|
+
--header "Content-Type: application/json" \
|
|
604
|
+
--data '{"title":"feat: harden auth","source_branch":"feature/auth","target_branch":"main","remove_source_branch":true,"squash":true}' \
|
|
605
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/merge_requests"
|
|
606
|
+
|
|
607
|
+
# Issues/MRs a nivel grupo
|
|
608
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
609
|
+
--url "$GITLAB_HOST/api/v4/groups/$GROUP_ENC/issues?state=opened&per_page=100"
|
|
610
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
611
|
+
--url "$GITLAB_HOST/api/v4/groups/$GROUP_ENC/merge_requests?state=opened&per_page=100"
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
### 10.5 Miembros, acceso y gobernanza
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
# Miembros del proyecto
|
|
618
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
619
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/members?per_page=100"
|
|
620
|
+
|
|
621
|
+
# Miembros del grupo
|
|
622
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
623
|
+
--url "$GITLAB_HOST/api/v4/groups/$GROUP_ENC/members?per_page=100"
|
|
624
|
+
|
|
625
|
+
# Access requests del proyecto
|
|
626
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
627
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/access_requests"
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### 10.6 CI/CD, pipelines, jobs y variables
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# Pipelines del proyecto
|
|
634
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
635
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/pipelines?status=failed&per_page=100"
|
|
636
|
+
|
|
637
|
+
# Crear pipeline
|
|
638
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
639
|
+
--header "Content-Type: application/json" \
|
|
640
|
+
--data '{"ref":"main","variables":[{"key":"SCAN","value":"true","variable_type":"env_var"}]}' \
|
|
641
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/pipeline"
|
|
642
|
+
|
|
643
|
+
# Pipeline detalle + jobs + variables
|
|
644
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
645
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/pipelines/<pipeline_id>"
|
|
646
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
647
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/pipelines/<pipeline_id>/jobs?per_page=100"
|
|
648
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
649
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/pipelines/<pipeline_id>/variables"
|
|
650
|
+
|
|
651
|
+
# Retry/cancel pipeline
|
|
652
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
653
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/pipelines/<pipeline_id>/retry"
|
|
654
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
655
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/pipelines/<pipeline_id>/cancel"
|
|
656
|
+
|
|
657
|
+
# Jobs y trace
|
|
658
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
659
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/jobs?scope[]=failed&scope[]=success&per_page=100"
|
|
660
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
661
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/jobs/<job_id>/trace"
|
|
662
|
+
|
|
663
|
+
# Variables de proyecto
|
|
664
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
665
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/variables"
|
|
666
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
667
|
+
--header "Content-Type: application/json" \
|
|
668
|
+
--data '{"key":"SEC_SCAN_MODE","value":"strict","masked":false,"protected":false}' \
|
|
669
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/variables"
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### 10.7 Artifacts, releases y webhooks
|
|
673
|
+
|
|
674
|
+
```bash
|
|
675
|
+
# Artifacts por job o por ref
|
|
676
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
677
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/jobs/<job_id>/artifacts"
|
|
678
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
679
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/jobs/artifacts/main/download?job=<job_name>"
|
|
680
|
+
|
|
681
|
+
# Releases
|
|
682
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
683
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/releases?per_page=100"
|
|
684
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
685
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/releases/<tag_name>"
|
|
686
|
+
|
|
687
|
+
# Hooks
|
|
688
|
+
curl --request GET --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
689
|
+
--url "$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/hooks"
|
|
690
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
691
|
+
--header "Content-Type: application/json" \
|
|
692
|
+
--data '{"url":"https://example.com/webhook","push_events":true,"merge_requests_events":true}' \
|
|
693
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/hooks"
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
### 10.8 Seguridad y vulnerabilidades (flujo autonomo)
|
|
697
|
+
|
|
698
|
+
#### A) Endpoints REST de seguridad disponibles en OpenAPI
|
|
699
|
+
|
|
700
|
+
```bash
|
|
701
|
+
# NPM advisory bulk (proyecto)
|
|
702
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
703
|
+
--header "Content-Type: application/json" \
|
|
704
|
+
--data '{"name":"mobilcash-web","version":"1.0.0","requires":{},"dependencies":{}}' \
|
|
705
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/packages/npm/-/npm/v1/security/advisories/bulk"
|
|
706
|
+
|
|
707
|
+
# NPM quick audit (proyecto)
|
|
708
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
709
|
+
--header "Content-Type: application/json" \
|
|
710
|
+
--data '{"name":"mobilcash-web","version":"1.0.0","requires":{},"dependencies":{}}' \
|
|
711
|
+
"$GITLAB_HOST/api/v4/projects/$PROJECT_ENC/packages/npm/-/npm/v1/security/audits/quick"
|
|
712
|
+
|
|
713
|
+
# NPM advisory bulk (grupo)
|
|
714
|
+
curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
|
|
715
|
+
--header "Content-Type: application/json" \
|
|
716
|
+
--data '{"name":"mobilcash-web","version":"1.0.0","requires":{},"dependencies":{}}' \
|
|
717
|
+
"$GITLAB_HOST/api/v4/groups/$GROUP_ENC/-/packages/npm/-/npm/v1/security/advisories/bulk"
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
#### B) GraphQL para vulnerabilidades de proyecto (recomendado)
|
|
721
|
+
|
|
722
|
+
1) Introspeccion minima para descubrir campos reales del schema:
|
|
723
|
+
```bash
|
|
724
|
+
curl --request POST \
|
|
725
|
+
--url "$GITLAB_HOST/api/graphql" \
|
|
726
|
+
--header "Authorization: Bearer $GITLAB_TOKEN" \
|
|
727
|
+
--header "Content-Type: application/json" \
|
|
728
|
+
--data '{"query":"query { __type(name:\"Project\") { fields { name } } }"}'
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
2) Query plantilla para listado de vulnerabilidades (ajustar a schema real):
|
|
732
|
+
```graphql
|
|
733
|
+
query($fullPath: ID!, $first: Int!, $after: String) {
|
|
734
|
+
project(fullPath: $fullPath) {
|
|
735
|
+
vulnerabilities(first: $first, after: $after) {
|
|
736
|
+
nodes {
|
|
737
|
+
id
|
|
738
|
+
title
|
|
739
|
+
severity
|
|
740
|
+
state
|
|
741
|
+
reportType
|
|
742
|
+
confidence
|
|
743
|
+
description
|
|
744
|
+
}
|
|
745
|
+
pageInfo { endCursor hasNextPage }
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
3) Regla de paginacion GraphQL:
|
|
752
|
+
- Iterar mientras `hasNextPage=true`, reenviando `after=endCursor`.
|
|
753
|
+
- Consolidar resultados en JSON unico.
|
|
754
|
+
|
|
755
|
+
#### C) Consolidacion automatica para "lista vulnerabilidades"
|
|
756
|
+
|
|
757
|
+
Flujo sugerido para agentes:
|
|
758
|
+
1. Resolver `project_id` y `project_path`.
|
|
759
|
+
2. Extraer vulnerabilidades via GraphQL (paginado).
|
|
760
|
+
3. En paralelo, obtener:
|
|
761
|
+
- ultimos pipelines fallidos
|
|
762
|
+
- jobs de seguridad (por nombre/etiquetas/artefactos)
|
|
763
|
+
- quick audits/advisories npm si aplica
|
|
764
|
+
4. Normalizar en objeto unico:
|
|
765
|
+
- `summary` (totales por severidad/estado)
|
|
766
|
+
- `findings` (lista detallada)
|
|
767
|
+
- `evidence` (pipeline/job/url/source)
|
|
768
|
+
5. Devolver recomendaciones accionables.
|
|
769
|
+
|
|
770
|
+
## 11) Equivalentes con `glab` para operacion diaria
|
|
771
|
+
|
|
772
|
+
```bash
|
|
773
|
+
# REST
|
|
774
|
+
glab api "/projects/$PROJECT_ENC"
|
|
775
|
+
glab api "/projects/$PROJECT_ENC/issues?state=opened&per_page=100" --paginate
|
|
776
|
+
glab api "/projects/$PROJECT_ENC/merge_requests?state=opened&scope=all&per_page=100" --paginate
|
|
777
|
+
glab api "/projects/$PROJECT_ENC/pipelines?per_page=100" --paginate
|
|
778
|
+
|
|
779
|
+
# GraphQL: introspeccion Project
|
|
780
|
+
glab api graphql -f query='query { __type(name:"Project") { fields { name } } }'
|
|
781
|
+
|
|
782
|
+
# GraphQL: currentUser
|
|
783
|
+
glab api graphql -f query='query { currentUser { id username name } }'
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
Regla operativa:
|
|
787
|
+
- Si existe comando nativo (`glab issue`, `glab mr`, `glab ci`), se puede usar.
|
|
788
|
+
- Para control fino de payload/headers/paginacion, preferir `glab api`.
|
|
789
|
+
|