{ "description": "Scripted flows (CONTRACT.md section 8). The format, steps, expectations and captures are defined in conformance/FLOWS.md. Everything a run needs is in this file, scenarios.json and statute.json.", "statute": "statute.json", "peers": { "callback-1": "6d61732d6d6f6465732d76302e312d746573742d6b65792d63616c6c6261636b31", "cms-1": "6d61732d6d6f6465732d76302e312d746573742d6b65792d636d732d312d2d2d2d", "gateway": "6d61732d6d6f6465732d76302e312d746573742d6b65792d676174657761792d2d" }, "setups": { "master": { "roles": { "ticket": { "role": "master", "modes": { "callback": { "peer": "callback-1" } }, "fields": [ "phone", "time", "scenario" ], "timeout": 3600 } } }, "slave": { "roles": { "case": { "role": "slave", "master_peer": "cms-1", "autonomous_send": false, "transfers": "block" } } }, "slave-webhook": { "roles": { "case": { "role": "slave", "master_peer": "cms-1", "autonomous_send": false, "transfers": { "webhook": "", "peer": "callback-1" } } } } }, "flows": [ { "id": "m-001", "setup": "master", "title": "callback completes", "scenario": "completed", "steps": [ { "mail": { "to": "ticket!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" }, "expect": { "event_accepted": true, "mode_received": 1 } }, { "mode": "run", "expect": { "mode_statuses": [ "scheduled", "running", "completed" ], "last_mail_contains": "has taken place" } } ] }, { "id": "m-002", "setup": "master", "title": "negotiation over email", "scenario": "negotiate", "steps": [ { "mail": { "to": "ticket!callback", "text": "Please call me." }, "expect": { "event_accepted": true } }, { "mode": "run", "expect": { "mode_statuses": [ "negotiating" ], "last_mail_contains": "Phone: ..." } }, { "mail": { "to": "ticket={case_id}", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" }, "expect": { "event_accepted": true, "mode_received_last": "handoff.update" } }, { "mode": "run", "expect": { "mode_statuses": [ "negotiating", "scheduled", "running", "completed" ], "last_mail_contains": "has taken place" } } ] }, { "id": "m-003", "setup": "master", "title": "no answer, retried, completed", "scenario": "no-answer-retry", "steps": [ { "mail": { "to": "ticket!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" } }, { "mode": "run", "expect": { "mode_statuses": [ "scheduled", "attempted", "scheduled", "running", "completed" ] } } ] }, { "id": "m-004", "setup": "master", "title": "no answer twice, failed", "scenario": "no-answer-fail", "steps": [ { "mail": { "to": "ticket!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" } }, { "mode": "run", "expect": { "mode_statuses": [ "scheduled", "attempted", "scheduled", "attempted", "failed" ], "last_mail_contains": "did not succeed" } } ] }, { "id": "m-005", "setup": "master", "title": "refused out of hours", "scenario": "out-of-hours", "steps": [ { "mail": { "to": "ticket!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" } }, { "mode": "run", "expect": { "mode_statuses": [ "refused" ], "last_mail_contains": "out-of-hours" } } ] }, { "id": "m-006", "setup": "master", "title": "email owns the timeout", "scenario": "silent", "steps": [ { "mail": { "to": "ticket!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" }, "expect": { "mails_sent": 1 } }, { "mode": "run", "expect": { "mode_statuses": [] } }, { "advance": 3599, "expect": { "mode_received": 1, "mails_sent": 1 } }, { "advance": 2, "expect": { "mode_received_last": "handoff.cancel", "mails_sent": 2, "last_mail_contains": "could not arrange" } }, { "advance": 100000, "expect": { "mode_received": 2, "mails_sent": 2 } } ] }, { "id": "m-007", "setup": "master", "title": "mode not enabled by the statute", "scenario": "completed", "steps": [ { "mail": { "to": "ticket!chat", "text": "hi" }, "expect": { "event_accepted": true, "mode_received": 0, "mails_sent": 1 } } ] }, { "id": "m-008", "setup": "master", "title": "unauthenticated sender gets no mail", "scenario": "negotiate", "steps": [ { "mail": { "to": "ticket!callback", "text": "call me", "dmarc": "fail" }, "expect": { "event_accepted": true } }, { "mode": "run", "expect": { "mode_statuses": [ "negotiating" ], "mails_sent": 0 } } ] }, { "id": "s-001", "setup": "slave", "title": "master issues the id; email sends only on instruction", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "My order is late" }, "expect": { "event_accepted": true, "master_received": { "case.intake": 1 }, "mails_sent": 0 } }, { "master": { "command": "assign", "resource_id": "EXT-100" }, "expect": { "response_ok": true, "case_address": "case=EXT-100@modes.example" } }, { "mail": { "to": "case={case_id}", "text": "more" }, "expect": { "master_received": { "case.message": 1 }, "mails_sent": 0 } }, { "master": { "command": "send", "in_reply_to": "{message_ref}", "body": "We are on it." }, "expect": { "response_ok": true, "mails_sent": 1 } } ] }, { "id": "s-002", "setup": "slave", "title": "principle 10 refuses a master send", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "hi", "dmarc": "fail" } }, { "master": { "command": "assign", "resource_id": "EXT-100" } }, { "master": { "command": "send", "in_reply_to": "{message_ref}", "body": "x" }, "expect": { "response_ok": false, "response_reason": "unauthenticated-sender", "mails_sent": 0 } } ] }, { "id": "s-003", "setup": "slave", "title": "transfer blocked", "scenario": "completed", "steps": [ { "mail": { "to": "case!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" }, "expect": { "master_received": { "case.intake": 1 } } }, { "master": { "command": "assign", "resource_id": "EXT-100" }, "expect": { "master_received": { "handoff.requested": 1, "handoff.status": 1 }, "relayed": [ "refused" ], "mode_received": 0 } } ] }, { "id": "s-004", "setup": "slave-webhook", "title": "transfer to the primed webhook; statuses relayed", "scenario": "completed", "steps": [ { "mail": { "to": "case!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" } }, { "master": { "command": "assign", "resource_id": "EXT-100" }, "expect": { "mode_received": 1 } }, { "mode": "run", "expect": { "relayed": [ "scheduled", "running", "completed" ], "mails_sent": 0 } }, { "advance": 1000000, "expect": { "mode_received": 1 } } ] }, { "id": "s-005", "setup": "slave-webhook", "title": "the master owns the timeout", "scenario": "silent", "steps": [ { "mail": { "to": "case!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" } }, { "master": { "command": "assign", "resource_id": "EXT-100" } }, { "mode": "run", "expect": { "relayed": [] } }, { "advance": 1000000, "expect": { "mode_received": 1 } }, { "master": { "command": "cancel", "handoff_id": "{handoff_id}" }, "expect": { "response_ok": true, "mode_received_last": "handoff.cancel" } }, { "mode": "run", "expect": { "relayed": [ "cancelled" ] } } ] }, { "id": "s-006", "setup": "slave", "title": "over the cap a master send is held", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "hi" } }, { "master": { "command": "assign", "resource_id": "EXT-100" } }, { "master": { "command": "send", "in_reply_to": "{message_ref}", "body": "one" }, "expect": { "response_ok": true, "mails_sent": 1 } }, { "master": { "command": "send", "in_reply_to": "{message_ref}", "body": "two" }, "expect": { "response_ok": false, "response_reason": "send-cap-reached", "response_held": true, "mails_sent": 1 } } ], "max_sent": 1 }, { "id": "a-001", "setup": "slave", "title": "unsigned master command refused", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "hi" } }, { "master": { "command": "assign", "resource_id": "EXT-100" } }, { "inject": { "endpoint": "master", "sign": "none", "message": { "type": "mail.send", "case": "current", "in_reply_to": "{message_ref}", "body": "hello" } }, "expect": { "http_status": 401, "error": "unauthenticated-peer", "mails_sent": 0 } } ] }, { "id": "a-002", "setup": "slave", "title": "a mode cannot assign case ids", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "hi" } }, { "inject": { "endpoint": "master", "as": "callback-1", "message": { "type": "case.assign", "intake_ref": "{intake_ref}", "resource_id": "EVIL-1" } }, "expect": { "http_status": 403, "error": "wrong-peer" } }, { "master": { "command": "assign", "resource_id": "EXT-100" }, "expect": { "case_address": "case=EXT-100@modes.example" } } ] }, { "id": "a-003", "setup": "slave", "title": "webhook to a peer email has no key for", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "hi" } }, { "master": { "command": "assign", "resource_id": "EXT-100" } }, { "inject": { "endpoint": "master", "as": "cms-1", "message": { "type": "case.policy", "case": "current", "transfers": { "webhook": "http://attacker.example/h", "peer": "mallory" } } }, "expect": { "http_status": 400, "error": "unknown-peer" } } ] }, { "id": "a-004", "setup": "slave", "title": "replayed master command", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "hi" } }, { "master": { "command": "assign", "resource_id": "EXT-100" } }, { "inject": { "endpoint": "master", "as": "cms-1", "sign": "stale", "message": { "type": "mail.send", "case": "current", "in_reply_to": "{message_ref}", "body": "hello" } }, "expect": { "http_status": 401, "error": "replayed", "mails_sent": 0 } } ] }, { "id": "a-005", "setup": "slave", "title": "master command signed with the wrong key", "scenario": "completed", "steps": [ { "mail": { "to": "case", "text": "hi" } }, { "master": { "command": "assign", "resource_id": "EXT-100" } }, { "inject": { "endpoint": "master", "as": "cms-1", "sign": "wrong-key", "message": { "type": "mail.send", "case": "current", "in_reply_to": "{message_ref}", "body": "hello" } }, "expect": { "http_status": 401, "error": "unauthenticated-peer", "mails_sent": 0 } }, { "inject": { "endpoint": "master", "as": "cms-1", "message": { "type": "mail.send", "case": "current", "in_reply_to": "{message_ref}", "body": "hello" } }, "expect": { "http_status": 200, "mails_sent": 1 } } ] }, { "id": "a-006", "setup": "master", "title": "statuses only from the handoff's peer, at its URL", "scenario": "silent", "steps": [ { "mail": { "to": "ticket!callback", "text": "Phone: +49 30 1234567\nTime: tomorrow 10:00" }, "expect": { "mails_sent": 1 } }, { "inject": { "endpoint": "status", "as": "cms-1", "message": { "type": "handoff.status", "case": "current", "handoff_id": "{handoff_id}", "seq": 1, "status": "completed" } }, "expect": { "http_status": 403, "error": "wrong-peer" } }, { "inject": { "endpoint": "status", "as": "callback-1", "token": "bogus", "message": { "type": "handoff.status", "case": "current", "handoff_id": "{handoff_id}", "seq": 1, "status": "completed" } }, "expect": { "http_status": 404, "error": "unknown-handoff", "mails_sent": 1 } }, { "inject": { "endpoint": "status", "as": "callback-1", "message": { "type": "handoff.status", "case": "current", "handoff_id": "{handoff_id}", "seq": 1, "status": "scheduled", "at": "x" } }, "expect": { "http_status": 200 } } ] }, { "id": "a-007", "setup": "master", "title": "only the gateway posts events", "scenario": "completed", "steps": [ { "inject": { "endpoint": "events", "as": "callback-1", "message": { "type": "x" } }, "expect": { "http_status": 403, "error": "wrong-peer" } } ] } ] }