Skip to content

listen --path persistently mutates the destination; consider a client-side forwarding rewrite #372

Description

@leggetter

hookdeck listen --path is not a session flag. When the value differs from what the destination already has, Listen PATCHes the destination (pkg/listen/listen.go:100-119), writing destinations.cli_path — a persisted column (server/migrations/20210327154934_destination-cli-path.ts in core). The change outlives the process and applies to every subsequent hookdeck listen on that connection, including other people's on a shared project.

That is surprising for a flag that reads like "for this run, deliver to this local path", and it is the root of several downstream constraints:

  • --path is rejected outright with multiple sources (pkg/listen/listen.go:57), because one flag value cannot express per-connection paths.
  • It is rejected again when multiple CLI destinations resolve (pkg/listen/listen.go:88), because we do not want to rewrite several destinations at once.
  • The Console cmd_hint bakes in --path /webhooks (server/controllers/console-test-url-response.ts:16 in core). If the user's local server does not serve /webhooks, the wrong path is persisted rather than just being wrong for one run.

The idea

Make --path a client-side forwarding rewrite instead of a destination mutation.

The CLI already has what it needs to do this per connection. The attempt message carries webhook_id (the connection id) alongside cli_path (pkg/websocket/attempt_messages.go:12-20), so the proxy knows which connection each attempt belongs to and could substitute a local path per connection when building the forward URL at pkg/listen/proxy/proxy.go:373, without touching stored config.

Reporting stays truthful

The obvious objection is that the dashboard would then show something other than where the request actually went. It would not, as long as the CLI reports the rewritten value.

server/cli/routes/attempt.ts in core takes body.cli_path off the CLI's attempt_response and publishes it as requested_url on the attempt completion. The recorded URL for a CLI attempt is whatever the CLI sends, not the stored destinations.cli_path. Today the CLI echoes the server-supplied path verbatim (pkg/listen/proxy/proxy.go:526); it would need to send the rewritten path instead.

What this would unlock

  • --path stops mutating shared project state, so running it is no longer something you can get wrong in a way that persists.
  • The multi-source restriction can be reconsidered on its own merits rather than as a guard against multi-destination writes. A single --path across several sources becomes a per-session default, and a per-source form (stripe=/webhooks/stripe,...) becomes expressible if we ever want it.
  • The Console cmd_hint can keep suggesting a path without the risk of leaving a wrong one behind.

Open questions

  • Is anyone relying on --path as the way to set a destination's path persistently? If so, that use case needs an explicit home — connection update / destination update already exist and are arguably the right place for it.
  • Migration: changing what an existing flag does is a behaviour change. Options are a new flag, a deprecation period, or a major-version change.
  • requested_url is published as just the path today, since that is what the CLI sends. Worth confirming how the dashboard renders it before relying on it to carry the rewrite.

Relationship to #371

Split out of #371, which is about the multi-source panic and silent drop. That issue can be fixed without any of this. This one is the larger question behind the --path restrictions it runs into.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions