Este documento contiene las soluciones completas de las 4 misiones, las explicaciones línea a línea de los workflows suministrados, las reparaciones de las 3 averías y las respuestas a las preguntas de reflexión.
Ábrelo solo después de haberlo intentado de verdad. Leer la solución antes de haber tanteado es perderse el 80 % del aprendizaje.
config.jsonEjemplo de archivo válido:
{
"titre": "Portfolio de <votre nom>",
"sous_titre": "Deploiement automatique via GitHub Actions",
"couleur_fond": "#7c3aed",
"couleur_texte": "#f8fafc",
"couleur_accent": "#22d3ee",
"auteur": "<Votre Nom>",
"version": "1.0.0"
}Puntos a respetar:
titre, sous_titre, couleur_fond, couleur_texte, couleur_accent, auteur, version) son obligatorias.#RRGGBB (6 caracteres hexadecimales después del #).Validación local:
python .\outils\build.pyDebe mostrar OK dist/index.html genere y OK dist/css/style.css genere. Cualquier error ERREUR : detiene el script y bloqueará después el workflow GitHub.
Paleta sugerida para probar el bucle en la misión 2:
| Color | Fondo | Texto | Acento |
|---|---|---|---|
| Noche oscura | #0f172a | #f1f5f9 | #38bdf8 |
| Violeta vivo | #7c3aed | #f8fafc | #22d3ee |
| Rojo vivo | #dc2626 | #fef2f2 | #facc15 |
| Verde bosque | #16a34a | #f0fdf4 | #fbbf24 |
| Azul océano | #0891b2 | #ecfeff | #f472b6 |
deployer-pages.ymlname: Deployer sur GitHub Pages # nombre que aparece en la UI ActionsEste nombre es puramente cosmético — ayuda a situar el workflow en la pestaña Actions del repositorio.
on:
push:
branches: [main]
workflow_dispatch:Dos disparadores:
main (el caso normal).permissions:
contents: read
pages: write
id-token: writeEl trío mágico de Pages. Sin esas tres líneas, se obtiene Resource not accessible by integration en el job deployer (es exactamente la avería 1 de la misión 3):
contents: read — permite a actions/checkout@v4 leer el código.pages: write — autoriza a actions/deploy-pages@v4 a publicar.id-token: write — necesario para la autenticación OIDC entre el runner y el servicio Pages.concurrency:
group: pages
cancel-in-progress: falseSi dos git push llegan casi a la vez, GitHub Actions no lanza dos despliegues en paralelo sobre el mismo grupo pages — los runs se ejecutan uno detrás de otro. cancel-in-progress: false = se deja terminar el run en curso antes de arrancar el siguiente. Es crucial para Pages: dos publicaciones simultáneas producen estados incoherentes.
jobs:
construire:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # 1. recuperar el código
- uses: actions/setup-python@v5 # 2. instalar Python
with:
python-version: "3.12"
- run: python outils/build.py # 3. generar dist/
- uses: actions/upload-pages-artifact@v3 # 4. preparar el artefacto
with:
path: dist # <-- IMPORTANTE: carpeta a publicarCuatro pasos secuenciales. Si uno falla, los siguientes no se ejecutan.
deployer:
needs: construire # espera a que "construire" acierte
environment:
name: github-pages # entorno oficial Pages
url: ${{ steps.publication.outputs.page_url }} # muestra la URL en la UI
steps:
- uses: actions/deploy-pages@v4
id: publicationEl job deployer espera explícitamente a construire gracias a needs:. Al final, la UI de GitHub muestra un enlace clicable hacia https://<tu>.github.io/<repo>/.
verifier-config.ymlon:
pull_request:
branches: [main]
push:
branches-ignore: [main]Se dispara en PR hacia main y en push hacia cualquier rama salvo main. El objetivo: validar antes de que el código se fusione. Nota que se excluye main del push: — si no, se duplicaría el trabajo con deployer-pages.yml.
El resto de los pasos es idéntico a deployer-pages.yml salvo que no se publica: basta con verificar que dist/ se genera sin error.
Secuencia a reproducir dos veces:
# --- Iteración 1: fondo violeta ---
# Edita site/config.json : "couleur_fond": "#7c3aed"
git add site/config.json
git commit -m "fond violet"
git push
# Esperar ~40 s -> abrir https://<tu>.github.io/<repo>/ -> fondo violeta
# --- Iteración 2: fondo rojo ---
# Edita site/config.json : "couleur_fond": "#dc2626"
git add site/config.json
git commit -m "fond rouge"
git push
# Esperar ~40 s -> abrir la misma URL -> fondo rojoComprobaciones a incluir en el informe:
git log --oneline: muestra los 2 commits con sus SHA cortos.Deployer sur GitHub Pages están verdes.Diff del correctivo en .github/workflows/casse-1-permissions-manquantes.yml:
name: Casse 1 - Permissions manquantes
on:
push:
branches: [main]
workflow_dispatch:
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
concurrency:
group: pages
cancel-in-progress: false
jobs:
...Diagnóstico escrito a poner en el informe:
Sin el bloque permissions:, GitHub otorga al workflow solo contents: read (lectura del código) — no el permiso de publicar en Pages. La action actions/deploy-pages@v4 reclama explícitamente pages: write e id-token: write (token OIDC). De ahí el error Resource not accessible by integration (403 Forbidden) en el job deployer.
Regla de seguridad: se da el mínimo de permissions posible, pero no menos. El principio del menor privilegio aplicado al CI/CD.
Diff del correctivo:
name: Casse 2 - Declencheur errone
on:
- pushh:
+ push:
branches: [main]Diagnóstico escrito a poner en el informe:
GitHub Actions no señala los disparadores desconocidos en on: — los ignora en silencio. Un simple pushh (con dos h) hace que ningún run se dispare: no se ve error, no se ve nada en la pestaña Actions.
¿Cómo se descubre la avería? Se empuja un commit, se va a Actions, se constata que ningún run aparece para este workflow. El único indicio es la ausencia.
Truco anti-trampa: un Run workflow rápido (botón manual, disponible si está workflow_dispatch:) verifica que el workflow en sí es sintácticamente válido. El workflow_dispatch: funciona con independencia de push:.
Diff del correctivo:
- name: Preparer le dossier a publier
uses: actions/upload-pages-artifact@v3
with:
- path: public
+ path: distDiagnóstico escrito a poner en el informe:
outils/build.py escribe sistemáticamente en dist/ (constante DIST = RACINE / "dist" en el código Python). El workflow pedía path: public — una carpeta que no existe. De ahí:
Error: Path does not exist: ./publicactions/upload-pages-artifact@v3 verifica la existencia de la carpeta antes de crear el artefacto y falla de inmediato si la ruta es falsa. La buena práctica: hacer siempre que el workflow apunte a la carpeta exacta que produce el script de build.
README.mdEn el README.md de tu repositorio GitHub (en la raíz, no en la carpeta projet14-github-actions-pages-tp/ del curso), añade:
# Mi sitio portfolio

Sitio publicado: https://<tu>.github.io/<repo>/El badge se pone verde si el último run ha pasado, rojo si no. Se actualiza solo.
config.json inválidogit checkout -b test-config-cassee
# Editar site/config.json y sustituir "couleur_fond": "#0f172a" por "couleur_fond": "rouge"
git add site/config.json
git commit -m "test : couleur invalide"
git push -u origin test-config-cassee
# Luego en GitHub: abrir una PR de test-config-cassee hacia mainEl workflow Verifier la configuration se dispara, build.py grita:
ERREUR : couleur_fond doit etre au format #RRGGBB (recu : 'rouge')La PR muestra un cuadrado rojo y el botón Merge pull request queda bloqueado si has configurado la protección de rama (Settings → Branches → Add rule → Require status checks to pass).
.github/workflows/notifier.yml:
name: Notifier une URL
on:
workflow_dispatch:
jobs:
notifier:
runs-on: ubuntu-latest
steps:
- name: Ping du webhook
env:
URL: ${{ secrets.URL_WEBHOOK }}
run: |
curl -X POST "$URL" \
-H "Content-Type: application/json" \
-d '{"texte":"Un utilisateur a declenche notifier.yml"}'El secreto URL_WEBHOOK se define en Settings → Secrets and variables → Actions → New repository secret. Nunca aparecerá en los logs: GitHub enmascara automáticamente cualquier valor que coincida con un secreto.
1. on: push sin branches: — ¿cuándo se dispara?
Se dispara en cada push en todas las ramas. Rara vez es deseable: un git push en una rama de feature en desarrollo lanzará un despliegue Pages en producción. Siempre limitar con branches: [main] o una lista explícita.
2. ¿Por qué id-token: write es necesario para Pages? ¿Para qué sirve el token OIDC?
actions/deploy-pages@v4 usa OIDC (OpenID Connect) para probar al servicio Pages que la petición viene de un run GitHub Actions autorizado, sin usar contraseña ni PAT (Personal Access Token). El token OIDC es efímero (vida limitada al run) y firmado por GitHub — más seguro que un secreto estático. id-token: write autoriza al runner a generar ese token para este workflow.
3. Dos pushes simultáneos en main — ¿qué hace concurrency?
Sin concurrency, GitHub lanza dos workflows en paralelo. El primero termina su upload de artefacto, el segundo arranca su propio upload, y Pages puede recibir las dos publicaciones en desorden → el orden final ya no está garantizado. Con concurrency: { group: pages, cancel-in-progress: false }, los dos runs se serializan: el segundo espera a que el primero termine. cancel-in-progress: true tendría otro efecto — cancelar el run en curso en cuanto arranca uno nuevo, útil para un rebuild ultra-rápido pero peligroso para Pages.
4. ¿Puede un secreto aparecer en los logs?
GitHub enmascara automáticamente cualquier valor registrado como secreto: aparece como *** en los logs. Pero si transformas el secreto (por ejemplo echo "$SECRET" | base64), el enmascaramiento ya no se aplica al valor transformado. Regla: nunca transformes un secreto en un run:, úsalo tal cual vía env: y pásalo directamente a la herramienta (aquí curl).
5. ¿Por qué conservar los dos workflows deployer-pages.yml y verifier-config.yml?
deployer-pages.yml publica en main: es el workflow de entrega. Solo corre después de un merge.verifier-config.yml valida en las ramas de feature y en las PR: es el workflow de prevención. Impide que un config.json roto llegue a main.Los dos forman una red de dos capas: la verificación bloquea aguas arriba, el despliegue entrega aguas abajo. Es el patrón CI (Continuous Integration) + CD (Continuous Deployment).
6. ¿Qué pasaría si build.py creara un archivo historique.log?
Nada duradero. El runner es una VM efímera destruida al final del run. El archivo desaparecería con la VM. Para conservar un historial entre runs, habría que commitearlo en el repositorio (regular, ensucia el repo), guardarlo en un artefacto con actions/upload-artifact (vida máxima 90 días), o enviarlo a un servicio externo (S3, Postgres, etc.).
| Síntoma | Causa probable | Solución |
|---|---|---|
Resource not accessible by integration | Bloque permissions: ausente o incompleto | Añadir pages: write + id-token: write |
| Ningún run se dispara | Errata en on: (pushh:, pull_requests:) | Verificar la ortografía de las claves YAML |
Path does not exist: ./xxx | La ruta en upload-pages-artifact.path: no coincide con la carpeta de salida de build.py | Verificar path: = dist |
| La página publicada muestra el contenido antiguo | Caché del navegador | Ctrl+Shift+R para una recarga dura |
| El primer despliegue tarda > 5 min | Propagación DNS de GitHub Pages | Normal la primera vez, ~40 s después |
Workflow rojo en el paso python outils/build.py | config.json inválido | Lanzar python .\outils\build.py en local para ver el error exacto |
| El workflow corre pero la URL devuelve 404 | Source Pages sigue en modo «Deploy from a branch» | Pasar a GitHub Actions en Settings → Pages |
| Dos runs Pages a la vez producen un contenido incoherente | concurrency: ausente | Añadir el bloque concurrency: { group: pages } |
El profesor abre tres pestañas:
config.json, presencia de .github/workflows/ con al menos los 3 workflows corregidos (los originales deployer-pages.yml y verifier-config.yml + las 3 averías reparadas).Deployer sur GitHub Pages (misión 2), más los runs de la misión 3 (antes/después de la reparación).https://<tu>.github.io/<repo>/ — debe mostrarse con tus colores personalizados y un SHA reciente.Luego lee tu RAPPORT.md:
Un informe limpio + un repositorio bien estructurado = nota alta fácil. La dificultad no es técnica, está en el rigor de la demostración.
Curso creado por el Dr. Haythem REHOUMA — Desarrollo y despliegue de soluciones de datos