Skip to content

Add desktop app, resilient webhooks, and realistic demo mode#67

Merged
raroque merged 6 commits into
mainfrom
codex/electron-app
Jul 13, 2026
Merged

Add desktop app, resilient webhooks, and realistic demo mode#67
raroque merged 6 commits into
mainfrom
codex/electron-app

Conversation

@raroque

@raroque raroque commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

  • add an experimental Dock-runnable desktop app with one-time setup, start/stop/restart controls, a macOS status menu, the Boop icon, and an embedded dashboard
  • synchronize signed Sendblue webhooks on every startup, compare the registered webhook with the active public URL, migrate signing secrets without duplicate subscriptions, preserve legacy and current image payload fields, and load quoted environment values with .env.local and process-environment precedence
  • keep private server, dashboard, browser-control, configuration, and WebSocket routes local while exposing only health and verified provider webhooks through the public tunnel
  • make demo mode realistic across dashboard metrics, memories, the connected memory graph, agents and sub-agents, tool traces, automations, events, consolidation, and the full Composio catalog
  • isolate mutable runtime data and the optional local embedding cache from the app bundle, refresh packaged source safely, and document terminal vs desktop setup clearly

Privacy and security audit

  • scanned every added line in all six branch commits, including content later removed, for private emails, phone numbers, local paths, live tunnel/Convex URLs, key-shaped secrets, and private-key material
  • compared sensitive values from the local .env.local against every committed branch tree without printing those values; no matches
  • scanned the packaged app for local paths, runtime env values, PII patterns, .env.local, .convex, databases, logs, generated Convex files, and model caches; no private runtime data was bundled
  • phone-shaped additions are limited to the intentional demo placeholder +11111111111 and an unmistakable 555 formatting example; existing public project branding and the public bundle namespace remain

Verification

  • npm run typecheck
  • npm test (15 files, 71 tests)
  • npm run build:debug
  • npx convex codegen
  • npm audit (0 vulnerabilities)
  • npm run desktop:pack
  • installed and relaunched the exact final app bundle; dashboard reported Connection healthy
  • verified the packaged Sharp/libvips native pair and a 1,024-dimensional finite local embedding
  • verified the demo memory graph, realistic records and sub-agent traces, and the paginated Composio catalog (1,047 toolkits in the configured test environment)
  • verified private HTTP routes return 404 through the public tunnel and external WebSocket connections are rejected

Release note

The desktop build is still experimental, unsigned, and not notarized. Users must run setup once; npm run desktop:setup prepares the dedicated runtime and can install the app into Applications.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This 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.

  • Desktop app (electron/): packages the runtime into a mutable user-data directory, creates a Node shim from the Electron binary, manages child-process lifecycle (start/stop/restart with identity-guarded exit handlers), and embeds the debug dashboard in a status-page iframe with a scoped-origin postMessage bridge.
  • Resilient webhooks (scripts/sendblue-webhook.mjs, server/sendblue-webhook-auth.ts): migrates from CLI-only to REST-API-based webhook registration, derives a scoped HMAC secret from the API key so the raw secret is never transmitted, and synchronizes the globalSecret when it drifts; the server now rejects unauthenticated Sendblue callbacks with a 401 and uses timingSafeEqual throughout.
  • Local-only gate (server/local-access.ts, server/index.ts): a middleware layer checks socket address, Host, Origin, and all three forwarding-header formats, allowing only /health and the two provider-webhook endpoints publicly while rejecting everything else (including WebSocket upgrades) from non-local origins.

Confidence Score: 5/5

Safe 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

Filename Overview
server/local-access.ts New module enforcing local-only access for private routes with multi-layer guards (socket address, host header, origin, forwarding headers); correctly uses isLocalAuthority for Forwarded host= parameter.
electron/main.cjs New Electron main process for desktop lifecycle, runtime copying, node shim, webhook checking, and process management. Known concerns already flagged in previous review; process identity guard in exit handlers is correctly implemented.
server/sendblue-webhook-auth.ts New HMAC-based webhook signature verification using timingSafeEqual; derives a scoped secret so the raw API secret is never transmitted.
scripts/sendblue-webhook.mjs Reworked to use Sendblue REST API directly with signing-secret synchronization, check-only mode with JSON output, and quoted env-value parsing. Well-tested.
server/sendblue.ts Adds webhook signature verification, unified media-URL extraction, phone-number redaction in error logs, and scripted demo reply interception after HTTP response is sent.
server/index.ts Gate middleware allows only health and provider webhook endpoints publicly; WebSocket connections restricted to trusted-local requests.
electron/preload.cjs Minimal preload exposing only specific IPC channels via contextBridge with contextIsolation enforced.
electron/status.js Status page renderer scoping postMessages to exact local dashboard origin and validating iframe URLs against local-only hostnames.
convex/demo.ts Large expansion of demo-mode fixtures with deterministic FNV-1a-based unit embedding so demo mode works without a real embedding service.

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
Loading
%%{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
Loading

Reviews (6): Last reviewed commit: "Avoid duplicate webhook registration" | Re-trigger Greptile

Comment thread electron/main.cjs
Comment thread electron/main.cjs
@raroque raroque changed the title Add desktop app and webhook status checks Add desktop app, resilient webhooks, and realistic demo mode Jul 13, 2026
@raroque raroque merged commit 3197913 into main Jul 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant