Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

- GitHub: `https://github.com/Jdelg718/BotFucker`
- Default branch: `main`
- Latest merged milestone: Phase 14 Durable Bridge Ledger Scaffold (`feat: add durable bridge ledger scaffold`, main at 8904d67)
- Current working branch: `phase-15-emergency-stop-bridge-rehearsal`
- Current PR target: Phase 15 Emergency-Stop Bridge Rehearsalcode/docs/tests only, dry-run-only, no OAuth/live provider mutation
- Latest merged milestone: Phase 15 Emergency-Stop Bridge Rehearsal (`feat: add emergency-stop bridge rehearsal`, main at 3b1075e)
- Current working branch: `phase-16-outlook-warning-draft-sandbox-contract`
- Current PR target: Phase 16 Microsoft Outlook Warning-Draft Sandbox Contract — docs/tests only, no OAuth/live provider mutation/no send
- Selected next provider/action target: Microsoft Outlook warning draft in sandbox/manual reviewed bridge contract; no send-reply mutation yet
- Current local demo target: demonstrate deterministic local review, optional mocked LLM classifier fallback/validation, approved-action export, dry-run n8n bridge contract, fail-closed YOLO policy checks, real n8n import validation results, the Phase 13 Reviewed Action Bridge Promotion Plan, durable bridge ledger dedupe scaffold, and emergency-stop bridge rehearsal
- Current promo artifact: `promo/botfucker-animated-explainer/renders/botfucker-animated-explainer_narrated-final.mp4`
Expand Down Expand Up @@ -38,6 +38,7 @@ docs/provider-auth-plan.md # provider auth/action boundary plan
docs/reviewed-action-bridge-promotion-plan.md # Phase 13 reviewed live-bridge gate; no OAuth/live mutation
docs/bridge-ledger-scaffold.md # Phase 14 durable processed-audit ledger scaffold; no OAuth/live mutation
docs/bridge-rehearsal.md # Phase 15 emergency-stop/dry-run bridge rehearsal; no provider execution
docs/microsoft-outlook-warning-draft-sandbox.md # Phase 16 Outlook warning-draft sandbox contract; no send
README.md # user-facing setup and project overview
outreach_filter.py # compatibility CLI wrapper
botfucker/models.py # normalized email/classification/review models
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ See [DESIGN.md](DESIGN.md) for the proposed architecture and roadmap.
- Provides an inactive n8n approved-action bridge starter that validates/dedupes actions in dry-run mode.
- Provides a Phase 14 durable bridge ledger scaffold for recording processed `audit_id` state before provider mutation.
- Provides a Phase 15 dry-run bridge rehearsal that proves emergency stop and duplicate-skip behavior before provider mutation.
- Documents the selected Phase 16 sandbox target: Microsoft Outlook warning-draft creation only, with no send-reply mutation.
- Keeps provider credentials and live mailbox side effects outside the local UI and review queue.

## Safety First
Expand Down
38 changes: 31 additions & 7 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,33 @@ python3 -m botfucker.review_cli --db botfucker_review.sqlite3 import-webhook-jso

Use fake or sanitized JSON only. Real mailbox payloads stay out of the repo.

### Phase 16 — Microsoft Outlook Warning-Draft Sandbox Contract ✅

Status: implemented on `phase-16-outlook-warning-draft-sandbox-contract`.

Goal: document Kent's selected first provider/action target without adding OAuth, credentials, or live mutation behavior.

Delivered:

- `docs/microsoft-outlook-warning-draft-sandbox.md`
- Microsoft Graph `createReply` reference for draft creation
- explicit Outlook warning-draft-only target
- explicit `/send` and reply-send prohibition
- n8n/operator credential boundary
- acceptance criteria for a future implementation PR
- tests proving the contract exists and current n8n workflows still contain no Outlook send or credential material

Acceptance criteria:

- Provider target is Microsoft Outlook.
- First action is warning draft creation/save only.
- No send-reply mutation is allowed.
- Credentials stay outside BotFucker and inside n8n/operator infrastructure.
- Current workflow exports remain provider-call-free and credential-free.

## Near-Term Recommendation

After Phase 15 is reviewed and merged, the next PR should be **Phase 16: Microsoft Outlook warning-draft sandbox contract**, not broad OAuth implementation.
After Phase 16 is reviewed and merged, the next PR should be **Phase 17: inactive Microsoft Outlook warning-draft workflow scaffold**, not broad OAuth implementation.

Kent selected the first provider/action target:

Expand All @@ -427,14 +451,14 @@ Recommended scope:
- map the Phase 15 rehearsal outcomes onto an inactive n8n/operator checklist
- require Rex/Gus security/ops review before any live mutation node is connected

OAuth can still wait. Phase 15 proves the brakes in code. Next is picking the sandbox road — not handing the robot live mailbox keys because apparently we enjoy learning by fire.
OAuth can still wait. Phase 16 picks the sandbox road. Next is building the inactive/manual Outlook draft scaffold — not handing the robot live mailbox keys because apparently we enjoy learning by fire.

### Restart checklist after Phase 15
### Restart checklist after Phase 16

1. Re-check Phase 15 PR CI and mergeability.
2. Squash-merge Phase 15 into `main` if still green.
3. Use Microsoft Outlook as the selected sandbox provider target.
4. Limit the first provider/action pair to warning draft creation/save only; do not send replies.
1. Re-check Phase 16 PR CI and mergeability.
2. Squash-merge Phase 16 into `main` if still green.
3. Build only an inactive/manual Microsoft Outlook warning-draft workflow scaffold.
4. Keep the provider action to create/save draft only; do not send replies.
5. Keep provider credentials inside n8n/operator infrastructure only; do not put secrets in BotFucker.

## Team Utilization
Expand Down
145 changes: 145 additions & 0 deletions docs/microsoft-outlook-warning-draft-sandbox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Phase 16 — Microsoft Outlook Warning-Draft Sandbox Contract

Kent selected the first provider/action target:

- Provider: Microsoft Outlook / Microsoft Graph
- Action: create/save a warning draft only
- Environment: sandbox/manual reviewed bridge first
- Explicit non-goal: sending replies

This phase is a contract and safety checklist for the future n8n/provider bridge. It does not add OAuth code, credentials, tokens, live n8n activation, or provider mutation logic to BotFucker core.

## Microsoft Graph primitive

Microsoft Graph supports creating a reply draft with:

```http
POST /me/messages/{id}/createReply
```

or the user-scoped form:

```http
POST /users/{id | userPrincipalName}/messages/{id}/createReply
```

Microsoft documents the least-privileged permission for this operation as `Mail.ReadWrite`.

Important behavior:

- `createReply` creates a draft reply.
- It does not send the draft.
- Sending is a separate operation and remains out of scope.
- The bridge must never call `/send` in this phase.

Reference:

- https://learn.microsoft.com/en-us/graph/api/message-createreply?view=graph-rest-1.0

## Required safety gates

Before any sandbox call is allowed, the bridge must prove all of these gates:

1. Human-approved local audit event exists.
2. Approved-action export schema is `botfucker.approved_actions.v1`.
3. `provider_execution` is `not_performed`.
4. Approved action is exactly `approve_warning`.
5. Provider is exactly `outlook` or `microsoft_outlook`, normalized to a single bridge value.
6. Durable bridge ledger claim succeeds for the `audit_id`.
7. Emergency stop is false.
8. Dry-run rehearsal has passed for the same action shape.
9. Sandbox mailbox/provider target is explicitly configured in n8n/operator infrastructure.
10. Credentials remain in n8n/operator infrastructure only.

If any gate fails, the bridge exits before provider mutation.

## Credential boundary

Credentials are not BotFucker state.

Allowed:

- n8n-owned Microsoft credential
- operator-owned Microsoft sandbox account
- environment/credential store controlled outside this repo

Forbidden in this repo:

- OAuth client secret
- refresh token
- access token
- password
- cookie
- exported n8n credentials
- real mailbox payloads
- private message bodies

## Allowed provider effect for first sandbox test

The only permitted provider effect is:

```text
create Outlook reply draft warning for the reviewed message
```

The provider result must be recorded back to the bridge ledger as metadata only, such as:

- provider: `microsoft_outlook`
- approved_action: `approve_warning`
- provider_result_id: draft message ID or opaque test ID
- status: `processed` only after Graph returns a successful draft creation

The ledger must still avoid storing raw message bodies, headers, secrets, or tokens.

## Explicitly forbidden provider effects

Do not:

- send the draft
- call Microsoft Graph `/send`
- reply in a single operation
- delete email
- move email
- archive email
- mark read/unread
- create rules
- update contacts
- write mailbox settings
- attach credentials to exported workflow JSON

No “just testing” send. That is how a sandbox turns into a customer-service fire drill wearing a fake mustache.

## n8n sandbox shape

A future n8n workflow may contain these conceptual steps:

1. Manual trigger only.
2. Read approved-action export from controlled test input.
3. Validate schema/safety fields.
4. Check emergency-stop flag.
5. Claim `audit_id` in durable bridge ledger.
6. Use Microsoft Outlook/Graph credential from n8n only.
7. Create reply draft with Microsoft Graph `createReply`.
8. Update draft body with the human-approved warning text if the create step produces an empty draft.
9. Record provider draft ID in bridge ledger.
10. Stop. Do not send.

The workflow must remain inactive/manual until Rex and Gus review the exact artifact.

## Acceptance criteria for implementation PR

A future implementation PR must include:

- an inactive/manual n8n workflow or operator guide only
- sample fake Outlook action bundle using reserved/fake IDs
- tests/static validator proving no `/send` call exists
- tests/static validator proving no credentials are exported
- emergency-stop test evidence
- duplicate `audit_id` test evidence
- rollback/remediation note for deleting the sandbox draft manually
- Rex security review
- Gus ops/n8n review

## Current status

Phase 16 selected target is documented, but no live provider mutation has been implemented yet.
85 changes: 85 additions & 0 deletions tests/test_microsoft_outlook_warning_draft_sandbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import json
import unittest
from pathlib import Path

DOC_PATH = Path("docs/microsoft-outlook-warning-draft-sandbox.md")
WORKFLOW_PATHS = [
Path("docs/n8n-workflow.json"),
Path("docs/n8n-approved-action-bridge.json"),
]


class MicrosoftOutlookWarningDraftSandboxContractTests(unittest.TestCase):
def test_contract_exists_and_targets_outlook_warning_draft_only(self):
text = DOC_PATH.read_text(encoding="utf-8")

self.assertIn("Microsoft Outlook", text)
self.assertIn("warning draft", text.lower())
self.assertIn("approve_warning", text)
self.assertIn("POST /me/messages/{id}/createReply", text)
self.assertIn("Mail.ReadWrite", text)
self.assertIn("Explicit non-goal: sending replies", text)

def test_contract_forbids_send_and_other_provider_mutations(self):
text = DOC_PATH.read_text(encoding="utf-8")

required_phrases = [
"The bridge must never call `/send` in this phase.",
"Do not:",
"send the draft",
"call Microsoft Graph `/send`",
"delete email",
"move email",
"archive email",
"mark read/unread",
"No “just testing” send.",
]
for phrase in required_phrases:
with self.subTest(phrase=phrase):
self.assertIn(phrase, text)

def test_contract_keeps_credentials_out_of_repo(self):
text = DOC_PATH.read_text(encoding="utf-8")

for forbidden_secret in [
"OAuth client secret",
"refresh token",
"access token",
"password",
"cookie",
"exported n8n credentials",
]:
with self.subTest(forbidden_secret=forbidden_secret):
self.assertIn(forbidden_secret, text)
self.assertIn("Credentials are not BotFucker state.", text)
self.assertIn("Credentials remain in n8n/operator infrastructure only.", text)

def test_existing_n8n_workflows_still_do_not_contain_outlook_send_or_credentials(self):
forbidden_terms = [
"/send",
"sendMail",
"microsoftGraph",
"client_secret",
"refresh_token",
"access_token",
"password",
]
for path in WORKFLOW_PATHS:
raw = path.read_text(encoding="utf-8")
json.loads(raw)
lowered = raw.lower()
for term in forbidden_terms:
with self.subTest(path=str(path), term=term):
self.assertNotIn(term.lower(), lowered)

def test_roadmap_records_kents_selected_phase_16_target(self):
text = Path("ROADMAP.md").read_text(encoding="utf-8")

self.assertIn("Phase 16 — Microsoft Outlook Warning-Draft Sandbox Contract", text)
self.assertIn("Provider: Microsoft Outlook", text)
self.assertIn("First action: create/save a warning draft only", text)
self.assertIn("no send-reply mutation yet", text)


if __name__ == "__main__":
unittest.main()
Loading