fix: refuse declarations when source ownership is unknown - #54
Closed
albertovincenzi wants to merge 3 commits into
Closed
fix: refuse declarations when source ownership is unknown#54albertovincenzi wants to merge 3 commits into
albertovincenzi wants to merge 3 commits into
Conversation
…oes not name
`Stored::complete` is a fact about the whole NAMESPACE, not about this graph.
Refusing every declare on it means one row this build cannot read stops the
control plane for every application in the deployment — and `doc.rs` makes that
row a design goal, not an accident: `deny_unknown_fields` is there so a newer
build's document is unreadable by an older one. A rolling deploy or a rollback
therefore turns every declare and every sync into a 502 for tenants that share
nothing but a broker. Without the paging fix it is worse: past a thousand
stored graphs the inventory is permanently clamped and no declare ever succeeds
again.
The refusal only ever had teeth for a source Gate does not name. An owned
ingress and an interior queue are derived from `{app}.{graph}.{node}`, so no
other graph key can mint the same name and no unreadable document can be
claiming one. A user-declared ingress is free-form, and there the question is
real and still fails closed — the existing regression covers exactly that
shape.
Claude-Session: https://claude.ai/code/session_012K8u7BEJyd6nDNMCQAgH3z
Contributor
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.
Problema
Il controllo di ownership delle code fisiche introdotto dalla PR #32 consultava anche lo store, ma la lettura era best effort. Se la scansione falliva, veniva troncata dal broker o conteneva un documento non leggibile da questa versione di Gate, la dichiarazione proseguiva come se la coda fosse libera.
Su una replica non ancora riconciliata questo può avviare un secondo consumer group sulla stessa sorgente: entrambi ricevono ogni messaggio e l'egress viene duplicato.
Fix
La dichiarazione ora fallisce con 502 quando Gate non può dimostrare che l'inventario remoto sia completo:
Un conflitto verificato continua invece a rispondere 409. Restore e reconcile non cambiano comportamento: il fail closed riguarda soltanto una nuova mutazione richiesta dal caller.
Verifica per Alice
Il test live usa una seconda replica con registry vuoto e copre entrambi i casi:
In entrambi i casi la seconda dichiarazione riceve 502, nessun runtime viene avviato e la risposta nomina l'impossibilità di provare l'ownership esclusiva.
Controlli locali:
Dipendenze e trade-off
Questa PR è stacked su #32, perché protegge il controllo esteso a tutte le sorgenti fisiche. È consigliato integrare anche #28 prima di questa: #28 pagina l'intero store; senza #28, oltre il limite di una pagina Gate rifiuta in sicurezza nuove dichiarazioni invece di rischiare un doppio owner.
Questa PR chiude gli errori e gli inventari incompleti, ma non pretende di chiudere la finestra tra due scansioni simultanee su repliche diverse. Quella richiede un protocollo di lock con rinnovo e fencing, non un semplice TTL.