feat: un document en store public sert son ReadCap, une référence nue suffit
Le modèle amont est explicite dans `PublicRepoLinkV0` : le lien ne porte AUCUN `read_cap`, et son commentaire dit pourquoi — *"The latest ReadCap of the branch will be downloaded from the outerOverlay, if the peer brokers listed below allow it […] the public site are served differently by brokers"* (engine/net/src/types.rs:5098). La clé n'est pas remise par un émetteur : elle est donnée par le réseau à qui la demande, parce que le broker a épinglé l'overlay externe (`expose_outer`). La bibliothèque refusait jusqu'ici la forme sans cap quel que soit le store. Sûr dans le bon sens, mais une application ne pouvait pas exprimer « fais circuler, la référence suffit » — le seul acte que le modèle rend gratuit — et son unique contournement était de distribuer la clé, ce qui détruit la confidentialité composable. `emulated-verifier/public-store.ts` émule le mécanisme SANS toucher à la garde. La possession reste l'unique critère : un document public est lisible non par exception mais parce que son cap est *obtenable*. Chaque porte de lecture demande d'abord (`readUnion`, `docs.sparqlQuery`, `ensureRepoOpen`, `documentInboxAddress`), puis le chemin ordinaire s'applique. Lire n'est pas écrire. Ce que le store sert est un droit de LECTURE : `learnFromPublicStore` le classe à part et `assertMayWrite` refuse l'écriture dessus. Sans cela une référence nue achetait une écriture, ce qu'aucun store amont n'accorde. Autres conséquences : - `recordInPublicStore` (marquer + frapper) devient `markInPublicStore` (marquer). Frapper un second cap à côté de celui qu'on vient de télécharger donnerait deux clés différentes le jour où la constante devient un secret. - `hasCap` quitte la porte polyfill : il se lisait « ai-je le droit de lire ceci ? » et un document public y répondait `false` jusqu'à ce qu'on demande son cap. Aucun appelant hors des tests. - Les tests cross-user ne font plus traverser de cap par une variable JS : Bob n'obtient que la référence nue, comme une vraie application. Écarts documentés plutôt que masqués : le pari sur un modèle DÉCLARÉ (`expose_outer` est câblé à `false` côté client et `ExtTopicSyncReq` est `unimplemented!()`), la découverte limitée à ce qu'on sait déjà nommer, `useShape` qui n'a pas d'await à dépenser, et l'absence de `locator`. 179 tests unitaires, e2e 42/42 contre le broker en ligne.
This commit is contained in:
@@ -160,6 +160,11 @@ describe("access-log: ON via configure({ debugAccessLog: true })", () => {
|
||||
it("sparqlQuery emits a READ line with identity, nuri, label, and row-count", async () => {
|
||||
injectFake(true);
|
||||
setCurrentUser("alice");
|
||||
// `setCurrentUser` FIRES the connection work; draining it here (and only then
|
||||
// dropping the caps it filed) is what keeps this test about the log and not about
|
||||
// whether a background connect happened to win the race.
|
||||
await connectedUser();
|
||||
resetCaps();
|
||||
const { lines, restore } = spyConsoleLog();
|
||||
try {
|
||||
await sparqlQuery("sid-log", "SELECT * {}", undefined, "did:ng:o:q", "myLabel");
|
||||
@@ -178,6 +183,11 @@ describe("access-log: ON via configure({ debugAccessLog: true })", () => {
|
||||
it("sparqlUpdate emits a WRITE line with identity, anchor nuri, and label", async () => {
|
||||
injectFake(true);
|
||||
setCurrentUser("alice");
|
||||
// `setCurrentUser` FIRES the connection work; draining it here (and only then
|
||||
// dropping the caps it filed) is what keeps this test about the log and not about
|
||||
// whether a background connect happened to win the race.
|
||||
await connectedUser();
|
||||
resetCaps();
|
||||
const { lines, restore } = spyConsoleLog();
|
||||
try {
|
||||
await sparqlUpdate("sid-log", "INSERT DATA {}", "did:ng:o:w", "writeLabel");
|
||||
@@ -194,6 +204,11 @@ describe("access-log: ON via configure({ debugAccessLog: true })", () => {
|
||||
it("docCreate emits a WRITE line with identity and the returned nuri", async () => {
|
||||
injectFake(true);
|
||||
setCurrentUser("alice");
|
||||
// `setCurrentUser` FIRES the connection work; draining it here (and only then
|
||||
// dropping the caps it filed) is what keeps this test about the log and not about
|
||||
// whether a background connect happened to win the race.
|
||||
await connectedUser();
|
||||
resetCaps();
|
||||
const { lines, restore } = spyConsoleLog();
|
||||
try {
|
||||
await docCreate("sid-log", "Graph", "data:graph", "store");
|
||||
|
||||
Reference in New Issue
Block a user