memory.sharing.identity¶
memory.sharing.identity ¶
Identity, keypair, and identity-registry models for firm-wide sharing.
Three concerns live here:
-
Keypair generation — :func:
generate_keypairmints a freshageX25519 keypair (viapyrage; we never hand-roll key material). -
The local machine identity — :class:
LocalIdentitybinds this machine's logicalidto its keypair and is persisted at~/.angelo/identity.yaml. This file holds the PRIVATE key and MUST NEVER be committed to any repo. It lives under the user's HOME directory (not inside the workspace) precisely so it cannot be swept into a git commit; :func:save_local_identityalso chmods it to0600. -
The identity registry — :class:
IdentityRegistrymapsid -> public key(plus optional display name and github handle used only for attribution / discovery). The registry holds PUBLIC keys only, so it is safe to share and version in a repo (e.g. beside.memory/asidentities.yaml). It is the enforcement anchor: whoever is in the registry with a public key can be encrypted to.
KeyPair
dataclass
¶
A freshly generated identity keypair (encryption + signing).
public_key is an age1... recipient string and private_key an
AGE-SECRET-KEY-... string — the age X25519 keypair used for
encryption. age has no signing primitive, so an independent Ed25519
signing keypair rides alongside it (URL-safe base64 of the raw key bytes;
see :mod:memory.sharing.signing). The signing fields are optional and
default to None so legacy callers/keypairs without a signing key keep
working. Guard the private keys like passwords.
Source code in memory/sharing/identity.py
RegistryEntry
dataclass
¶
One published identity: a logical id bound to a public key.
display_name and github are optional and used only for attribution /
discovery — never for access control (the public key is the anchor).
signing_public_key is the identity's Ed25519 signing public key (base64,
public part only); optional so legacy registries without it still parse.
Source code in memory/sharing/identity.py
LocalIdentity
dataclass
¶
This machine's identity: a logical id plus its keypair(s).
Persisted (with the private keys) to ~/.angelo/identity.yaml. Carries both
the age X25519 encryption keypair and the Ed25519 signing keypair; the
signing fields are optional (default None) so a legacy identity file with
no signing key still loads.
Source code in memory/sharing/identity.py
to_pyrage_identity ¶
to_registry_entry ¶
to_registry_entry() -> RegistryEntry
The public-only :class:RegistryEntry for publishing to the registry.
Source code in memory/sharing/identity.py
IdentityRegistry
dataclass
¶
An id -> RegistryEntry map of publishable (public-key) identities.
Source code in memory/sharing/identity.py
member_ids ¶
public_key_for ¶
The public key for recipient_id, or None if unregistered.
signing_public_key_for ¶
The Ed25519 signing public key for recipient_id.
Returns None when the id is unregistered or when the registered
entry predates signing (legacy entry with no signing_public_key).
Source code in memory/sharing/identity.py
public_keys_for ¶
Resolve ids to public keys, silently dropping unregistered ids.
Source code in memory/sharing/identity.py
with_entry ¶
with_entry(entry: RegistryEntry) -> 'IdentityRegistry'
A copy of this registry with entry added/overwritten (immutably).
default_identity_path ¶
Path of this machine's private identity file: ~/.angelo/identity.yaml.
Under HOME (never the workspace) so the private key cannot be committed.
default_registry_path ¶
Default path of the shared identity registry (.memory/identities.yaml).
Anchored to the memory store so it is versioned alongside the tree. Contains public keys only, so committing it is safe. Callers may override the path.
Source code in memory/sharing/identity.py
generate_keypair ¶
generate_keypair() -> KeyPair
Generate a fresh identity keypair: an age X25519 pair + Ed25519 signing pair.
Source code in memory/sharing/identity.py
save_local_identity ¶
save_local_identity(identity: LocalIdentity, path: Path | str | None = None) -> Path
Write identity (including the private key) to disk, chmod 0600.
Defaults to ~/.angelo/identity.yaml. The chmod is best-effort (a no-op on
filesystems that don't support POSIX modes, e.g. some Windows setups).
Source code in memory/sharing/identity.py
load_local_identity ¶
load_local_identity(path: Path | str | None = None) -> LocalIdentity | None
Load this machine's identity, or None if the file is absent/invalid.
The public key is derived from the private key when the file omits it, so an
identity file carrying only id + private_key still loads.
Source code in memory/sharing/identity.py
create_identity ¶
create_identity(identity_id: str, *, display_name: str | None = None, github: str | None = None, path: Path | str | None = None, overwrite: bool = False) -> LocalIdentity
Generate a keypair, build a :class:LocalIdentity, and persist it.
Refuses to clobber an existing identity file unless overwrite=True — a
lost private key cannot be recovered, so overwriting is opt-in.
Source code in memory/sharing/identity.py
load_registry ¶
load_registry(path: Path | str | None = None) -> IdentityRegistry
Load the shared identity registry, or an empty one if absent/invalid.
Expected YAML shape::
identities:
alice:
public_key: age1...
display_name: Alice
github: alice-gh
signing_public_key: ... # optional Ed25519 signing public key (base64)
bob: age1... # shorthand: id -> public key (no signing key)
Malformed rows are skipped rather than raising, so a partially-authored registry still loads the good rows.
Source code in memory/sharing/identity.py
save_registry ¶
save_registry(registry: IdentityRegistry, path: Path | str | None = None) -> Path
Write the identity registry (public keys only) to disk.