Repository navigation
feat(ra-console): révocation et salle de quorum dans le navigateur (étape 6c) - #72
Closed
PhilippeVienne wants to merge 7 commits into
Closed
PhilippeVienne wants to merge 7 commits into
PhilippeVienne wants to merge 7 commits into
Conversation
…pe 3a) docs/WEBUI.md §15 étape 3, schéma de signature §4 étapes 1 à 3 : `POST /api/v1/webauthn/challenge` relaie à ca-server (`/internal/v1/challenge`) l'action demandée par l'opérateur connecté ; ca-server la fige et rend le corps qu'il exécutera, son empreinte et les options WebAuthn. - Le challenge vise l'opérateur de la session : `operator_hint` vient de la session (Authenticated gagne `operator_id`), jamais du navigateur. L'action est relue dans l'énumération fermée d'oe_actions puis resérialisée : un champ en trop ne franchit pas la console. - Seuls approve_request et reject_request sont préparés à ce stade (403 action_not_available sinon, sans solliciter ca-server). Le rôle et l'état de la demande restent jugés par ca-server. - Journal de la console : ra.action_challenge (AppState gagne `journal`). - action_challenge.rs, contre le vrai service d'actions de ca-server et PostgreSQL ; trois mutations tuées (indice venu du navigateur, filtre de l'étape, session non exigée). - docs/RA-CONSOLE.md mis à jour. Co-authored-by: Claude <noreply@anthropic.com>
…pe 3b)
docs/WEBUI.md §15 étape 3, §4 étapes 5 à 7 : `POST
/api/v1/requests/{id}/approve|reject` relaie à ca-server
(`/internal/v1/actions`) l'identifiant du challenge et l'assertion brute,
jamais de corps : ca-server exécute celui qu'il a figé.
- Lien assertion ↔ demande contrôlé par ca-server (décision de
l'utilisateur) : la console joint `expect` (action et demande du
chemin) ; oe_actions::Service::execute_expecting le compare au corps
figé avant de retirer l'état de la cérémonie, et refuse (409
action_mismatch) s'il diffère. Une signature obtenue pour une demande
ne décide jamais d'une autre, ni l'inverse de ce qui a été signé, et
l'assertion reste utilisable sur la bonne route. `expect` ne peut que
restreindre ; `execute` sans attente est inchangé.
- Réponse de la forme du §5 : `decided_by` est l'opérateur dont la clé a
signé, lu dans le registre de ca-server.
- Journal de la console : ra.action_relayed.
- Tests de bout en bout (approbation, rejet, rejeu, mauvaise cible,
corps non relayés) et unitaire d'Expect ; trois mutations tuées
(contrôle retiré, contrôle après consommation, expect non envoyé).
Co-authored-by: Claude <noreply@anthropic.com>
…pe 4a)
docs/WEBUI.md §15 étape 4, §8 : la console prépare `revoke_certificate`
et relaie la signature par `POST /api/v1/certificates/{serial}/revoke`.
La politique de ca-server exige deux ca_operateur distincts : la
première signature est enregistrée, rien n'est révoqué
(AWAITING_QUORUM, 1/2). La co-signature est l'étape 4b.
- oe_actions::Expect gagne `serial` : ca-server compare le certificat de
la route au corps figé avant toute consommation, comme pour une
décision ; une cible sans rapport avec le type d'action est refusée.
- ra-console : relay_assertion factorise le relais d'une assertion
(décisions et révocation) ; numéro de série exigé sous forme
canonique (hexadécimal minuscule, 20 octets au plus) avant relais.
- Tests : harnais doté d'une vraie CA sur PostgreSQL et du révocateur de
ca-server ; première signature sans révocation, mauvaise cible,
forme non canonique, refus pour un ra_operateur. Deux mutations tuées.
Co-authored-by: Claude <noreply@anthropic.com>
…tape 4b)
docs/WEBUI.md §8, §15 étape 4 : deux ca_operateur distincts révoquent
ensemble depuis la console.
- Co-signature : `POST /api/v1/webauthn/challenge` accepte
`{"action_id"}` (action existante, non exécutée, proposée à ce stade),
puis `POST /api/v1/quorum/{action_id}/sign`. oe_actions::Expect gagne
`action_id`, comparé avant toute consommation : une co-signature ne
compte que pour l'action pour laquelle son challenge a été émis.
- Salle d'attente : `GET /api/v1/quorum?state=PENDING` lit `actions` et
`decision_evidence` de ca-server en lecture seule (décision de
l'utilisateur) : corps figé, empreinte, signatures, signataires. Le
rôle de la console gagne SELECT sur `actions` (aucun secret n'y
figure) ; le test de schéma est mis à jour.
- Écart assumé avec le §8, en plus sûr : pas de tables de collecte, la
console ne conserve jamais d'assertion (ca-server enregistre chaque
signature au fil de l'eau). WEBUI.md §8 dit ce qui est construit.
- Tests : révocation à deux de bout en bout, seconde signature du même
opérateur refusée, exécution unique, co-signature présentée pour une
autre action sur le même certificat refusée. Deux mutations tuées.
- Mise à jour d'un déploiement : rejouer ra_console_grants.sql.
Co-authored-by: Claude <noreply@anthropic.com>
docs/WEBUI.md §15 étape 6, docs/UI-UX.md : la console sert son interface, en TypeScript compilé par esbuild (choix de l'utilisateur), sans framework ni dépendance d'exécution. - Assets embarqués dans le binaire (include_bytes!, src/web.rs) depuis web/dist, versionné : compiler ra-console n'exige pas Node. - En-têtes de sécurité sur toutes les réponses, API comprise (UI-UX §6.3) : CSP stricte sans unsafe-inline ni CDN, frame-ancestors 'none', X-Frame-Options DENY, nosniff, Referrer-Policy, Cache-Control no-store. `http::app` compose l'API, le frontend et ces en-têtes. - Bannière d'environnement (OPENEIDAS_RA_ENVIRONMENT, « non déclaré » à défaut), connexion par nom et clé FIDO2, poste de travail (identité et rôle relus sur le serveur, compteurs des files), déconnexion, verrouillage après 15 min d'inactivité (avertissement à 14). Aucun innerHTML : le contenu de l'API est inséré en texte. - Tests : tests/web.rs (en-têtes et assets, sans navigateur) ; Playwright contre une console réelle (examples/e2e_console.rs, PostgreSQL), clé du SoftToken confiée à l'authentificateur WebAuthn virtuel de Chromium. - CI : job frontend (typage strict, dist/ conforme aux sources, parcours de bout en bout). Dépendances npm de développement seulement (esbuild MIT, TypeScript et Playwright Apache-2.0), jamais dans l'image. Co-authored-by: Claude <noreply@anthropic.com>
docs/WEBUI.md §15 étape 6, docs/UI-UX.md §3.1, §3.4, §5, §6.1 : les décisions RA se prennent dans le navigateur, avec la clé FIDO2. - File des demandes en attente : tableau dense, sélection au clavier (j/k, a approuver, r rejeter), inspecteur latéral. - Justification avant signature, obligatoire pour un rejet (garde d'interface : attribut required et contrôle du script). - Modale de signature (<dialog> natif) : corps figé par ca-server affiché tel quel avec son empreinte SHA-256, puis la clé ; erreur sans fermeture, challenge redemandé s'il est consommé ou expiré, Échap bloqué pendant la cérémonie matérielle. - Harnais e2e : le vrai service d'actions de ca-server derrière le lien mTLS, et huit demandes en attente. Parcours Playwright : approbation (corps et empreinte affichés, état APPROVED côté serveur), rejet au clavier avec motif obligatoire, renoncement sans effet. Co-authored-by: Claude <noreply@anthropic.com>
6 tasks
…tape 6c) docs/WEBUI.md §8, §15 étape 6, docs/UI-UX.md §3.2 : deux opérateurs CA distincts révoquent un certificat depuis la console. - `GET /api/v1/certificates?status=issued|revoked` : certificats émis, en lecture seule sur la table de ca-server, numéro de série sous la forme canonique qu'attend la révocation (test Rust : liste, filtre, passage en « revoked » après double signature, refus sans session). - Navigation entre demandes, certificats et quorum. Écran des certificats : motif RFC 5280 parmi ceux qu'admet ca-server, justification obligatoire, modale de signature ; la première signature part en salle de quorum. - Salle de quorum : corps figé, empreinte, signataires ; co-signature désactivée pour qui a déjà signé (ca-server la refuserait aussi). - Harnais e2e : trois opérateurs (alice RA, bob et carol CA), une CA sur la même base avec son révocateur, deux certificats. Parcours : révocation à deux de bout en bout, refus pour un opérateur RA. Mutation tuée (co-signature par soi-même non désactivée). Co-authored-by: Claude <noreply@anthropic.com>
PhilippeVienne
force-pushed
the
feat/ra-console-frontend-revoke
branch
from
September 30, 2026 13:09
942f85a to
9e19ad5
Compare
PhilippeVienne
force-pushed
the
feat/ra-console-frontend-requests
branch
from
September 30, 2026 17:17
d05e829 to
42716c4
Compare
Contributor
Author
This was referenced Sep 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Objet
docs/WEBUI.md§8 et §15 étape 6, tranche 6c ;docs/UI-UX.md§3.2. Deux opérateurs CA distincts révoquent un certificat depuis la console. Empilée sur #71 (feat/ra-console-frontend-requests, têted05e829).GET /api/v1/certificates?status=issued|revoked— certificats émis, en lecture seule sur la table deca-server(que le rôle de la console lisait déjà), numéro de série en hexadécimal minuscule, la forme canonique qu'attend la révocation. Les certificatsreservedn'y figurent pas.ca-server(1, 3, 4, 5, 9), justification obligatoire, modale de signature (corps figé + empreinte). La première signature part en salle de quorum (« 1 sur 2 »).ca-serverla refuse de toute façon.sign()rend désormais la réponse de l'autorité (pour afficherAWAITING_QUORUM/EXECUTED).ra_operateur, bob et carolca_operateur), une vraie CA sur la même base avec le révocateur deca-server, deux certificats émis.Vérifications
the_console_lists_issued_certificates: liste, filtre, passage enrevokedaprès double signature,400sur un état inconnu,401sans session.revokedcôté serveur, la salle se vide ; unra_operateurse voit refuser la préparation par l'autorité, rien n'est figé. Parcours de 6a/6b toujours verts.cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings(1.97 et 1.98.1),cargo test --workspaceavec PostgreSQL,cargo audit --ignore RUSTSEC-2023-0071,npm run typecheck: verts.Revue humaine obligatoire
Voir PROVENANCE.md. Chaque case est cochée par le
contributeur humain qui valide la PR, après l'avoir fait lui-même.
make licenses)Assistance par IA
Co-authored-by: Claude <noreply@anthropic.com>, auteur et committer restent humains, etscripts/provenance.py archivea été lancé