mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 18:01:09 +02:00
feat(crypto): Phase 2a — declare encryption intent for tags/scenes/missions
Preparation step for the space-scoped data model migration (Phase 2b).
Moves globalTags, tagGroups, workbenchScenes, and aiMissions from the
plaintext allowlist into the encryption registry with enabled:false —
so the audit script documents which fields WILL be encrypted without
changing any runtime behaviour.
Fields chosen per design-doc:
- globalTags.name — personal categorization (Therapie, Finanzen-privat)
- tagGroups.name — same
- workbenchScenes.name + description — scene labels often encode
Space-specific context (Q2-Launch, Urlaub 2026)
- aiMissions.title + conceptMarkdown + objective — all user-typed
mission config; state/cadence/inputs stay plaintext for the Runner
Deliberately kept plaintext (against my initial suggestion):
- aiAgents.name — registry comment explains: name is the Actor
displayName cache key for historic attribution. Encrypting would
show "🤖 [encrypted]" on every past task the agent ever touched.
- globalTags.icon / tagGroups.icon / color — not personal content;
icon is a visual cue, color is theme metadata
The 2c migration (Dexie v35, flip enabled:true) runs after 2b lands
the schema changes so existing rows get encrypted in one controlled
pass instead of mixing schema + encryption in the same upgrade.
Crypto audit: 195 Dexie tables classified (94 encrypted, 101
plaintext-allowlisted). Type-check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3e09ff66d1
commit
766ad2ea8f
2 changed files with 36 additions and 4 deletions
|
|
@ -19,7 +19,6 @@
|
||||||
export const PLAINTEXT_ALLOWLIST: readonly string[] = [
|
export const PLAINTEXT_ALLOWLIST: readonly string[] = [
|
||||||
'achievements', // TODO: audit
|
'achievements', // TODO: audit
|
||||||
'activities', // TODO: audit
|
'activities', // TODO: audit
|
||||||
'aiMissions', // TODO: audit
|
|
||||||
'albumItems', // TODO: audit
|
'albumItems', // TODO: audit
|
||||||
'albums', // TODO: audit
|
'albums', // TODO: audit
|
||||||
'articleTags', // FK-only junction into globalTags (articleId, tagId). Tag names live in globalTags.
|
'articleTags', // FK-only junction into globalTags (articleId, tagId). Tag names live in globalTags.
|
||||||
|
|
@ -50,7 +49,6 @@ export const PLAINTEXT_ALLOWLIST: readonly string[] = [
|
||||||
'fileTags', // TODO: audit
|
'fileTags', // TODO: audit
|
||||||
'financeCategories', // TODO: audit
|
'financeCategories', // TODO: audit
|
||||||
'foodFavorites', // TODO: audit
|
'foodFavorites', // TODO: audit
|
||||||
'globalTags', // TODO: audit
|
|
||||||
'goals', // TODO: audit
|
'goals', // TODO: audit
|
||||||
'guideCollections', // TODO: audit
|
'guideCollections', // TODO: audit
|
||||||
'guideTags', // TODO: audit
|
'guideTags', // TODO: audit
|
||||||
|
|
@ -99,7 +97,6 @@ export const PLAINTEXT_ALLOWLIST: readonly string[] = [
|
||||||
'songTags', // TODO: audit
|
'songTags', // TODO: audit
|
||||||
'spaceMembers', // TODO: audit
|
'spaceMembers', // TODO: audit
|
||||||
'storageFolders', // TODO: audit
|
'storageFolders', // TODO: audit
|
||||||
'tagGroups', // TODO: audit
|
|
||||||
'taskLabels', // TODO: audit
|
'taskLabels', // TODO: audit
|
||||||
'timeAlarms', // TODO: audit
|
'timeAlarms', // TODO: audit
|
||||||
'timeBlockTags', // TODO: audit
|
'timeBlockTags', // TODO: audit
|
||||||
|
|
@ -121,5 +118,4 @@ export const PLAINTEXT_ALLOWLIST: readonly string[] = [
|
||||||
'wishesItems', // TODO: audit
|
'wishesItems', // TODO: audit
|
||||||
'wishesLists', // TODO: audit
|
'wishesLists', // TODO: audit
|
||||||
'wishesPriceChecks', // TODO: audit
|
'wishesPriceChecks', // TODO: audit
|
||||||
'workbenchScenes', // TODO: audit
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -573,6 +573,42 @@ export const ENCRYPTION_REGISTRY: Record<string, EncryptionConfig> = {
|
||||||
// structural fields.
|
// structural fields.
|
||||||
agents: { enabled: true, fields: ['systemPrompt', 'memory'] },
|
agents: { enabled: true, fields: ['systemPrompt', 'memory'] },
|
||||||
|
|
||||||
|
// ─── AI Missions ─────────────────────────────────────────
|
||||||
|
// docs/plans/space-scoped-data-model.md §2a — declared with
|
||||||
|
// enabled:false during prep so the audit script is happy; flips to
|
||||||
|
// true in 2c alongside the Dexie v35 encryption migration.
|
||||||
|
//
|
||||||
|
// User-typed content on missions: `title` (display label the user
|
||||||
|
// types at create time), `conceptMarkdown` (free-form context the
|
||||||
|
// planner reads), `objective` (the actionable goal string). State,
|
||||||
|
// cadence, inputs (FK-only), nextRunAt, iterations, agentId all
|
||||||
|
// stay plaintext — needed for the Runner's "due now" index walk
|
||||||
|
// and mission-detail filters.
|
||||||
|
aiMissions: { enabled: false, fields: ['title', 'conceptMarkdown', 'objective'] },
|
||||||
|
|
||||||
|
// ─── Tags (shared-stores) ────────────────────────────────
|
||||||
|
// docs/plans/space-scoped-data-model.md §2a — declared with
|
||||||
|
// enabled:false during prep; flips to true in 2c. Tag names like
|
||||||
|
// "Therapie" or "Finanzen-privat" can leak personal categorization,
|
||||||
|
// so they belong under encryption. `color` + `icon` + `groupId` +
|
||||||
|
// `sortOrder` stay plaintext: they're visual metadata + the group
|
||||||
|
// FK, none of which leak sensitive taxonomy. `name` is NOT indexed
|
||||||
|
// for .where() lookups today, so encrypting it is safe — dedupe-
|
||||||
|
// within-space lookups go through the new [spaceId+name] index after
|
||||||
|
// Phase 2b and run over already-decrypted rows in the scoped store.
|
||||||
|
globalTags: { enabled: false, fields: ['name'] },
|
||||||
|
tagGroups: { enabled: false, fields: ['name'] },
|
||||||
|
|
||||||
|
// ─── Workbench Scenes ────────────────────────────────────
|
||||||
|
// docs/plans/space-scoped-data-model.md §2a — declared with
|
||||||
|
// enabled:false during prep; flips to true in 2c. `name` is the
|
||||||
|
// user-visible scene label ("Heute", "Q2-Launch") and `description`
|
||||||
|
// is the short subtitle — both are user-typed free text that can
|
||||||
|
// leak Space-specific context. openApps / order / wallpaper /
|
||||||
|
// viewingAsAgentId / scopeTagIds stay plaintext (structural /
|
||||||
|
// indexed / foreign-key data).
|
||||||
|
workbenchScenes: { enabled: false, fields: ['name', 'description'] },
|
||||||
|
|
||||||
// ─── Articles (Pocket-style read-it-later) ──────────────
|
// ─── Articles (Pocket-style read-it-later) ──────────────
|
||||||
// Reading-behaviour data — same sensitivity class as newsArticles.
|
// Reading-behaviour data — same sensitivity class as newsArticles.
|
||||||
// Encrypted:
|
// Encrypted:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue