Add desktop app, resilient webhooks, and realistic demo mode#67
Conversation
Greptile SummaryThis PR adds an experimental Electron desktop wrapper around the existing Node/Convex stack, hardens the webhook surface with signed Sendblue verification and a strict local-only gate for all private HTTP and WebSocket routes, and expands demo mode with realistic fixtures and scripted in-app replies.
Confidence Score: 5/5Safe to merge — the new webhook authentication, local-only gate, and desktop process management are all well-tested and the key security paths (timingSafeEqual, scoped postMessage origin, contextIsolation) are correctly implemented. The three core new subsystems (desktop lifecycle, webhook signing, local-access gate) are each covered by targeted unit tests. The process identity guard in exit handlers correctly prevents the restart-race scenario. Both publicly-exposed webhook endpoints have independent HMAC verification before any business logic runs. No issues were found that affect correctness or security on the changed paths. No files require special attention beyond the previously-flagged electron/main.cjs concerns already reviewed inline. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant SB as Sendblue
participant TU as ngrok Tunnel
participant SV as Express Server
participant LA as local-access.ts
participant WA as sendblue-webhook-auth.ts
participant DR as scripted-demo-replies.ts
participant AI as interaction-agent.ts
SB->>TU: POST /sendblue/webhook (sb-signing-secret header)
TU->>SV: Forward request (public IP)
SV->>LA: isPublicServerRequest(req)?
LA-->>SV: true (whitelisted path)
SV->>WA: verifySendblueWebhookSecret(header)
WA-->>SV: true / false
alt signature invalid
SV-->>TU: 401 invalid webhook signature
else signature valid
SV-->>TU: 200 OK (res.json sent immediately)
SV->>DR: maybeHandleScriptedDemoReply()
alt demo mode + matching prompt
DR-->>SB: scripted iMessage reply
else normal flow
SV->>AI: handleUserMessage()
AI-->>SB: AI-generated iMessage reply
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant SB as Sendblue
participant TU as ngrok Tunnel
participant SV as Express Server
participant LA as local-access.ts
participant WA as sendblue-webhook-auth.ts
participant DR as scripted-demo-replies.ts
participant AI as interaction-agent.ts
SB->>TU: POST /sendblue/webhook (sb-signing-secret header)
TU->>SV: Forward request (public IP)
SV->>LA: isPublicServerRequest(req)?
LA-->>SV: true (whitelisted path)
SV->>WA: verifySendblueWebhookSecret(header)
WA-->>SV: true / false
alt signature invalid
SV-->>TU: 401 invalid webhook signature
else signature valid
SV-->>TU: 200 OK (res.json sent immediately)
SV->>DR: maybeHandleScriptedDemoReply()
alt demo mode + matching prompt
DR-->>SB: scripted iMessage reply
else normal flow
SV->>AI: handleUserMessage()
AI-->>SB: AI-generated iMessage reply
end
end
Reviews (6): Last reviewed commit: "Avoid duplicate webhook registration" | Re-trigger Greptile |
Summary
.env.localand process-environment precedencePrivacy and security audit
.env.localagainst every committed branch tree without printing those values; no matches.env.local,.convex, databases, logs, generated Convex files, and model caches; no private runtime data was bundled+11111111111and an unmistakable555formatting example; existing public project branding and the public bundle namespace remainVerification
npm run typechecknpm test(15 files, 71 tests)npm run build:debugnpx convex codegennpm audit(0 vulnerabilities)npm run desktop:packConnection healthyRelease note
The desktop build is still experimental, unsigned, and not notarized. Users must run setup once;
npm run desktop:setupprepares the dedicated runtime and can install the app into Applications.