Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c70609f
fix(ci): pin verified action commits and Pages packaging
iPoower Oct 23, 2026
2b2dda9
fix(drive): require confirmed test account and dedicated destination
iPoower Oct 23, 2026
b677c7c
fix(drive): distinguish conflict from integrity and access blocks
iPoower Oct 23, 2026
642da6f
fix(drive): freeze download identity before asynchronous folder checks
iPoower Oct 23, 2026
3e33edc
fix(idb): retry failed opens and invalidate closed connections
iPoower Oct 23, 2026
f2eff8c
test(idb): verify blocked, failed and versionchanged reopen without p…
iPoower Oct 23, 2026
9b0abdf
fix(drive): persist and readback download receipts under shared outbo…
iPoower Oct 23, 2026
bd71f91
test(drive): receipt readback, reload, idempotence, pending job and f…
iPoower Oct 23, 2026
1403c62
test(drive): initialize synthetic IndexedDB before importing eager ar…
iPoower Oct 23, 2026
3efb23e
test(e2e): prove Control Vault downloaded packet decrypts fully on vi…
iPoower Oct 23, 2026
aa0f852
test(e2e): inject actual owner codec using a valid JavaScript newline
iPoower Oct 23, 2026
7a2b78b
fix(drive): compare pending encrypted bytes without JSON expansion
iPoower Oct 25, 2026
50121ea
test(drive): prepare isolated TEST profile from approved source candi…
iPoower Oct 25, 2026
37d9d81
fix(ci): run CodeQL inside the single guarded pipeline
iPoower Oct 25, 2026
9f222ac
test(fortress): attest synthetic test bundle SHA-256
iPoower Oct 26, 2026
37f67a2
ci(fortress): build PR-only test bundle with strict provenance
iPoower Oct 26, 2026
461a567
fix(ci): preserve unique pipeline invariant; fold FORTRESS artifact i…
iPoower Oct 26, 2026
d58b1d3
ci(fortress): add verified fake TEST bundle to unique protected pipeline
iPoower Oct 26, 2026
bb29de6
test(fortress): fail closed unless configured Google TEST is enabled
iPoower Oct 26, 2026
e809e1c
ci(test): verify Google-enabled synthetic artifact in parallel, prese…
iPoower Oct 26, 2026
956005e
ci(fortress): single attested TEST artifact job; prevent duplicate up…
iPoower Oct 26, 2026
28767b2
fix(test): keep lab app navigation within isolated origins
iPoower Oct 26, 2026
ac7e7af
fix(fortress-test): import independently red-green-tested CV SW v4 an…
iPoower Oct 26, 2026
6169777
test(fortress): Refuser le HTML redirigé et éprouver la première ouve…
iPoower Oct 26, 2026
f0b93ab
fix(test-pwa): precache exact build assets before first offline reope…
iPoower Oct 26, 2026
51031e8
fix(test-pwa): preserve first offline navigation after index redirect
iPoower Oct 27, 2026
63a035b
test(pwa): expose read-only offline readiness diagnostics
iPoower Oct 27, 2026
f8a6143
test(pwa): exercise diagnostic with native worker and offline cache
iPoower Oct 27, 2026
a3395ec
test(pwa): bound diagnostic failures and blocked storage
iPoower Oct 27, 2026
7855f40
test(pwa): track native WebKit activation state
iPoower Oct 27, 2026
08c1ae8
test(pwa): restore single-workflow repository invariant
iPoower Oct 27, 2026
f87834b
fix(test-pwa): keep diagnostic failures from blocking startup
iPoower Oct 27, 2026
3675ec1
security(test): disallow document base overrides in CSP
iPoower Oct 27, 2026
36447d5
feat(test): select authorized dedicated Drive folders without Picker
iPoower Oct 28, 2026
2e112f6
fix(test): keep dedicated Drive folder actions usable on mobile
iPoower Oct 28, 2026
fc33a9d
fix(fortress-test): make Google Picker optional for dedicated Drive API
iPoower Oct 28, 2026
4b7da07
test(fortress): normalize optional Picker network rejection
iPoower Oct 28, 2026
3e680b7
test(fortress): prove Drive API survives optional Picker outage
iPoower Oct 28, 2026
012ddf6
fix(drive): accept omitted false incompleteSearch while rejecting inc…
iPoower Oct 28, 2026
05d0879
test(drive): cover omitted optional incompleteSearch and malformed value
iPoower Oct 28, 2026
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
88 changes: 78 additions & 10 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,68 @@ concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
fortress-test-bundle:
name: FORTRESS TEST - isolated public config bundle
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && (github.head_ref == 'test/fortress-drive-execution-20261026' || startsWith(github.head_ref, 'test/fortress-final-acceptance-'))
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
steps:
- name: Checkout exact PR head
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false
- name: Configure Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1
with:
node-version: '22'
cache: npm
- name: Install pinned dependencies
run: npm ci --no-audit --no-fund
- id: fortress
name: Build and attest Google-enabled fake-only TEST
env:
BUILD_SHA: ${{ github.event.pull_request.head.sha }}
FORTRESS_TEST_GOOGLE_CONFIG: ${{ vars.FORTRESS_TEST_GOOGLE_CONFIG }}
GOOGLE_DRIVE_CONFIG: ${{ vars.FORTRESS_TEST_GOOGLE_CONFIG }}
run: |
node scripts/build-drive-test.mjs > "$RUNNER_TEMP/fortress-build-receipt.json"
node scripts/verify-fortress-artifact.mjs "$RUNNER_TEMP/fortress-build-receipt.json"
- name: Archive attested synthetic TEST only
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: fortress-control-vault-test-${{ github.event.pull_request.head.sha }}
path: ${{ steps.fortress.outputs.site_dir }}/
include-hidden-files: true
if-no-files-found: error
retention-days: 14
codeql:
name: CodeQL JavaScript/TypeScript
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
contents: read
actions: read
security-events: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370
with:
languages: javascript-typescript
build-mode: none
queries: security-extended
- uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370
with:
category: drive-test-javascript

verify:
name: Vérification complète
needs: codeql
runs-on: ubuntu-24.04
timeout-minutes: 30
# Même version que package-lock.json : navigateurs et bibliothèques déjà présents.
Expand All @@ -43,10 +103,10 @@ jobs:
env:
BUILD_SHA: ${{ github.sha }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 — SHA vérifié le 23/10/2026
with:
persist-credentials: false
- uses: actions/setup-node@v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 — SHA vérifié le 23/10/2026
with:
node-version: 22
cache: npm
Expand Down Expand Up @@ -90,32 +150,40 @@ jobs:
CI: '1'
- name: Captures d'écran des parcours (données fictives uniquement)
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 — SHA vérifié le 23/10/2026
with:
name: captures-parcours
path: screenshots/
retention-days: 30
- name: Rapport Playwright
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 — SHA vérifié le 23/10/2026
with:
name: rapport-playwright
path: playwright-report/
retention-days: 14
# L'artefact publié est celui-ci : construit puis testé ci-dessus, pour ce commit.
- name: Artefact vérifié (Cloudflare)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 — SHA vérifié le 23/10/2026
with:
name: site-verifie-${{ github.sha }}
path: dist-cloudflare/
include-hidden-files: true
retention-days: 7
# Même archive Linux que upload-pages-artifact v3, sans son appel
# transitif mobile à upload-artifact@v4. Les octets de dist/ restent ceux testés.
- name: Archive vérifiée (GitHub Pages)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: tar --dereference --hard-dereference -C dist --exclude=.git --exclude=.github -cvf "$RUNNER_TEMP/artifact.tar" .
- name: Artefact vérifié (GitHub Pages)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 — SHA vérifié le 23/10/2026
with:
path: dist/
name: github-pages
path: ${{ runner.temp }}/artifact.tar
retention-days: 1
if-no-files-found: error

gate:
name: Porte de publication
Expand Down Expand Up @@ -144,7 +212,7 @@ jobs:
cancel-in-progress: false
steps:
- id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 — SHA vérifié le 23/10/2026
- name: Le site sert bien ce commit
run: |
url="${{ steps.deployment.outputs.page_url }}"
Expand All @@ -170,13 +238,13 @@ jobs:
cancel-in-progress: false
steps:
- name: Récupération de l'artefact vérifié de ce run
uses: actions/download-artifact@v4
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 — SHA vérifié le 23/10/2026
with:
name: site-verifie-${{ github.sha }}
path: dist
- name: L'artefact correspond au commit
run: grep -q "\"sha\":\"${{ github.sha }}\"" dist/version.json
- uses: actions/setup-node@v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 — SHA vérifié le 23/10/2026
with:
node-version: 22
- name: Projet Cloudflare en envoi direct (créé une seule fois, sans connexion Git)
Expand Down
47 changes: 47 additions & 0 deletions docs/DRIVE_ACCOUNT_BOUNDARY_20261023.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Frontière compte et destination — NOESIS, 23 octobre 2026

Statut : préparation sensible, revue humaine obligatoire, aucune fusion ni activation cloud autorisée par cette PR. Cette note ne modifie pas les contrats normatifs V1/A1/A2.

## Défauts reproduits avant correction

Deux contre-tests du fournisseur, exécutés sur la version antérieure, échouent : un dossier personnel simplement accessible en écriture est accepté ; un fichier déplacé hors du dossier sélectionné peut encore être téléchargé et annoncé vérifié si ses empreintes concordent.

## Correction limitée au périmètre

Le choix du compte reste dans l'interface officielle Google, avec `prompt: select_account`, le seul scope `drive.file` et aucun consentement automatique. Après le retour Google, l'application lit seulement l'identité du compte courant (`about.get`, permissionId/emailAddress), l'affiche en mémoire et exige une confirmation explicite avant Picker, réservation d'ID ou accès aux fichiers. Ni compte, ni adresse, ni jeton ne sont persistés ou consignés. L'application ne peut pas déterminer seule si le compte est personnel : l'utilisateur doit choisir un compte de test dédié. La configuration de production reste absente/désactivée.

Le dossier est neuf, créé par l'application avec un ID réservé et la marque privée `rc-folder-v1`, puis relu. Sa sélection reste explicite dans Google Picker. Le fournisseur exige son identité, sa propriété, son type, l'absence de corbeille et le droit d'ajout. Aucune modification, suppression, exploration générale ou labellisation d'un dossier existant. Un dossier ancien non marqué est refusé : aucune migration implicite. Le même dossier marqué peut être choisi sur l'autre appareil avec le même projet/client OAuth autorisé.

Listes et relectures sont limitées au dossier choisi, aux marques `rc-v1`/`rc-key-a1` et aux métadonnées attendues. Le parent du fichier est vérifié avant sa lecture. Une empreinte SHA-256 reste une preuve d'octets, pas une authentification GCM : celle-ci appartient uniquement à Race Control. Un ajout extérieur au dossier ou une suppression par un utilisateur autorisé n'est pas empêché par cette marque.

Le jeton est exclusivement en mémoire. Expiration, déconnexion et révocation connue invalident la sélection. Les callbacks d'un ancien compte ou d'un ancien Picker ne réactivent pas la nouvelle session. Un changement de destination invalide le bail réseau précédent. Une opération persistée conserve sa liaison opaque compte/client/dossier et ne peut être reprise ailleurs. Le marquage du dossier ne remplace ni l'autorisation Google ni la comparaison de cette liaison.

La création du dossier réutilise l'ID réservé pendant la session si une réponse est perdue. Après fermeture complète avant confirmation du dossier, il faut retrouver explicitement le dossier existant dans Picker ; ne pas annoncer une reprise persistante de cette préparation de dossier. Les files d'archives conservent déjà durablement leurs octets et identifiants, séparément.

Race Control suspend son moteur avant un changement de destination, attend la fin de l'ancienne exécution, et ne valide pas son résultat tardif. La file reste conservée ; un paquet éventuellement créé est relu avec son ID initial lors d'une reprise autorisée dans sa destination initiale. Les données métier restent exclusivement dans Race Control.

Control Vault affiche le compte et le dossier sélectionnés, la date d'opération, la file connue et les états distincts attente/envoi/envoyé/octets vérifiés/blocage/erreur. Les têtes A2 listées restent déclaratives avant authentification dans Race Control. Aucun déchiffrement ou arbitrage métier dans Vault.

## Reproduction et vérifications

- Vault : `npm ci`, `npm run typecheck`, `npm test`, `npm run build`, `npm run security`, `CI=1 npm run test:e2e` ; les deux moteurs et les quatre projets de viewport restent requis.
- Contre-tests : `tests/unit/drive-boundary.test.ts` (dossier non dédié, parent divergent, confirmation, changement de compte, callbacks tardifs, création idempotente et révocation).
- Parcours navigateur : `tests/e2e/connected-drive.spec.ts` (Google entièrement intercepté, données fictives, confirmation avant création/Picker, relecture et téléchargement, rejet du clair, oubli du jeton au rechargement).
- Race Control : `node tests/run-ci.js --lane unit`, `BROWSER=chromium node tests/e2e85-drive-runtime.js`, puis `BROWSER=webkit node tests/e2e85-drive-runtime.js` ; suite CI complète avant toute décision de fusion. `tests/test_drive_sync.js` vérifie aussi le changement de destination pendant l'envoi.
- Reproduction statique du fournisseur dans Race Control : `node tools/vendor-vault-drive.js ../Control-Vault`. Les SHA-256 des quatre sources sont inscrits dans l'en-tête généré. Le module GIS est identique entre dépôts, hormis l'export ES de Vault.

Ces preuves sont unitaires et d'intégration avec réseau Google simulé. Aucun appel Google réel, aucun compte personnel, aucune validation sur un iPhone physique. VALIDATION PHYSIQUE EN ATTENTE.

## Environnement réel à autoriser séparément

Deux origines HTTPS de test indépendantes, un client OAuth Web de test commun à ces seules origines, une clé Picker restreinte, un compte Google de test confirmé par l'utilisateur et un dossier neuf sont nécessaires. La création de ressources administratives et leur publication nécessitent un GO ciblé distinct. Le schéma public reste exactement `approved`, `clientId`, `apiKey`, `appId`, `raceOrigin`, `vaultOrigin`. Aucun compte/dossier/jeton/secret ajouté au schéma. Ne jamais configurer un secret client OAuth dans une application statique.

L'autorisation `approved: true` est réservée au futur environnement de test isolé après validation de ses ressources. Aucun changement des variables ou secrets de production. Aucun accès réel depuis `ipoower.github.io`. Les essais réels doivent démontrer les droits effectifs sur les fichiers des deux applications : Picker seul ne prouve pas ces droits.

## Risques, dépendances et récupération

Modification sensible commune aux deux clients : relire les deux PR et la compatibilité du fournisseur reproduit. La PR de sécurité CI/CD Control Vault #16 reste séparée et non fusionnée. Aucun changement de workflow, permission, secret, données existantes, contrat normatif, service worker ou animation.

Le retour arrière concerne le code uniquement, par PR et après accord. Ne jamais effacer la file, les bases locales, le dossier ou les archives pour faciliter un retour arrière. Une installation ancienne non marquée reste disponible ; son export chiffré et sa restauration isolée doivent être validés avant toute migration personnelle explicite.

Aucune promesse de synchronisation permanente d'une PWA fermée sur iOS. Reprise seulement application ouverte, autorisée, connectée et coffre déverrouillé ; expiration Google implique une action humaine. Un succès HTTP ne constitue pas une sauvegarde vérifiée, et les octets vérifiés par Vault ne constituent pas une restauration réussie.
21 changes: 21 additions & 0 deletions docs/DRIVE_REAL_TEST_20261025.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Candidat Google Drive TEST — 25 octobre 2026

Cette branche est réservée aux projets Cloudflare existants `rc-drive-test-ipoower` et `cv-drive-test-ipoower`, branche de publication `noesis-test`. Aucun main, environnement de production, projet Reconversion ou travail Garage/Climatisation n'est modifié. Les PR temporaires #239/#20 restent des preuves et ne sont ni fusionnées ni publiées.

Le candidat réunit les PR sources pertinentes sans intégrer les commits des branches temporaires. Les moteurs métier/chiffrement restent ceux des sources, avec les correctifs de sécurité/IDB et de récupération déjà testés. RC accepte désormais une base HTTPS à la racine, auparavant refusée par le validateur de build ; les URL avec identifiants, requête ou fragment restent refusées.

Les scripts `tools/build-drive-test.cjs` (RC) et `scripts/build-drive-test.mjs` (Vault) exigent `BUILD_SHA` à 40 caractères. Avec `GOOGLE_DRIVE_CONFIG` absent, ils produisent un profil fermé, `googleEnabled:false`, configuration `null`. Ce n'est pas une activation Google. Un client réel ne sera accepté qu'avec les six champs existants et les deux origines TEST exactes ; aucune clé secrète, phrase, dossier, email ou jeton dans cette configuration publique.

RC construit exclusivement depuis `tests/fixtures/preset.fake.json` et un relais fictif sans notification, avec les clés publiques de test du harnais. Il déchiffre et compare le préréglage produit. Les sorties sont limitées aux assets publics et données synthétiques ; aucun fichier chiffré du dossier personnel `encrypted/`, préréglage clair, artifact privé ou code du relais n'est publié. Géolocalisation interdite. Les deux PWA portent TEST, un bandeau visible et un lien réciproque TEST ; les empreintes de tous les fichiers figurent dans `fixture-manifest.json`.

Le numéro RC `prod-999` est réservé à la fixture de recette ; ses copies ne doivent jamais être utilisées comme progression personnelle ou importées dans la production. Chaque construction utilise les sels et IV aléatoires normaux : les octets chiffrés changent légitimement entre deux builds. Vérifier le manifeste du ZIP effectivement publié, sans prétendre à un chiffré déterministe.

Les nouvelles preuves Node couvrent 128 révisions A2 valides, 129 refusées avant HTTP et le budget 128 Mio. La borne mémoire utilise des métadonnées HTTP simulées et n'annonce aucun transfert Google de 128 Mio. Aucun historique n'est supprimé. Les copies sont indépendantes ; la limite demeure une restriction de disponibilité à traiter avant une promesse de récupération durable pour de gros historiques.

Après vérification des SHA/CI, dépôt uniquement dans le projet TEST correspondant, jamais dans `race-control-ipoower` / `control-vault-ipoower`. Le libellé Cloudflare « production » de ces deux projets isolés désigne leurs seules URL TEST. Contrôler version, octets, CSP et origine effective avant OAuth. Une connexion Cloudflare sécurisée est actuellement nécessaire car le connecteur refuse le téléversement des assets avec ses permissions présentes. Ne pas extraire ou élargir les secrets de production pour contourner ce refus.

Google Cloud doit utiliser un projet TEST dédié, Drive API + Picker, client Web commun, `drive.file`, clé Picker limitée aux référents TEST et à Picker API, aucun billing. L'administrateur et l'identité Drive de test sont deux rôles distincts ; ne jamais choisir automatiquement un compte personnel pour les essais. L'absence d'accès console ne constitue pas une configuration exécutée.

La recette réelle requiert : envoi de fixture, relecture exacte des octets, reçu, édition pendant envoi, perte de réponse après écriture, reprise du même identifiant, hors ligne, deux contextes indépendants, conflit sans écrasement, installation vierge, fermeture/réouverture et égalité exhaustive des valeurs. Distinguer fournisseur Google simulé, Google hébergé et iPhone physique. Aucun mot de passe, code, jeton ou HAR brut dans les preuves.

Rollback TEST : sélectionner le déploiement TEST précédent si nécessaire et autorisé, sans supprimer de déploiement, fichier Drive, cache, coffre, outbox ou historique. Un rollback logiciel ne restaure pas des données. Ne pas réintroduire une version ignorant un journal de récupération en cours.
Loading
Loading