Memories / Documentation

Sur cette page

Autorisation du coffre

Ce document décrit le service d’autorisation du daemon local et l’interface HTTP d’autorisation du Center SaaS. Les opérations RPC locales ci-dessous sont disponibles dans le cœur partagé, la CLI et les outils d’autorisation MCP. Les commandes existantes memories mcp grant, memories mcp revoke, d’importation de tickets Center et d’audit du coffre utilisent les vérifications mises à jour du cœur.

Rôles et plafonds de portée

Rôle dans le coffre Portée maximale de l’autorisation Peut émettre ou déléguer ?
Lecteur read Non
Éditeur read_write Non
Administrateur read_write_delete Oui
Propriétaire allow_all Oui

L’omission de la portée signifie lecture, et non allow_all. Cela s’applique aux autorisations locales, à l’émission de tickets Center, aux autorisations statiques hébergées et à la création de membres. Le paramètre historique explicite write: true sélectionne toujours read_write ; write: false sélectionne read. write reste une portée d’écriture seule. allow_all nécessite une sélection explicite et un émetteur Propriétaire, même s’il couvre actuellement les mêmes opérations sur le contenu des ressources ordinaires que read_write_delete.

L’émission vérifie à la fois le rôle actuel de l’émetteur dans le coffre et, pour un appelant utilisant un jeton au porteur, la portée de l’autorisation émettrice. Une autorisation ne peut pas autoriser un autre coffre, dépasser l’un ou l’autre plafond, ni survivre à son parent. Les durées sont de 1–60 minutes. Les demandes de droits plus étendus ou plus longs échouent au lieu de réduire silencieusement la portée demandée. Les bénéficiaires doivent déjà être membres du coffre sélectionné. Une autorisation de contenu peut donner à un membre un accès supplémentaire au contenu, mais ne change pas son rôle : un Éditeur ou un Lecteur possédant une autorisation étendue ne peut toujours pas déléguer ni approuver des demandes.

Les enregistrements d’autorisation exposent id, vault, scope, issued_by (ID du membre), grantee, parent (ID de l’autorisation émettrice, ou null), depth et expiry en secondes Unix. Un ID d’autorisation est un identifiant opaque aléatoire indépendant de son jeton au porteur. L’émission renvoie le jeton une seule fois ; les listes d’accès/d’autorisations ne l’incluent jamais. Les ID d’autorisation et de demande et les ID de principal sont des identifiants opaques canoniques ; les ID de coffre présentés au client conservent la projection normale en ID courts.

L’émission locale d’autorisations par un Administrateur/Propriétaire nécessite un coffre déverrouillé, pas une élévation du terminal. La révocation ne nécessite pas non plus d’élévation, mais elle n’est autorisée qu’à l’émetteur de l’autorisation ou à un Administrateur/Propriétaire actuel de son coffre. La révocation est transitive. La suppression d’un émetteur ou d’un bénéficiaire, ou l’abaissement du rôle d’un émetteur en dessous de la portée qu’il a émise, invalide les autorisations concernées et leurs descendants lors de la validation de la politique, y compris les modifications de politique importées par synchronisation et celles effectuées après un redémarrage. Les autorisations persistent dans le Store chiffré local à l’appareil en ne conservant que le hachage SHA-256 du jeton au porteur et les métadonnées d’autorisation ; l’authentification compare les hachages en temps constant. La révocation et la suppression des descendants sont validées avec l’état chiffré. Le verrouillage supprime les autorisations en mémoire et les clés du Store, rendant toutes les autorisations inutilisables jusqu’au déverrouillage ; les autorisations non expirées reprennent après le déverrouillage ou le redémarrage du daemon. L’expiration absolue est persistée, et les autorisations expirées et leurs descendants sont purgés au chargement et lors des cycles du daemon. Les autorisations ne sont pas exportées par la synchronisation du coffre ni par les sauvegardes de récupération.

Les modifications d’appartenance et les approbations d’appareils conservent leurs vérifications d’élévation existantes, en plus de la nouvelle exigence Administrateur/Propriétaire. La création d’une invitation nécessite désormais une appartenance Administrateur/Propriétaire dans au moins un coffre local. Les appelants sans coffre et ceux qui ne disposent que d’appartenances Éditeur/Lecteur sont refusés par défaut. Les Administrateurs peuvent gérer l’appartenance Administrateur, mais ne peuvent pas ajouter/supprimer/modifier un Propriétaire. Les changements de propriété utilisent l’opération signée de transfert de propriété et préservent exactement un Propriétaire.

Demandes de permission

Bénéficiaires désignés et profondeur de délégation

Le daemon comme le Center hébergé refusent l’émission à un bénéficiaire dont le rôle est supérieur au rôle effectif de l’émetteur, même lorsque la portée de contenu demandée est seulement read. Center refuse également le bénéficiaire réservé center-admin, y compris les autorisations précédemment persistées ayant ce sujet.

Un appelant par autorisation utilise l’autorité d’une autorisation dont le sujet diffère de son véritable émetteur (subject != issued_by). Ces appelants peuvent créer des demandes, mais ne peuvent approuver, rejeter, annuler ni réclamer aucune demande de permission, y compris la leur. Le daemon renvoie Unauthorized ; Center renvoie HTTP 403. Ces appelants ne sont pas des approbateurs admissibles. Les autorisations émises pour soi-même conservent leurs règles existantes de demande ; les réclamations Center nécessitent toujours l’identifiant durable de membre du demandeur. Les jetons au porteur durables de membre Center constituent une autorité de membre, et non une autorité d’autorisation déléguée.

Le daemon conserve sa liaison exacte avec l’identifiant du demandeur : une demande créée avec un jeton au porteur de bénéficiaire désigné ne peut pas ensuite être réclamée avec un identifiant de membre différent. Recréez cette demande avec l’identifiant de membre ou l’identifiant émis pour soi-même qui la réclamera. Center lie au contraire les réclamations au jeton au porteur durable de membre du demandeur.

Les deux implémentations définissent pub const MAX_DELEGATION_DEPTH: u32 = 2. Les autorisations émises directement par un membre ont une profondeur de 1. L’émission utilisant l’autorité d’une autorisation, y compris le parent d’une approbation différée au moment de la réclamation, a une profondeur parent.depth + 1 ; la profondeur 3 est refusée. depth est persisté et inclus dans les résumés d’autorisation, les réponses d’émission, les vues d’accès et les listes d’autorisations émises. Les anciens enregistrements sans depth sont reconstruits à partir de leur chaîne de parents (une autorisation sans parent est de profondeur 1). Une ascendance d’autorisation manquante/cyclique ou dépassant la limite est refusée par défaut et purgée au chargement. Les identifiants internes durables de membre Center sont de profondeur 0, et ne sont pas des autorisations déléguées.

L’émission déléguée préserve le véritable émetteur à travers la chaîne de parents, au lieu de transformer un bénéficiaire désigné en principal émettant pour lui-même. Les chaînes historiques existantes sont également vérifiées lors de la détermination du véritable émetteur de l’appelant.

Les anciennes approbations différées enregistrées au moyen d’une autorisation de bénéficiaire désigné sont également refusées par défaut lors de la réclamation ; obtenez une nouvelle approbation auprès d’une autorité de membre admissible.

Changements incompatibles : les destinataires de rôle supérieur et les destinataires center-admin ne peuvent plus recevoir d’autorisations ; les jetons au porteur de bénéficiaire désigné ne peuvent plus participer aux décisions/annulations/réclamations de permission ; les chaînes de plus de deux autorisations ne sont plus utilisables. Utilisez un identifiant de membre pour les décisions et les réclamations de permission, et émettez une nouvelle autorisation racine lorsqu’une délégation supplémentaire dépasserait la limite.

Tout membre actuel peut soumettre une demande pour son propre accès dans un coffre :

{
  "op": "request_create",
  "vault": "VAULT",
  "target": {"type": "scope", "scope": "read_write"},
  "reason": "Update the shared project notes",
  "duration_minutes": 15,
  "approvers": []
}

target est soit {"type":"scope","scope":"..."} (la portée vaut par défaut read), soit {"type":"role","role":"editor"}. Le motif, la durée et les approbateurs sont facultatifs. L’approbation de portée vaut par défaut 30 minutes si la durée est omise. Les changements de rôle sont permanents : une durée dans une demande de rôle est refusée, et les appelants par autorisation limitée dans le temps ne peuvent pas approuver un changement de rôle permanent. L’approbation d’une demande de rôle nécessite la même élévation liée à l’appelant que les changements directs de rôle de membre. Un Propriétaire approuvant une demande de rôle Propriétaire effectue un transfert de propriété signé.

Une liste d’approbateurs vide diffuse la demande à tous les membres Administrateur/Propriétaire actuels de ce coffre. Sinon, seuls les ID de membre listés peuvent la décider ; chaque ID listé doit être un membre Administrateur/Propriétaire à la création, et l’admissibilité est revérifiée lors de la décision. Les Lecteurs et les Éditeurs ne peuvent pas être listés comme approbateurs. Le demandeur ne peut pas approuver ni rejeter sa propre demande, même comme Administrateur/Propriétaire ou approbateur nommé ; il peut toujours l’annuler. L’approbation de portée/rôle doit respecter le rôle et la portée du jeton au porteur de l’approbateur, et l’expiration de portée doit respecter celle du parent. Une approbation dépassant le plafond laisse la demande en attente.

Les demandes ont exactement une transition de pending vers approved, rejected ou cancelled. Seul le demandeur peut annuler une demande en attente. L’approbation de portée enregistre les paramètres d’autorisation sans créer de jeton au porteur. Le demandeur utilise request_claim une seule fois pour créer et recevoir le jeton ; request_list ne renvoie que les métadonnées. La création/génération et la durée d’autorisation commencent à la réclamation, plafonnées par l’expiration enregistrée du parent. L’état d’approbation et de réclamation survit au verrouillage/redémarrage, mais une autorité d’approbation révoquée/expirée ne peut pas autoriser une réclamation. Aucun jeton en clair n’est conservé dans l’état de demande ni dans l’état persisté du Store. Les autorisations réclamées survivent au verrouillage/redémarrage sous forme de hachages et de métadonnées. Les demandes et les jetons ne sont pas exportés dans la synchronisation du coffre.

request_list renvoie les demandes de l’appelant (y compris celles déjà décidées) ainsi que les demandes en attente qu’il est admissible à décider. Les autres membres ne peuvent pas consulter une demande dirigée. Un coffre accepte au maximum 1,000 demandes stockées ; les motifs sont limités à 4,096 octets. Au maximum 10,000 autorisations peuvent être actives à la fois, aussi bien sur le daemon local que sur un Center hébergé.

Limites en attente : un demandeur peut détenir au maximum 20 demandes en attente par coffre, et un coffre au maximum 200 demandes en attente ; une création dépassant la limite échoue avec une erreur de limite (HTTP 429 sur un Center hébergé). Les demandes en attente et les demandes approuvées mais non réclamées expirent après 7 jours (auditées comme request.expire, acteur system) ; les demandes décidées sont supprimées 30 jours après leur dernière transition.

Opérations RPC et interfaces

Les noms JSON op du daemon sont :

Opération Champs Autorité
access_list vault Administrateur/Propriétaire
grant_list vault Les Administrateurs/Propriétaires voient tout ; les autres membres actuels voient uniquement les autorisations qu’ils ont émises
grant_issue vault, minutes, scope facultatif, grantee Administrateur/Propriétaire
grant_revoke vault, id Émetteur ou Administrateur/Propriétaire
request_create vault, target, reason facultatif, duration_minutes, approvers Tout membre
request_list vault Demandes propres ou demandes en attente admissibles
request_approve vault, id Administrateur/Propriétaire admissible
request_claim vault, id Identifiant du demandeur initial de la demande de portée approuvée ; une seule fois
request_reject vault, id, reason facultatif Administrateur/Propriétaire admissible
request_cancel vault, id Demandeur de la demande en attente
audit vault, verify_only Administrateur/Propriétaire

Les anciennes opérations mcp_grant et mcp_revoke restent prises en charge. Les appelants par jeton au porteur ne peuvent utiliser ces RPC d’autorisation que pour le coffre de leur autorisation ; cela ne permet pas à MCP d’hériter de l’élévation du terminal ni d’accéder aux identifiants stockés. La FFI mobile continue de refuser la gestion des autorisations et les nouvelles opérations de demande de permission ; aucun changement de l’ABI native n’est nécessaire.

access_list renvoie principals regroupés sous owner, admin, editor et reader, ainsi que les grants actives, les devices (appareils autorisés et non révoqués de la politique du coffre : device, member propriétaire, name ; la politique n’enregistre aucune date de création), pending_requests et approved_unclaimed_requests (chacun avec id, requester, target portée/rôle, liste approvers ou "broadcast", created et expires en secondes Unix). La visibilité reste Administrateur/Propriétaire. grant_list renvoie {"vault":"VAULT","grants":[...]} sans groupes de principaux. Chaque autorisation émise contient id, parent (null pour une autorisation racine), issued_by, grantee, scope, vault, expiry en secondes Unix, generation, depth et created en secondes Unix lorsque disponible. La génération locale est la génération de l’état validé à l’émission, non la génération actuelle au moment de la liste. Les autorisations expirées/révoquées sont exclues. Les Administrateurs/Propriétaires peuvent lister toutes les autorisations du coffre ; les autres membres actuels ne peuvent lister que leurs propres autorisations émises, et non celles simplement reçues. Les appelants par jeton au porteur restent liés au coffre de leur autorisation. Aucun jeton, hachage de jeton au porteur ni corps de ressource n’apparaît dans l’une ou l’autre réponse. Le RPC du daemon, le MCP grant_list et memories grant list VAULT partagent cette réponse de service.

Les enveloppes CLI sont implémentées avec ces commandes exactes (les ID sont opaques) :

memories access list VAULT
memories grant issue VAULT --minutes N [--scope S] [--grantee ID]
memories grant list VAULT
memories grant revoke VAULT ID
memories request create VAULT [--scope S | --role R] [--reason T] [--duration M] [--approver ID]...
memories request list VAULT
memories request approve VAULT ID
memories request claim VAULT ID
memories request reject VAULT ID [--reason T]
memories request cancel VAULT ID
memories audit list VAULT [--verify-only]

L’ancienne syntaxe memories audit VAULT [--verify] reste prise en charge. La portée vaut par défaut read ; les demandes locales de portée sans durée conservent la valeur par défaut d’approbation de 30 minutes du daemon. Les demandes de rôle ne peuvent pas inclure de durée. La sortie est du JSON dans l’enveloppe normale de la CLI.

Les équivalents du Center hébergé utilisent les routes HTTP d’autorisation :

memories center access VAULT
memories center grant issue VAULT --minutes N [--scope S] [--grantee ID]
memories center grant list [VAULT]
memories center grant revoke ID
memories center request create VAULT [--scope S] [--reason T] [--duration M] [--approver ID]...
memories center request list [VAULT]
memories center request approve ID
memories center request claim ID
memories center request reject ID [--reason T]
memories center request cancel ID
memories center audit [--vault V] [--format json|jsonl]

Ces commandes acceptent --center-url, sinon elles utilisent MEMORIES_CENTER_URL ou le Center SaaS configuré. Elles utilisent MEMORIES_CENTER_TOKEN s’il est défini, sinon MEMORIES_CENTER_ADMIN_TOKEN ; les échecs de permission ne sont pas retentés avec un autre jeton au porteur. Les demandes hébergées prennent en charge la portée, pas les changements locaux de rôle. La portée vaut par défaut read et la durée de demande 30 minutes. L’export d’audit JSONL affiche une entrée JSON par ligne sans l’enveloppe CLI ; les autres sorties utilisent l’enveloppe JSON.

Les outils MCP du daemon sont access_list, grant_issue, grant_list, grant_revoke, request_create, request_list, request_approve, request_claim, request_reject, request_cancel et audit_list. Leurs arguments suivent les champs RPC ci-dessus (minutes pour l’émission d’autorisation, target et duration_minutes pour la création de demande, et verify_only pour l’audit). Une portée d’autorisation ou une cible de demande omise vaut par défaut read. Chaque appel utilise la capacité MCP existante, jamais l’élévation du terminal ni un jeton au porteur du Center hébergé.

Le Center SaaS implémente GET /v1/access/{vault}, POST/GET /v1/grants, DELETE /v1/grants/{id}, POST/GET /v1/requests, POST /v1/requests/{id}/approve|claim|reject|cancel et GET /v1/audit réservé aux Administrateurs/Propriétaires. Ces routes nécessitent le mode hébergé (--data). Consultez center.md pour les corps HTTP exacts, les paramètres de requête, les réponses et les fichiers persistés.

Autorisation du Center SaaS

Les membres hébergés ont un role explicite facultatif (reader, editor, admin, owner), indépendant de leur scope de contenu. Lorsque role est omis, les niveaux de portée existants correspondent à Lecteur (read), Éditeur (write/read_write), Administrateur (read_write_delete) ou Propriétaire (allow_all). Le jeton au porteur de l’opérateur agit comme le Propriétaire center-admin sur tous les coffres hébergés. Les principaux à jeton au porteur statique utilisent des ID static:OPAQUE_ID et la même correspondance portée-rôle. Les ID de membre ne peuvent pas utiliser le nom réservé center-admin. La portée de contenu n’élève pas un destinataire Lecteur/Éditeur à un rôle administratif.

POST /v1/grants donne à scope la valeur par défaut read et à duration_minutes la valeur 30 ; minutes est un alias de durée. L’émission nécessite le rôle Administrateur/Propriétaire, avec les mêmes limites de rôle/portée/coffre/expiration que l’émission locale. Les réponses utilisent subject pour le destinataire et incluent parent, issued_by, expiry, generation et depth. Les jetons d’autorisation apparaissent uniquement dans les réponses d’émission/réclamation, jamais dans l’approbation, les listes ni l’audit. Le destinataire est par défaut l’émetteur pour les appelants membres ; un grantee explicite doit désigner un principal existant dans le coffre sélectionné. Une émission par l’opérateur sans grantee crée un principal d’autorisation anonyme identifié par son ID d’autorisation, jamais un sujet center-admin. Cela s’applique également à l’émission de tickets hébergée.

Chaque membre hébergé possède un compteur de génération persisté. Les autorisations créées figent les générations de l’émetteur et du destinataire à l’émission ; l’authentification ne les actualise jamais. La modification de la portée, du rôle ou du coffre d’un membre, ou sa suppression, incrémente uniquement la génération de ce membre. Les compteurs des membres supprimés persistent afin que la recréation d’un ID ne réinitialise pas sa génération. La suppression ou la mise à jour révoque les autorisations émises par ou pour ce membre et tous leurs descendants, avec des enregistrements d’audit, tandis que les autorisations sans rapport continuent de fonctionner. Le champ public generation est la génération du destinataire à l’émission. Les principaux statiques et opérateur ont une génération fixe. Les identifiants durables de membre sont rétablis uniquement lors de la transition explicite de politique, pas par l’authentification.

Les autorisations créées hébergées survivent au redémarrage dans DIR/grants.json, accessible uniquement au propriétaire, et contenant seulement les hachages SHA-256 des jetons au porteur, les générations figées, les métadonnées d’expiration/parent et les révocations. La comparaison des hachages est en temps constant. Les autorisations expirées et leurs descendants sont purgés au chargement, périodiquement et lors de l’authentification/émission. Le verrouillage supprime les clés du Store et suspend les autorisations sans les révoquer ; les autorisations non expirées et les identifiants statiques/durables reprennent après le déverrouillage. Les échecs de persistance verrouillent le service et nécessitent une réparation/un redémarrage par l’opérateur plutôt que de risquer une résurrection.

POST /v1/requests accepte vault, les champs facultatifs scope, reason, duration_minutes (alias duration) et approvers. Un approvers vide/omis diffuse via les listes de demandes en attente des Administrateurs/Propriétaires admissibles ; les ID fournis dirigent la demande. GET /v1/requests renvoie les demandes en attente appartenant à l’appelant ou relevant de son autorité d’approbation, ainsi que les demandes du demandeur approuvées mais non réclamées, éventuellement filtrées par vault. L’approbation et le rejet nécessitent tous deux l’autorité de rôle/portée/coffre/expiration de l’approbateur sélectionné. Le demandeur ne peut pas approuver ni rejeter sa propre demande, même comme Administrateur/Propriétaire ou approbateur nommé ; seul le demandeur peut l’annuler. Une seule décision est sérialisée et persistée ; les répétitions renvoient 409. L’approbation renvoie uniquement les métadonnées request avec status: approved, claimed: false et les limites validées de portée/durée/émetteur ; elle ne crée pas d’autorisation et ne renvoie pas de jeton. Le demandeur appelle ensuite POST /v1/requests/{id}/claim avec son jeton au porteur durable de membre, et reçoit request plus une réponse grant unique. Les approbateurs, les autres membres et les autres autorisations pour le même sujet ne peuvent pas réclamer avec ces identifiants. Une seconde réclamation renvoie 409. La génération, la date de création et la durée commencent à la réclamation, avec une expiration plafonnée par l’expiration enregistrée de l’autorité d’approbation. Des identifiants d’approbation révoqués/expirés ou des générations de membre modifiées ne peuvent pas servir à réclamer.

Le daemon utilise le même flux de création différée pour les demandes de portée : request_approve stocke les limites d’approbation et request_claim renvoie les métadonnées d’autorisation plus token une seule fois. Les appelants locaux authentifiés par le système d’exploitation doivent toujours être le membre demandeur ; MCP doit présenter la capacité exacte ayant créé la demande, pas une autre autorisation pour le même sujet. Les listes ne renvoient jamais de jetons. Les approbations de rôle restent des modifications immédiates de politique et n’ont pas d’autorisation réclamable. L’état chiffré du Store et DIR/requests.json ne contiennent que les métadonnées de demande ; les autorisations ne persistent que les hachages des jetons au porteur. Le démarrage rapproche les décisions et réclamations Center de l’audit vérifié, afin que des sauvegardes interrompues de métadonnées ne puissent pas rouvrir une décision ou une demande réclamée. Si une réponse de réclamation réussie est perdue, le jeton ne peut pas être récupéré à nouveau ; demandez plutôt une nouvelle approbation.

Format d’audit et vérification

Les entrées d’audit locales conservent vault, previous, sequence, timestamp, action, object, result, le certificat de signature et la signature. Les nouveaux champs facultatifs de premier niveau sont actor, subject (bénéficiaire), scope, expiry, parent, reason, issued_by, via_grant et request_id. L’acteur identifie le membre agissant ; le signataire identifie l’appareil daemon enregistrant l’événement. Une action déléguée peut donc avoir un acteur et un utilisateur signataire différents. Aucun mot de passe, identifiant stocké ni jeton au porteur n’est inclus dans les entrées d’audit.

Les entrées produites avec l’autorité d’une autorisation incluent issued_by (le véritable émetteur) et via_grant (l’ID d’autorisation de l’appelant) ; actor reste le sujet de l’autorisation. L’exception des événements d’émission (mcp.grant / grant.issue de Center) enregistre le véritable émetteur comme actor et le bénéficiaire comme subject, y compris pour l’émission déléguée. Les deux champs facultatifs utilisent les valeurs par défaut serde et sont omis lorsqu’ils sont absents, préservant la sérialisation et la vérification des anciens audits signés et des journaux JSONL Center. Les audits de contenu hébergé portent la même attribution dans le Store partagé.

Les audits sont des chaînes de hachage signées par appareil. previous pointe vers le hachage SHA-256 de l’entrée signée sérialisée précédente, et la table d’audit est indexée par ces hachages. Vault::verify valide les signatures, les hachages, la continuité de la séquence et les invariants existants de l’historique du coffre. Les anciens enregistrements omettent tous les nouveaux champs et conservent exactement leurs anciens octets de signature et hachages. Les nouveaux champs utilisent les valeurs par défaut serde et sont omis lorsqu’ils sont absents ; les détails renseignés sont couverts par la signature.

Les événements incluent device.authorize, mcp.grant, mcp.grant.center, mcp.revoke, session.lock, session.unlock et request.create|request.approve|request.claim|request.reject|request.cancel, aux côtés des événements existants d’appartenance et d’appareil. Les verrouillages explicites propagent les erreurs de persistance de l’audit, mais effacent tout de même l’état déverrouillé. Les verrouillages de cycle de vie/inactivité tentent un audit et effacent toujours l’état, même si la persistance échoue ; ils ne doivent pas laisser les secrets déverrouillés pour préserver un enregistrement d’audit. Les échecs à l’état verrouillé ne peuvent pas signer d’audit.

Le Center SaaS possède une chaîne SHA-256 séparée, en ajout seul, de mode 0600, DIR/audit.jsonl, qui n’est pas le format d’audit signé local. GET /v1/audit nécessite Administrateur/Propriétaire, accepte vault et format=json|jsonl, et vérifie la chaîne complète avant filtrage/export. Les administrateurs liés à un coffre ne peuvent pas lire les événements d’un autre coffre ; l’opérateur peut aussi voir les événements globaux de verrouillage/déverrouillage/inscription. Les entrées contiennent sequence, timestamp, prev_hash, hash, action, actor, subject, scope, vault, expiry, parent, reason, request_id et object ; les détails facultatifs valent null. Le hachage couvre le tuple sérialisé (sequence, timestamp, prev_hash, event_fields) ; prev_hash vaut null pour la première entrée et le hachage de l’entrée précédente ensuite.

verify_audit_chain(path) dans crates/center/src/saas/audit.rs vérifie les hachages, la continuité de la séquence, les hachages précédents et les lignes JSONL complètes. Le démarrage vérifie le fichier existant ; l’ajout/la lecture comparent également sa tête à la tête connue du processus en cours. Les événements incluent device.authorize, grant.issue, grant.revoke, member.add|member.set|member.remove, session.lock|session.unlock et request.create|request.approve|request.claim|request.reject|request.cancel. Les événements de réclamation enregistrent le demandeur comme acteur et l’ID de l’autorisation créée comme objet, jamais le jeton. Les échecs d’ajout à l’audit ou de persistance de demande/membre verrouillent le service hébergé, définissent restart_required et bloquent le déverrouillage à distance jusqu’à ce qu’un opérateur le répare et le redémarre. Les mutations d’autorisation et les décisions de permission s’arrêtent également tant que restart_required est défini ; l’inspection en lecture seule par l’opérateur reste disponible. Ces chaînes sans clé ne protègent pas contre un opérateur réécrivant le journal entier ou rétablissant une ancienne version de tous les fichiers ; des garanties plus fortes nécessitent des ancrages externes de la tête.

Modèle de menace et changements de comportement

  • Les appelants locaux authentifiés par le système d’exploitation agissent comme le membre de l’appareil déverrouillé. Les processus malveillants du même utilisateur restent à l’intérieur de la frontière de confiance existante du terminal.
  • Les jetons au porteur de capacité sont des secrets ; quiconque en possède un peut utiliser son autorité limitée jusqu’à la révocation, au verrouillage ou à l’expiration. Un jeton au porteur ne peut pas élargir sa propre portée, sortir de son coffre, prolonger son expiration ni contourner le rôle de délégation de son sujet.
  • La révocation n’efface pas les textes en clair ou les clés précédemment copiés et ne peut pas atteindre instantanément les pairs hors ligne. L’invalidation de politique et d’autorisation prend effet sur le daemon qui a validé la politique mise à jour.
  • Les chaînes de hachage détectent les altérations par rapport à un état connu, pas un retour complet de la base de données à un état antérieur ni les événements omis par un appareil compromis. Des ancrages externes et un audit de sécurité indépendant restent nécessaires pour des garanties plus fortes.
  • Changements incompatibles : l’émission sans portée est en lecture seule ; les Éditeurs/Lecteurs ne peuvent pas créer d’autorisations ni d’invitations ; l’accès à l’audit nécessite Administrateur/Propriétaire plutôt qu’une élévation ; les modifications de membre invalident les autorisations déléguées. La nouvelle émission d’autorisation Administrateur/Propriétaire et la révocation par l’émetteur/Administrateur ne nécessitent plus d’élévation. La création d’invitation sans coffre est refusée plutôt que de traiter silencieusement un appelant comme un administrateur.
  • Changement incompatible : l’approbation ne crée ni ne livre plus de jeton au porteur, et les listes de demandes ne livrent plus de jeton au porteur approuvé. Les demandeurs doivent explicitement réclamer une seule fois. Les demandes précédemment approuvées sans limites d’approbation différée enregistrées ne peuvent pas être réclamées ; créez une nouvelle demande. Les autorisations existantes émises séparément continuent de suivre leurs règles normales d’expiration/révocation.

Consultez SECURITY.md pour les limites et center.md pour les frontières de confiance distinctes du Center limité aux tickets et du Center hébergé utilisant la clé de l’opérateur.

Limites, expiration et conservation des demandes de permission

S’applique au daemon (demandes dans le Store chiffré) comme au Center (requests.json) :

  • MAX_PENDING_PER_REQUESTER_PER_VAULT = 20 et MAX_PENDING_PER_VAULT = 200 ne comptent que les demandes en attente. Les demandes décidées, annulées, expirées et approuvées mais non réclamées ne comptent pas dans ces limites. (Cela remplace l’ancien plafond global de 1000 demandes, qui comptait toutes les demandes jamais faites.) Si vous dépassez une limite, le daemon renvoie une erreur de limite et Center renvoie HTTP 429.
  • PENDING_REQUEST_TTL = 7 days : une demande en attente plus ancienne passe à l’état expired. Elle est auditée comme request.expire avec l’acteur system, et ne peut plus être approuvée. Une demande de portée approuvée qui n’a pas été réclamée dans les 7 jours suivant l’approbation expire également, de la même façon, et ne peut plus être réclamée ensuite.
  • REQUEST_RETENTION = 30 days : les demandes rejetées, annulées, expirées ou réclamées sont supprimées après ce délai à compter de leur dernière transition (l’horodatage decided, ou created pour les anciens enregistrements qui n’en ont pas).
  • L’expiration et la suppression se produisent à la demande : le daemon les exécute au début de toute demande d’autorisation, et Center les exécute lors de la création, de la liste, de la décision et de la réclamation de demandes. Rien ne les exécute au démarrage.
  • Le rapprochement au démarrage de Center ignore les entrées d’audit pour les demandes supprimées et accepte les entrées request.expire. Une demande expired doit avoir une expiration auditée. Les ID de demande sont des valeurs aléatoires de 128 bits qui ne sont jamais réutilisées, donc une demande supprimée (y compris une demande réclamée) n’existe plus et ne peut pas être réclamée. Pour cette raison, Center ne conserve pas d’ensemble séparé de marqueurs de suppression.