Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,73 @@ jobs:
git commit -m "Épingle le staging sur open-eidas/open-eidas@${GITHUB_SHA}"
git push origin main

frontend:
name: Frontend de ra-console (typage, build, bout en bout)
runs-on: ubuntu-latest
# La console réelle tourne sur PostgreSQL (examples/e2e_console.rs), avec un
# opérateur dont la clé est confiée à l'authentificateur WebAuthn virtuel de
# Chromium : connexion, déconnexion et verrouillage sont prouvés dans un vrai
# navigateur, en-têtes de sécurité et CSP compris (docs/UI-UX.md §6.3).
services:
postgres:
image: postgres:17-alpine
env:
POSTGRES_PASSWORD: test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 10
defaults:
run:
working-directory: bin/ra-console/web
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: bin/ra-console/web/package-lock.json

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2

- name: Dépendances de développement (jamais dans l'image)
run: npm ci

- name: Typage strict (navigateur et tests)
run: npm run typecheck

- name: web/dist correspond aux sources
# Les assets sont versionnés pour que la compilation Rust n'exige pas
# Node ; un dist/ désynchronisé servirait autre chose que le code relu.
run: |
npm run build
git diff --exit-code -- dist || {
echo "::error::web/dist est désynchronisé : lancez 'npm run build' dans bin/ra-console/web"
exit 1
}

- name: Navigateur de test
run: npx playwright install --with-deps chromium

- name: Parcours de bout en bout (Playwright)
env:
OE_CASTORE_TEST_DSN: postgres://postgres:test@localhost:5432/postgres
run: npx playwright test

- name: Rapport Playwright (en cas d'échec)
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: bin/ra-console/web/playwright-report
retention-days: 7

helm-lint:
name: Lint du chart Helm
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion bin/ca-server/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ struct ExecuteRequest {
/// Sortie brute de `navigator.credentials.get`. Aucun corps d'action :
/// c'est celui figé à l'émission du challenge qui s'exécute.
assertion: PublicKeyCredential,
/// Ce que l'appelant croit faire exécuter (type et cible), comparé au corps
/// figé avant toute vérification : ne peut que faire refuser, jamais changer
/// ce qui s'exécute.
#[serde(default)]
expect: Option<oe_actions::Expect>,
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -101,6 +106,7 @@ fn failure(e: Error) -> Response {
Error::Verification(_) => (StatusCode::UNAUTHORIZED, "signature_rejected"),
Error::Journal(_) => (StatusCode::SERVICE_UNAVAILABLE, "journal_unavailable"),
Error::Blocked(_) => (StatusCode::SERVICE_UNAVAILABLE, "registry_blocked"),
Error::Mismatch(_) => (StatusCode::CONFLICT, "action_mismatch"),
Error::Db(_) | Error::Effect(_) => {
tracing::error!(erreur = %e, "action interne en échec");
return error(
Expand Down Expand Up @@ -160,7 +166,15 @@ async fn handle_actions(State(service): State<Arc<Service>>, body: Bytes) -> Res
Ok(r) => r,
Err(e) => return bad_json(e),
};
match service.execute(req.challenge_id, &req.assertion).await {
let done = match &req.expect {
Some(expect) => {
service
.execute_expecting(req.challenge_id, &req.assertion, expect)
.await
}
None => service.execute(req.challenge_id, &req.assertion).await,
};
match done {
// L'identité vient du registre de `ca-server`, jamais de l'appelant.
Ok(done) => Json(serde_json::json!({
"action_id": done.action_id,
Expand Down
6 changes: 6 additions & 0 deletions bin/ra-console/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ rand = "0.8"

[dev-dependencies]
async-trait = "0.1"
# Harnais de bout en bout du frontend (examples/e2e_console.rs) : export de la
# clé du SoftToken vers l'authentificateur virtuel du navigateur. Déjà dans
# l'arbre de dépendances (webauthn-authenticator-rs), aucune crate nouvelle.
serde_cbor_2 = "0.13"
openssl = "0.10"
base64 = "0.22"
oe-raflow = { path = "../../crates/oe-raflow" }
webauthn-authenticator-rs = { version = "0.5", features = ["softtoken"] }
ca-server = { path = "../ca-server" }
Expand Down
Loading
Loading