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/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
+