Skip to content

CyberWealth: people's own connected-app keys - #109

Merged
leonardoaraujosantos merged 6 commits into
mainfrom
feat/cyberwealth-user-keys
Sep 27, 2026
Merged

leonardoaraujosantos merged 6 commits into
mainfrom
feat/cyberwealth-user-keys

Conversation

@leonardoaraujosantos

@leonardoaraujosantos leonardoaraujosantos commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

A person can send their CyberWealth connected-app key in a DM (or /connect, DM-only) and ask about their own budget, bills and accounts. The key is sealed at rest (AES-GCM under PERSONAL_SECRETS_KEY, person id + kind as associated data), only its last four characters are ever shown, and it never reaches a model, trace, memory or the archive. Personal (my_*) CyberWealth tools carry it as the bearer on a per-call connection, only in the key owner's own DM.

Migration 0037 (person_secret + opt-out insert trigger), re-chained to revise 0036: it restates 0036's purge_person_derived body (account and user-session tables) plus person_secret, and its downgrade restores 0036's body. New integration tests pin the purge's table set at head and after downgrading to 0036.

Needs PERSONAL_SECRETS_KEY on the bot and the my_* tools in FEDERATION_TOOL_ALLOWLIST; unset, a key is refused and nothing is saved.

Tests: unit + integration + e2e green locally; alembic upgrade / downgrade -1 / upgrade clean; mypy, ruff, openspec strict clean.

…heir my_* calls

A key (cwk_live|test|dev_...) sent in a DM, as text or with the new DM-only
/connect, is stored in person_secret (migration 0037) as AES-GCM ciphertext
under PERSONAL_SECRETS_KEY, bound to the person id and kind as associated
data, with only its last four characters in the clear. Replies and /privacy
name it by those four characters; a message carrying cwk_ is handled before
the answer path, so it never reaches a model, a trace or memory.

A my_* call on the cyberwealth server, already held to the asker's DM, now
carries the asker's own key over a connection opened for that call alone;
intel_* and the shared connection keep the service token. No key: nothing is
sent (NO_PERSONAL_KEY, audited as refused). A 401 to the key is KEY_REJECTED
and does not mark the server lost. Allowlisted my_* tools the service
principal cannot list are registered from their name when keys are on.
Keys are only turned on for an https target.

/forget (everywhere or in the DM), Delete everything and opt-out delete the
key: purge_person_derived gains person_secret, and an insert trigger drops a
key from an opted-out person. /privacy lists keys and the erasure reply
counts them.

A channel message containing cwk_ is never archived (live, edit, backfill)
or answered, and its author is warned by DM to revoke it. /ask, /suggest and
/schedule create never ask or store text carrying a key.

OpenSpec change add-cyberwealth-personal-keys; README, operations and
roadmap updated; PERSONAL_SECRETS_KEY declared on the bot service.
…th key

The ingest process already retracted such an edit from the archive, but the
bot only checked keys in on_message, so the key stayed readable in the channel
and nobody was told to revoke it. on_raw_message_edit now sends the same DM,
skipping messages whose cached copy already carried a key.

Cover the key guards on /suggest and /schedule create, and bind of the kind
into the AES-GCM associated data, with tests; note in 0037 how to re-chain it
behind another purge_person_derived rewrite.
…r-keys

# Conflicts:
#	README.md
#	src/chatmemory/adapters/discord/bot.py
#	tests/unit/test_sql_audit.py
0037 now revises 0036 and restates its purge_person_derived body (account
and user-session tables) plus person_secret, so the later CREATE OR REPLACE
no longer drops the account tables; its downgrade restores 0036's body.
Integration tests pin the purge's table set at head and after downgrading
to 0036.
@leonardoaraujosantos
leonardoaraujosantos merged commit 9bd1a56 into main Sep 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant