- Python 98.2%
- TypeScript 1%
- Dockerfile 0.6%
- HTML 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
## Summary
- `e2e/accueil.spec.ts`'s `$("main p")` matched both `ProjectListView`'s own error paragraph and `BigbDashboard`'s independent loading/error `<p>` (nested one level deeper, inside `section.overview`), so the assertion flaked depending on which of the two independent fetches had settled by sample time.
- Scoped the selector to `main > p` (direct child), which is exactly `ProjectListView`'s own paragraph — no timing dependency, no frontend change needed.
Closes #60
## Test plan
- [ ] CI e2e job green
- [ ] Re-run e2e a few times (or check history) to confirm the flake is gone, not just hidden
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_014HiJrn6J6vhyFfC2qyY4uh
Reviewed-on: #61
|
||
| .forgejo/workflows | ||
| apps | ||
| config | ||
| deploy | ||
| docs | ||
| e2e | ||
| .env.example | ||
| .gitignore | ||
| .pylintrc | ||
| conftest.py | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| LICENSE | ||
| manage.py | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| pytest.ini | ||
| README.md | ||
| renovate.json | ||
| requirements-dev.txt | ||
| requirements-gilles.txt | ||
| requirements-spa.txt | ||
| requirements.txt | ||
| tox.ini | ||
| tsconfig.json | ||
| wdio.conf.ts | ||
argus/backend
API Django + DRF d'Argus — service de rapports de tests unitaires et de
couverture de code pour les pipelines Forgejo Actions de l'instance
git.stationmyr.net. Voir le dépôt soeur argus/frontend (SPA Vue 3).
Plan complet : voir la mémoire du projet (argus_project.md) et le plan
d'implémentation associé.
Développement local
cp .env.example .env
python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/python manage.py migrate
.venv/bin/python manage.py runserver
Sans DATABASE_URL/REDIS_URL configurés, le projet retombe sur SQLite
en local et Celery tourne en mode ALWAYS_EAGER (pas de worker séparé
nécessaire pour développer).
Tests
tox # pytest + couverture, lint (pylint), format-check, bandit
tox -e format # reformate avec autopep8
État actuel
En production sur https://reports.stationmyr.net/ (web+worker+beat+
redis). Modèles (Project, UploadToken, Report, ForgejoIdentity),
API d'enregistrement de projets/tokens/upload de rapports (traitement
asynchrone via Celery), résolution de permissions Forgejo à la volée,
login OIDC via Authentik — tout confirmé fonctionnel en conditions
réelles. Parseurs réels implémentés (apps/reports/parsers/) :
JUnit, Cobertura (avec détail ligne par ligne), lint
(pylint/bandit/eslint), format maison (JSON/YAML/XML). Badges SVG,
nettoyage automatique (PR fermées + historique, webhook Forgejo inclus)
et vue de code source annoté tous implémentés. Les deux tâches
périodiques (sweep_closed_prs, prune_history) se rapportent à
elles-mêmes sur Argus (dogfooding, apps/reports/selfreport.py) comme
n'importe quel autre projet.
Sources hors Forgejo et accès par groupes
Une organisation peut être native (propre à Argus, sans équivalent
Forgejo) et un projet externe (aucun dépôt derrière) : c'est là que
vont les rapports de serveurs, de sondes de disponibilité, de collecteurs
de métriques… (argus/backend#26). Les URL /:owner/:repo, les badges et
les jetons d'upload fonctionnent à l'identique ; seules les fonctions
propres à Forgejo (nettoyage des PR, webhook, code source, découverte,
commentaires de PR) les ignorent.
Les droits viennent de Forgejo et des groupes Authentik
(argus/backend#27) : un groupe reçoit un niveau (read/write/admin)
sur une organisation (donc tous ses projets) ou sur un projet, et le
niveau retenu est le plus élevé des deux. Les membres de
ARGUS_ADMIN_GROUP (argus-admins par défaut) et les superusers créent
les organisations natives et en sont admin. Toute la résolution passe par
apps.accounts.access.
Les groupes sont lus dans le claim OIDC groups (scope profile
d'Authentik, qui ne liste que les groupes directs de l'utilisateur,
pas leurs groupes parents) et mémorisés à chaque connexion : retirer
quelqu'un d'un groupe ne prend effet qu'à sa prochaine connexion.
Envoyer un rapport depuis une source
Un script ou un outil envoie un rapport « format maison » en JSON, sans
fichier ni commit, sur une ref source (le nom de la machine ou de
l'outil) -- argus/backend#28 :
curl -fsS -H "Authorization: Bearer $ARGUS_TOKEN" -H "Content-Type: application/json" \
https://reports.stationmyr.net/api/projects/stationmyr/infra/reports/ -d '{
"report_type": "custom", "custom_type_name": "host-health",
"ref_kind": "source", "ref_value": "garion",
"report": {"title": "Santé", "expect_every": "1h",
"metrics": [{"key": "disk_pct", "label": "Disque", "value": 57, "unit": "%"}]}}'
keyidentifie une métrique de façon stable. Une règle « seuil sur une métrique » (metric_threshold, argus/backend#23 : clé, opérateur, seuilswarn/fail) relève le statut de la métrique et du rapport au pire de ce qu'annonce la source et de ce que calculent les règles (badges et agrégats compris), et lève un événement quand le niveau monte. Deux options contre les bascules ok/warn (argus/backend#54) :recover, un seuil de retour (warn à>= 95, retour à ok seulement sous 85) ;for_count, le nombre de rapports consécutifs au-delà du seuil avant de changer de niveau (le dépassement en cours est marquépendingsur la métrique). Le retour à un niveau plus bas reste immédiat (horsrecover).expect_everyannonce la périodicité de la source (90s,15m,1h,7d…). Une règle « source muette » (stale, argus/backend#29) prévient quand plus rien n'arrive au-delà de cette période (+ max(10 min, 10 %)), puis quand la source revient ; la règle peut imposer son propre délai (after). Vérifié toutes les 5 minutes par la tâche Celerycheck_stale_sources. Les tâches quotidiennes d'Argus lui-même (sweep-closed-prs,prune-history) annoncent1d.- Sur une ref
source, un rapport identique au précédent (même statut, même résumé) n'est pas conservé : le précédent est seulement marqué « vu à » (last_seen_at), l'historique ne garde que les changements.
Règles d'événements d'organisation et globales
Une règle d'événement vit sur un projet, sur une organisation (elle
s'applique alors à tous ses projets, droit d'écriture sur l'organisation
requis) ou nulle part en particulier (globale : tous les projets,
réservée aux admins Argus) -- argus/backend#21. API identique sous
/api/projects/<owner>/<repo>/event-rules/,
/api/organizations/<org>/event-rules/ et /api/event-rules/ ;
?include_inherited=1 sur un projet liste aussi les règles héritées (en
lecture seule, sans leurs destinataires). L'état d'une règle (détection
de front) est suivi par projet. Quand plusieurs règles lèvent le même
événement pour le même rapport, chaque cible (canal ou utilisateur
Mattermost, adresse email, utilisateur Argus) n'est notifiée qu'une fois
par canal (SentTarget, fenêtre d'une heure).
Connecteurs
Pour un outil qui ne sait pas envoyer ses rapports, Argus va les chercher
(argus/backend#37) : un connecteur (réglages du projet, admin) a un type,
une URL interne (joignable par le worker, par exemple
http://beszel:8090 sur le réseau Docker monitoring -- pas l'URL
publique protégée par le SSO), un compte, un secret chiffré en base et
jamais renvoyé, et une période (60 s minimum). La tâche Celery
run_due_connectors (chaque minute) lance ceux qui sont dus ; chaque
passage note son résultat (last_status, last_error).
- Beszel : un rapport
beszelpar système, sous la refsource=<nom du système>(la machine : sa carte réunit aussi host-check), avec l'état du système (fail s'il est down) et les alertes que Beszel considère déclenchées (warn).expect_everyvaut trois périodes : un connecteur ou un Beszel en panne finit en source muette.
Notifications Uptime Kuma
- Une notification « Webhook » de Kuma (corps JSON, jeton d'upload dans les
- « Additional Headers » :
{"Authorization": "Bearer <jeton>"}) envoyée à /api/projects/<owner>/<repo>/ingest/uptime-kuma/devient un rapport- maison sous la ref
source=kuma(ou?source=), typeuptime:<moniteur> - hors service → fail, en attente → warn, en service / maintenance → ok
(argus/backend#38). Kuma ne notifie qu'aux changements d'état : pas
d'
expect_every. Le test de notification de Kuma est accepté sans créer de rapport.
Rapports de publication
Le type publish (argus/backend#22) décrit ce qu'une release ou un
snapshot devel a livré : version, nature (release / devel), date,
artefacts (nom, taille, lien), liens, dépendances. Envoyé en JSON (ou en
fichier) par publish-release de ci-base :
{"version": "1.2.0", "kind": "release", "date": "2026-10-29T10:00:00Z",
"artifacts": [{"name": "app.whl", "size": 123456, "url": "https://..."}],
"links": [{"label": "Release", "url": "https://..."}],
"dependencies": [{"name": "django", "version": "5.2.18"}]}
Les dépendances vont dans le détail du rapport
(GET .../reports/<id>/dependencies/), le résumé garde les tailles et le
nombre de dépendances. Les rapports publish ne sont jamais purgés par
la rétention d'historique. Une règle « Nouveau rapport » filtrée sur le
type publish sert d'alerte « nouvelle version ».
Vue d'ensemble
GET /api/overview/ (argus/backend#41) : tous les flux lisibles par
l'utilisateur, du pire au meilleur (fail, muet, warn, ok) -- chaque flux
de source (dernier rapport : statut, dernière réception, période
annoncée, muet ou non, même règle que le déclencheur stale) et, pour
les autres projets, le statut agrégé de leur branche principale
(master / main) par type de rapport.
Métriques dans bigb
Chaque métrique numérique à clé d'un rapport maison est copiée dans
ReportMetric (rapport, projet, ref, type, nom maison, variante, clé,
libellé, valeur, unité, date) au traitement du rapport, et supprimée
avec lui (argus/backend#46). Le modèle est déclaré à bigb
(reports.ReportMetric, même portée « projets lisibles » que les autres) :
les courbes de métriques et les tableaux de bord de projet sont des
requêtes bigb, par exemple
{"model": "reports.ReportMetric", "fields": ["at", "value"], "filters": [{"field": "key", "op": "eq", "value": "disk_pct"}], "order_by": ["at"]}
(fields demande bigb-django ≥ 1.3). Le groupe des lecteurs bigb peut
lancer ces requêtes ad hoc (execute_query).