Merge pull request 'fix(ci): e2e DinD par DNS réseau — fin du blocage 'Start ObsiGate'' (#60) from fix/ci-e2e-resseau-dns into main
This commit was merged in pull request #60.
This commit is contained in:
+29
-17
@@ -12,7 +12,7 @@ on:
|
||||
jobs:
|
||||
# ── Lint ──────────────────────────────────────────────────────────
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ci-deepin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
# ── Tests ─────────────────────────────────────────────────────────
|
||||
test:
|
||||
needs: lint
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ci-deepin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
|
||||
# ── Security scan ─────────────────────────────────────────────────
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ci-deepin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -209,7 +209,7 @@ jobs:
|
||||
# ── Docker build ──────────────────────────────────────────────────
|
||||
build:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ci-deepin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -252,7 +252,7 @@ jobs:
|
||||
# ── E2E Tests (Playwright) ─────────────────────────────────────────
|
||||
e2e:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ci-deepin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -272,7 +272,13 @@ jobs:
|
||||
- name: Start ObsiGate
|
||||
run: |
|
||||
docker rm -f obsigate-e2e 2>/dev/null || true
|
||||
docker create --name obsigate-e2e -p 2029:8080 \
|
||||
# DinD robuste : PAS de port publié (les ports 2029 fuités par des
|
||||
# runs antérieurs font échouer « docker start », et l'IP passerelle
|
||||
# du job n'est pas toujours joignable → boucle de health curls sans
|
||||
# timeout qui pendaient 150 s chacun). À la place, l'app est
|
||||
# rattachée au réseau du job et jointable par nom DNS embarqué.
|
||||
JOBNET=$(docker inspect -f '{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}' "$(hostname)" 2>/dev/null | awk '{print $1}')
|
||||
docker create --name obsigate-e2e \
|
||||
-v $(pwd)/test_vault:/vaults/TestVault \
|
||||
-v $(pwd)/test_dir:/vaults/TestDir \
|
||||
-e VAULT_1_NAME=TestVault \
|
||||
@@ -288,17 +294,22 @@ jobs:
|
||||
# fixtures avant le démarrage (l'indexeur scanne au démarrage).
|
||||
docker cp test_vault/. obsigate-e2e:/vaults/TestVault
|
||||
docker cp test_dir/. obsigate-e2e:/vaults/TestDir
|
||||
if [ -n "$JOBNET" ]; then docker network connect "$JOBNET" obsigate-e2e || true; fi
|
||||
docker start obsigate-e2e
|
||||
# Le port publié est joignable via l'IP de la passerelle (localhost
|
||||
# du job container ne voit pas le port publié sur l'hôte).
|
||||
GW=$(ip route show default | awk '{print $3}' || echo 172.17.0.1)
|
||||
echo "Gateway IP: $GW"
|
||||
# Wait for health check
|
||||
for i in $(seq 1 30); do
|
||||
if curl -sf "http://$GW:2029/api/health"; then echo "Health OK"; break; fi
|
||||
if [ -n "$JOBNET" ]; then
|
||||
APP_URL="http://obsigate-e2e:8080"
|
||||
else
|
||||
echo "Réseau du job introuvable (JOBNET vide) — impossible de localiser l'app sans port publié"
|
||||
exit 1
|
||||
fi
|
||||
echo "APP_URL: $APP_URL"
|
||||
# --max-time : ne JAMAIS pendre sans timeout (bug d'origine : curls
|
||||
# sans timeout = 150 s × 31 tentatives, job « bloqué »).
|
||||
for i in $(seq 1 40); do
|
||||
if curl -sf --max-time 3 "$APP_URL/api/health"; then echo "Health OK"; break; fi
|
||||
sleep 1
|
||||
done
|
||||
curl -sf "http://$GW:2029/api/health" >/dev/null || { echo "App not reachable at $GW:2029"; exit 1; }
|
||||
curl -sf --max-time 5 "$APP_URL/api/health" >/dev/null || { echo "App not reachable at $APP_URL"; docker logs --tail 40 obsigate-e2e; exit 1; }
|
||||
# Les fixtures sont copiées via `docker cp` en root → rendre le vault
|
||||
# inscriptible par l'utilisateur non-root de l'app (UID 1000), sinon
|
||||
# toute création/édition de fichier renvoie 403 « Vault is read-only ».
|
||||
@@ -306,9 +317,10 @@ jobs:
|
||||
|
||||
- name: Run E2E tests
|
||||
run: |
|
||||
GW=$(ip route show default | awk '{print $3}' || echo 172.17.0.1)
|
||||
echo "Using BASE_URL=http://$GW:2029"
|
||||
BASE_URL="http://$GW:2029" npx playwright test --project=chromium-desktop --reporter=list
|
||||
BASE_URL="http://obsigate-e2e:8080"
|
||||
docker exec obsigate-e2e true >/dev/null 2>&1 || { echo "obsigate-e2e n'est pas en marche"; exit 1; }
|
||||
echo "Using BASE_URL=$BASE_URL"
|
||||
BASE_URL="$BASE_URL" npx playwright test --project=chromium-desktop --reporter=list
|
||||
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
|
||||
+1
-1
@@ -8493,7 +8493,7 @@ body.popup-mode .content-area {
|
||||
box-shadow: 0 2px 16px rgba(0,0,0,0.35);
|
||||
width: fit-content;
|
||||
max-width: 95%;
|
||||
z-index: 50;
|
||||
z-index: 66; /* au-dessus de .draco-spark-flottant (65) sinon la barre flottante DRACO intercepte les clics des flèches de recherche */
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.results-bar-count {
|
||||
|
||||
@@ -25,7 +25,7 @@ async function login(page) {
|
||||
await page.click('#login-btn');
|
||||
}
|
||||
// Wait until app init() resolved (all handlers bound).
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
}
|
||||
|
||||
async function openFile(page, vault, filePath) {
|
||||
|
||||
@@ -28,7 +28,7 @@ async function login(page) {
|
||||
await page.fill('#login-password', CREDS.password);
|
||||
await page.click('#login-btn');
|
||||
}
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
}
|
||||
|
||||
async function authEnabled(page) {
|
||||
|
||||
@@ -26,7 +26,7 @@ async function login(page) {
|
||||
await page.fill('#login-password', CREDS.password);
|
||||
await page.click('#login-btn');
|
||||
}
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
}
|
||||
|
||||
async function openFile(page, vault, filePath) {
|
||||
|
||||
@@ -25,7 +25,7 @@ async function login(page) {
|
||||
await page.fill('#login-password', CREDS.password);
|
||||
await page.click('#login-btn');
|
||||
}
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
}
|
||||
|
||||
async function openFile(page, vault, filePath) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { test, expect } from '@playwright/test';
|
||||
|
||||
async function boot(page) {
|
||||
await page.goto('/');
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
await page.waitForSelector('#dashboard-home, #search-input', { timeout: 15000 });
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const BASE = process.env.BASE_URL || 'http://localhost:2029';
|
||||
async function goHome(page) {
|
||||
await page.goto(BASE);
|
||||
// Wait until app init() resolved (all handlers bound, incl. search).
|
||||
await page.waitForFunction(() => (window as any).__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
await page.waitForSelector('#dashboard-home, #search-input', { timeout: 15000 });
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ async function login(page) {
|
||||
await page.fill('#login-password', CREDS.password);
|
||||
await page.click('#login-btn');
|
||||
}
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
}
|
||||
|
||||
async function openFile(page, vault, filePath) {
|
||||
|
||||
@@ -57,7 +57,7 @@ async function login(page) {
|
||||
await page.fill('#login-password', process.env.OBSIGATE_PASS || 'test123');
|
||||
await page.click('#login-btn');
|
||||
}
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
}
|
||||
|
||||
async function openFixture(page) {
|
||||
|
||||
@@ -117,7 +117,7 @@ test.describe('XSS — lecteur markdown (BUG-021)', () => {
|
||||
await api(request, 'POST', `/api/file/${VAULT}`, { path: XSS_FILE, content: `${XSS_BODY}\n` });
|
||||
|
||||
await page.goto(BASE);
|
||||
await page.waitForFunction(() => window.__OBSIGATE_BOOTED === true, { timeout: 20000 });
|
||||
await page.waitForFunction(() => document.readyState === 'complete' && !!document.querySelector('.tree-item'), { timeout: 20000 });
|
||||
await openFile(page, VAULT, XSS_FILE);
|
||||
|
||||
const content = page.locator('#content-area');
|
||||
|
||||
Reference in New Issue
Block a user