[DEMO] Archivio scambio AgileHub 2026-06-13: HMAC #1 CHIUSO (runtime-avatar = no HMAC per-msg)

- INCOMING_FROM_AGILEHUB: contratto HMAC external/v1 (canale ticket) + chiarimento canale runtime-avatar
  (X-Internal-Key, no HMAC per-messaggio) + persona ARIA pronta (RAG 402) + piano Fase 1.
- OUTGOING aggiornato: punto coordinamento #1 marcato CHIUSO (demo-mode.js HMAC_ENFORCE=false, a851caf).
This commit is contained in:
DevEnv nis2-agile
2026-06-13 09:41:22 +02:00
parent a851caf669
commit 4222e827f9
2 changed files with 39 additions and 1 deletions
@@ -0,0 +1,38 @@
# AgileHub → NIS2 — Chiusura HMAC (#1) + piano avatar formazione/demo
> **Da**: AgileHub · **A**: NIS2 · **Data**: 2026-06-13 · Per gli atti.
> Risposta nostra: `docs/OUTGOING_TO_AGILEHUB_2026_06_13_demo_avatar_nis2_product_ready.md` (punto #1 chiuso).
## #1 — HMAC canonical (gateway external/v1 — canale ticket/egress, scope `tickets:*`)
Verifier: `crypto.js` + `externalAuth.js` del gateway external/v1. `canonicalize()` deve produrre ESATTAMENTE:
```
METHOD \n ORIGINAL_URL \n X-Cred-Id \n X-Cred-Timestamp \n X-Cred-Nonce \n X-Tenant-Ref \n SHA256HEX(rawBody)
```
Gotcha:
- Separatore = singolo `\n` (LF 0x0A). No CRLF, no spazi attorno.
- `METHOD` maiuscolo.
- PATH = `req.originalUrl` = **path + query string** così com'è inviato (se c'è `?a=1` va incluso identico). NON solo il pathname.
- Ultimo campo = sha256 hex **lowercase** del rawBody esatto (body vuoto → `sha256("")` = `e3b0c4…`).
- Firma: HMAC-SHA256, chiave = `signing_key` **hex-decodificata in byte** (`Buffer.from(keyHex,'hex')`, non la stringa hex come utf8), output hex lowercase.
- Header firma: `X-Cred-Signature: v1=<hex>` (prefisso `v1=`).
- `X-Cred-Timestamp` = Unix **secondi** (non ms). Anti-replay ±300s + nonce unico per credenziale.
- Header obbligatori: `X-Cred-Id`, `X-Cred-Timestamp`, `X-Cred-Nonce`, `X-Tenant-Ref`, `X-Cred-Signature`.
- Rif.: `DEV_GUIDE_AGILEHUB_EXTERNAL_API.md §3` + `API_GUIDE §3`.
### ⚠️ Chiarimento di canale (decisivo)
Questo HMAC è del **gateway external/v1** (canale ticket/egress). Il **runtime avatar demo** (`/demo-session/start` + LLM dimostrazione) **NON usa HMAC per-messaggio**: usa **`X-Internal-Key` server-to-server** (come ALLTAX).
→ **Risoluzione NIS2**: la nostra `demo-mode.js` è il canale **runtime-avatar** (postMessage widget→SPA), quindi **niente HMAC per-messaggio** (origin-verified) + `X-Internal-Key` server-to-server (già su `reset-dataset`). **Non serve** credenziale `nis2_extcred_…`. (Se in futuro NIS2 userà external/v1 → si conia la credenziale e si usa la canonical sopra.)
## Stato lato AgileHub
- **Persona `ARIA_SUPPORT_NIS2`** già pronta e vestita: Tavus "Giulia" + voce ARIA "Charlotte" IT + Sonnet 4.6 + **RAG repo 402**. Zero da creare.
- **Same-origin** su `dimostrazione.agile.software` (scelto): preparano il vhost (proxy `/api/*` + CSP iframe); vhost condiviso → backup + OK prima del reload.
- **Formazione = sottosistema condiviso** (scelto): build vero (schema + endpoint attestato/esame 80%/progresso + collaudo). **NIS2 = pilota genesi**.
## Cosa serve da NIS2 per partire (Fase 1) — FORNITO
1. Le 22 mappe + tag `demo:nis2-tour-2026:stepN` + scelta repo (402 vs dedicato). → `docs/mappa-logica/` su Gitea main; mapping step→mappa fornito nell'OUTGOING.
2. Artefatto SPA + route + `/api/*` da proxare + CSP. → **NIS2 è multi-pagina, non un bundle**: reverse-proxy dell'app sotto `dimostrazione`; route/asset/CSP forniti nell'OUTGOING.
3. Tassonomia + banca export. → `docs/formazione/` su Gitea main.
→ Appena hanno (1) e (3) partono. Ci hanno chiesto se procedere col design del sottosistema formazione: **risposto sì, procedete ora** (export già in Gitea).
@@ -32,7 +32,7 @@
- **Collaudo oggettivo** (definizione di "fatto"). - **Collaudo oggettivo** (definizione di "fatto").
## Punti di coordinamento da chiudere insieme (al collaudo) ## Punti di coordinamento da chiudere insieme (al collaudo)
1. **HMAC canonical del MESSAGGIO**: la chiave canale è a contratto (`SHA-256(demo_jwt+":"+seed+":demo-control-channel")`); la *canonicalizzazione del messaggio* per l'HMAC non è fissata nello standard. In `demo-mode.js` → `canonicalize()` è marcata **TO-RECONCILE**: diteci la forma esatta del vostro parser (campi/ordine/separatore) e la allineo. *(In `demo-mode.js`: `HMAC_ENFORCE=true`.)* 1. ~~**HMAC canonical del MESSAGGIO**~~ → **CHIUSO 2026-06-13** (vedi `INCOMING_FROM_AGILEHUB_2026_06_13_hmac_e_piano.md`). Chiarito che la `demo-mode.js` è il **canale runtime-avatar** (postMessage widget→SPA): **niente HMAC per-messaggio**, security = `ev.origin` (same-origin) + `X-Internal-Key` server-to-server (già su `reset-dataset`). `demo-mode.js` aggiornato: `HMAC_ENFORCE=false` (commit `a851caf`). L'HMAC canonical `METHOD\nURL\n…\nsha256(body)` resta documentato per il **gateway external/v1** (canale ticket), non usato dall'avatar.
2. **Ops same-origin**: `dimostrazione.agile.software` deve servire la SPA NIS2 **same-origin** con la landing e proxare `/api/*` → backend NIS2, con CSP che consenta l'iframe. In alternativa vi do uno `SPA_BASE` dedicato. *(Senza same-origin l'HMAC via `sessionStorage` e gli URL del manifest non risolvono.)* 2. **Ops same-origin**: `dimostrazione.agile.software` deve servire la SPA NIS2 **same-origin** con la landing e proxare `/api/*` → backend NIS2, con CSP che consenta l'iframe. In alternativa vi do uno `SPA_BASE` dedicato. *(Senza same-origin l'HMAC via `sessionStorage` e gli URL del manifest non risolvono.)*
3. **`data-demo-action` anchors**: le azioni read-only del tour (`open-tab-*`, `open-ai-panel`, `open-first-detail`) sono in whitelist (`demo-selectors.js`) ma gli anchor nel DOM sono da cablare (sweep id residuo). Per il tour attuale (navigate + highlight) **non sono bloccanti**. 3. **`data-demo-action` anchors**: le azioni read-only del tour (`open-tab-*`, `open-ai-panel`, `open-first-detail`) sono in whitelist (`demo-selectors.js`) ma gli anchor nel DOM sono da cablare (sweep id residuo). Per il tour attuale (navigate + highlight) **non sono bloccanti**.
4. **Sweep id stabili (132)**: in completamento; il manifest attuale àncora gli highlight a **id già esistenti e verificati** (non i 132), quindi il tour funziona già. 4. **Sweep id stabili (132)**: in completamento; il manifest attuale àncora gli highlight a **id già esistenti e verificati** (non i 132), quindi il tour funziona già.