auth: put mail ingestion on the same rung as resolving a task
IngestMail was AuthRead and SetTaskStatus was AuthWrite, and they answer the same question: may this module change what is on his lists? The old argument for AuthRead — ingestion is additive, it can only produce candidate tasks — is still true and is the weaker half, because a compromised mail reader that can fill the review page indefinitely is not a read. Nothing loses access. AuthWrite outside WriteFact only requires enrollment, which mavmaild already has, and the method does not exist unless the operator wired a mail block. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TrVSBKe3RFDF4fGYKWYQnX
This commit is contained in:
@@ -417,6 +417,28 @@ func TestRequirement_SwapModel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestRequirement_ListMutation — the three methods that change what is on his
|
||||
// lists sit on one rung. IngestMail joined them on 2026-08-01; it used to be
|
||||
// AuthRead, which made it disagree with SetTaskStatus about the same question.
|
||||
// CaptureTask stays a read: it puts one line on a list he asked for.
|
||||
func TestRequirement_ListMutation(t *testing.T) {
|
||||
for _, m := range []ipc.Method{
|
||||
ipc.MethodIngestMail, ipc.MethodSetTaskStatus,
|
||||
} {
|
||||
if got := Requirement(m); got != AuthWrite {
|
||||
t.Errorf("%s authority = %v; want AuthWrite", m, got)
|
||||
}
|
||||
}
|
||||
if got := Requirement(ipc.MethodCaptureTask); got != AuthRead {
|
||||
t.Errorf("CaptureTask authority = %v; want AuthRead", got)
|
||||
}
|
||||
// mavmaild keeps working: AuthWrite outside WriteFact only needs enrollment.
|
||||
maild := Scope{Surface: SurfaceCoreProcess, Module: "mavmaild", SourceScope: []string{"mail:*"}}
|
||||
if err := Can(ipc.MethodIngestMail, maild, nil); err != nil {
|
||||
t.Errorf("mavmaild ingesting mail = %v; want allowed", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRequirement_Capture — recording other people is a write, not a read: it
|
||||
// puts audio of them on disk. The read side, "что ты записываешь?", is not.
|
||||
//
|
||||
|
||||
+14
-5
@@ -93,6 +93,20 @@ func Requirement(m ipc.Method) Authority {
|
||||
return AuthWrite
|
||||
case ipc.MethodWriteFact:
|
||||
return AuthWrite
|
||||
case ipc.MethodIngestMail:
|
||||
// Mail ingestion (Vikunja #246). Moved up from AuthRead on 2026-08-01,
|
||||
// for consistency with SetTaskStatus rather than for a new threat: both
|
||||
// answer the same question — may this module change what is on his
|
||||
// lists? — and they were answering it differently. The old argument was
|
||||
// that ingestion is additive and can only produce candidate tasks, which
|
||||
// is still true; it is the weaker half of the argument, because a
|
||||
// compromised mail reader that can fill the review page indefinitely is
|
||||
// not a read.
|
||||
//
|
||||
// No caller loses anything: AuthWrite outside WriteFact only requires
|
||||
// enrollment, which mavmaild already has, and the method does not exist
|
||||
// unless the operator wired a mail block.
|
||||
return AuthWrite
|
||||
case ipc.MethodSetTaskStatus:
|
||||
// Resolving a task is NOT additive, which is what separates it from
|
||||
// capture. Capture at AuthRead can only put a line on a list he reads
|
||||
@@ -122,11 +136,6 @@ func Requirement(m ipc.Method) Authority {
|
||||
// something.
|
||||
ipc.MethodCaptureTask,
|
||||
ipc.MethodListTasks,
|
||||
// Mail ingestion (Vikunja #246). AuthRead because of what the method can
|
||||
// produce: candidate tasks and nothing else. It cannot write a fact, set a
|
||||
// reminder, or touch the tool allowlist, so a compromised mail reader can
|
||||
// at worst put junk on a review page he clears in one click.
|
||||
ipc.MethodIngestMail,
|
||||
// Looking at one image (Vikunja #252). AuthRead because of what it can
|
||||
// produce: words about a picture, and optionally a note. It cannot write
|
||||
// a fact, set a reminder, or touch the tool allowlist. The invasive part
|
||||
|
||||
Reference in New Issue
Block a user