Docteur CI GitLab

VérifiéPrudence

Diagnostique et corrige les échecs de pipelines GitLab CI, puis durcit .gitlab-ci.yml contre les classes de pannes récurrentes du dépôt.

Spar Skills Guide Bot
DevOpsAvancé
08/11/2026
Claude Code
#gitlab-ci#pipeline-debugging#ci-cd#release-engineering#yaml

Recommandé pour

Synthèse automatique

Diagnostique les échecs de pipelines GitLab CI et durcit le fichier .gitlab-ci.yml en confrontant les symptômes à une taxonomie propre au dépôt des classes de pannes récurrentes.

Points forts

  • Part des faits du pipeline en direct (ID du pipeline, jobs en échec, trace du job) via l’API GitLab plutôt que de deviner à partir du diff de commit.
  • Fournit une taxonomie concrète symptôme → cause racine (jobs de tag jamais exercés, succès silencieux, dérive des chemins d’artefacts, câblage manquant de release:gate).
  • Encode des règles CI propres au dépôt, comme le fait qu’une ancre YAML ne traverse pas les fichiers inclus, d’où l’usage obligatoire de extends ou !reference.
  • Documente les particularités d’authentification et de branche avec glab et l’API brute.

Limites

  • Codé en dur pour le projet GitLab futo-notes/futo-notes et son organisation ci/<group>.yml.
  • Nécessite un accès réseau et un GITLAB_TOKEN valide ; le texte fourni semble par ailleurs tronqué au milieu d’une entrée.
  • La taxonomie est historique et peut manquer des modes de panne réellement nouveaux.
Quand l'utiliser

À utiliser lorsqu’un pipeline GitLab échoue, qu’un job de publication/tag n’a rien publié, ou avant de modifier .gitlab-ci.yml ou de poser un tag de release.

Quand l'éviter

À éviter pour des CI autres que GitLab, ou pour une simple revue de syntaxe YAML sans lien avec le comportement du pipeline de ce dépôt.

Analyse de sécurité

Prudence
Score qualité87/100

No destructive, obfuscated, or exfiltrating actions: the only secret use is an env-var token sent to the legitimate GitLab API endpoint for the repo, and nothing is piped to curl|sh or decoded. It does rely on Bash, network calls, and Edit of CI config, and contemplates pushing a throwaway branch, so it belongs in 'caution' rather than 'safe', but it is a legitimate diagnostics workflow with explicit guardrails (no silent green, ask before tagging).

Points d'attention
  • •Uses Bash/curl with a private GitLab token (`$GITLAB_TOKEN` via `PRIVATE-TOKEN` header) against a remote API; the token is read from the environment rather than hardcoded, which is correct, but the skill does exercise authenticated network access.
  • •Step 4 suggests pushing a temporary branch with a `rules:` override to dry-run tag-only jobs, i.e. it expects the agent to commit/push to the real remote; it does caution to revert before merge and to ask the user before any retag.
  • •Grants Edit on `.gitlab-ci.yml`/`ci/*.yml` and guides CI/publish pipeline changes — high-impact configuration surface, though changes are reviewable and the skill repeatedly insists on verification and ask-first for publishing.
  • •Skill routinely makes authenticated network calls to the GitLab API (gitlab.futo.org) using a personal access token from $GITLAB_TOKEN, and prints job traces — traces could contain secrets if run verbatim on hostile logs, though nothing here exfiltrates data off-site.
  • •Guidance to edit .gitlab-ci.yml and, in Step 4, to temporarily push branch-scoped rule overrides that make tag-only jobs run on a throwaway branch; legitimate but modifies release/publish configuration, so changes must be reverted as instructed.
  • •Suggests ad-hoc shell loops (watch_pipeline, curl | jq, tail on traces) that are read-only, but the skill assumes the token has broad API scope with no least-privilege note.
Comment cette analyse est faite

Exemples

Red pipeline triage
The pipeline on main is red. Get the latest pipeline, list the failed jobs, and show me the tail of the trace for the first failure before proposing a fix.
Tag publish failure
publish:android failed on the v1.2.0 tag build — check the job trace, classify the failure against our known CI failure classes, and patch .gitlab-ci.yml if needed.
Pre-tag CI check
I'm about to tag a release. Run the pre-tag check against the current .gitlab-ci.yml and flag any release-gate or artifact-path issues.

name: ci-doctor description: Diagnose and fix GitLab CI/pipeline failures, and harden .gitlab-ci.yml against this repo's recurring failure classes. Use when the user says "pipeline failed", "CI is red", "the tag build failed", "publish:android/publish:ios failed", "check the pipeline", "why didn't the release go out", "harden CI", or before tagging a release ("pre-tag check"). Also load this BEFORE editing .gitlab-ci.yml for any reason — it encodes the hard rules that past pipeline breakage taught. allowed-tools: Bash, Read, Edit, Grep, Glob

CI Doctor

.gitlab-ci.yml is the most-churned file in this repo — CI firefighting is the largest recurring time cost. This skill turns the historical failure classes into a triage procedure so a red pipeline costs minutes, not an afternoon of push-and-watch.

The root .gitlab-ci.yml holds default, variables, workflow, stages, and an include: list; the jobs live in ci/<group>.yml. A YAML anchor (&x/*x) does not resolve across included files, so a template used from another file goes through extends: or !reference. Text checks read the whole pipeline through scripts/lib/gitlab-ci.mjs.

Project: futo-notes/futo-notes on gitlab.futo.org. The curl calls below use $GITLAB_TOKEN, which always works. glab is usually also present, but whether it can authenticate is per-machine and per-shell — see the auth gotcha in docs/agents/issue-tracker.md before blaming a read.

Step 1 — Get the facts (never guess from the commit diff alone)

API="https://gitlab.futo.org/api/v4/projects/futo-notes%2Ffuto-notes"
H='--header PRIVATE-TOKEN:'"$GITLAB_TOKEN"

# Latest pipelines for a ref (branch or tag)
curl -s $H "$API/pipelines?ref=main&per_page=5" | jq '.[] | {id, status, ref, sha: .sha[0:8], web_url}'

# Jobs in a pipeline — find the failures
curl -s $H "$API/pipelines/<PIPELINE_ID>/jobs?per_page=100" \
  | jq '.[] | select(.status=="failed" or .status=="canceled") | {id, name, stage, status, allow_failure}'

# The job log (the tail is where the truth is)
curl -s $H "$API/jobs/<JOB_ID>/trace" | tail -80

glab ci status / glab ci view work for quick looks; use the raw API when you need job traces or to script a watch loop.

For pipelines on the current branch, glab ci list -b <branch> may parse the branch as a date and fail. Use the encoded project path through glab api:

BRANCH=$(git branch --show-current)
glab api "projects/futo-notes%2Ffuto-notes/pipelines?ref=$BRANCH"

Read the log tail FIRST, then the failing job's script: in its ci/*.yml file, then the diff of the commit that broke it (git log --oneline -5 -- .gitlab-ci.yml ci/).

Step 2 — Classify against the known failure taxonomy

Match the symptom before inventing a novel diagnosis. These classes account for most historical red pipelines here:

| Class | Symptom | Root cause pattern | |---|---|---| | First-contact tag job | A publish/release job fails on its first real run at tag time | Job only executes on tags, so it was never exercised: secrets not propagated (especially into nested VMs like Cirrus), cold caches hitting timeouts, wrong artifact lookup paths | | CWD/path assumption | A step "succeeds" but its effect didn't happen; later step fails mysteriously | GitLab preserves cd across script lines; relative path resolved elsewhere; -f/|| true masked it | | Silent green | "Job succeeded" but nothing was published/uploaded | An error branch special-cased to exit 0 | | Missing release-gate wiring | A test failed but the release published anyway | New test job absent from release:gate.needs (deliberate exceptions: test:audit, test:localization-audit, test:quality-report — see rule 3) | | Artifact-path drift | No files to upload / downstream job can't find inputs | Workspace layout changed; artifacts:paths/lookup globs didn't | | Cache death spiral | Retries keep timing out at the same wall | Caches upload only on_success, so every retry starts cold | | Flake | Same job passes on retry with no change | Fixed timeout or exact-string assertion in a cross-platform test | | Environment skew | Works locally, fails in CI image | Tool version differs (strip/binutils, glibc, NDK, Xcode) — check the job's image:/runner tag |

Step 3 — Fix by the hard rules

Apply the rule for the class; do not just patch the symptom:

  1. Absolute paths only in CI scripts — anchor on $CI_PROJECT_DIR. Never rely on a cd from an earlier line. After any destructive/cleanup line, verify the effect (ls, test -f) rather than trusting -f.
  2. No silent green. Every error path exits non-zero. If a failure is genuinely acceptable, model it as allow_failure: true on the JOB (visible in the UI), never as exit 0 in the script. Assert outcomes: artifact exists, upload count > 0, store accepted the bundle.
  3. Every new test job goes into release:gate.needs in the same commit. Publish jobs start as soon as their own needs succeed, so a red test job that is missing from that list does not hold anything back — that is how v1.4.0 twice came within one job of publishing past a failed test (the release:gate.needs comment in ci/publish.yml names both). Deliberate exceptions: test:audit, test:localization-audit, and test:quality-report are allow_failure: true and left out on purpose (docs/architecture-gates.md) — adding one would turn a reporter into a release blocker.
  4. Secrets into nested environments are passed explicitly (Cirrus VM, docker-in-docker). Never assume a CI variable propagates one level down.
  5. Caches upload when: always so a timed-out job doesn't doom every retry to a cold start.
  6. Flakes get root-caused — wait on conditions/events, not durations; don't assert exact user-facing strings. One commented timeout bump is the ceiling; a second bump on the same job means find the real cause.
  7. Keep MR-blocking vs allow_failure/manual intent explicit in rules: — don't accidentally promote a manual job to blocking or vice versa.

Step 4 — Verify without burning a tag

  • MR-scoped jobs: push a branch/MR and watch that pipeline.
  • Tag-only jobs: never verify by tagging. Options, in order of preference:
    1. Run the job's script locally with the same inputs (most publish scripts are scripts/*.py|mjs|sh — they run outside CI).
    2. Push a temp branch with a one-commit rule override making the job run on that branch (rules: - if: $CI_COMMIT_BRANCH == "ci-dryrun-x"); revert before merge.
    3. For the updater path specifically: node scripts/release-build.mjs e2e rehearses build→sign→serve→verify end-to-end with localdev keys.
  • After a failed tag: fix on main first. Then ask the user before any retag/new tag (publishing is an ask-first action). Repo convention favors bumping the patch version over deleting tags; release creation is retag-safe but partially-published artifacts from the failed run must be accounted for.

Watch loop after pushing a fix (jobs run 10–60 min; poll accordingly):

watch_pipeline() {
  curl -s $H "$API/pipelines/$1" | jq -r '"\(.status)  \(.web_url)"'
  curl -s $H "$API/pipelines/$1/jobs?per_page=100" \
    | jq -r '.[] | "\(.status | .[0:7])\t\(.stage)\t\(.name)"' | sort
}

Pre-tag checklist (run when asked for a "pre-tag check" or before /release tags)

  • [ ] just check green locally
  • [ ] Last main pipeline fully green (not "green with failed-but-allowed jobs you care about")
  • [ ] .gitlab-ci.yml diff since the last tag reviewed against the rules above (git diff $(git describe --tags --abbrev=0) -- .gitlab-ci.yml ci/)
  • [ ] Any NEW tag-only job since the last tag has been exercised (Step 4)
  • [ ] release:gate.needs still lists every test job except the three allow_failure reporters (test:audit, test:localization-audit, test:quality-report), non-blocking by design (grep -A30 'release:gate' ci/publish.yml)
  • [ ] test:audit was yellow because it FOUND something, not because it never ran — its log has no AUDIT-DID-NOT-RUN line (allow_failure renders both the same)
  • [ ] Updater artifacts: signing is the LAST touch on bytes (mesa patch / notarize / Authenticode all happen before .sig) — see docs/release/updater.md

Report format

State: pipeline + failing job(s) with links · the class from the taxonomy · root cause (quote the log line) · the fix and which hard rule it enforces · how it was verified (pipeline link or local run output) · any follow-up risk (e.g. "publish:ios remains unexercised until next tag").

Du fichier au premier essai

Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.

Consulter la source et ses fichiers annexes

Ce téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.

1. Télécharger le fichier

Télécharger SKILL.md

Depuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/gitlab-ci-doctor-mvj1oc4k/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.

Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.

mkdir -p '.skill-downloads/gitlab-ci-doctor-mvj1oc4k' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/gitlab-ci-doctor-mvj1oc4k/download' --output '.skill-downloads/gitlab-ci-doctor-mvj1oc4k/SKILL.md.part' && mv '.skill-downloads/gitlab-ci-doctor-mvj1oc4k/SKILL.md.part' '.skill-downloads/gitlab-ci-doctor-mvj1oc4k/SKILL.md'

2. Vérifier les prérequis

Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.

Outils déclarés par l’auteur (à vérifier dans votre agent) : Bash, Read, Edit, Grep, Glob

Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.

Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.

3. Charger la skill

Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.

Claude Code
test -f '.skill-downloads/gitlab-ci-doctor-mvj1oc4k/SKILL.md' && test -s '.skill-downloads/gitlab-ci-doctor-mvj1oc4k/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/ci-doctor' && cp -R '.skill-downloads/gitlab-ci-doctor-mvj1oc4k' '.claude/skills/ci-doctor'

OpenSkills

OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.

Installation officielle d’OpenSkills
openskills install './.skill-downloads/gitlab-ci-doctor-mvj1oc4k'

openskills read 'gitlab-ci-doctor-mvj1oc4k'

La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.

Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.

openskills sync

Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.

4. Faire un premier essai

Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :

Lis .skill-downloads/gitlab-ci-doctor-mvj1oc4k/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.

Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.

Skills similaires