Skip to content

fix(cli): serve TCP and Unix listeners without QUIC - #2879

Merged
kixelated merged 4 commits into
devfrom
codex/fix-cli-stream-only
Aug 16, 2026
Merged

fix(cli): serve TCP and Unix listeners without QUIC#2879
kixelated merged 4 commits into
devfrom
codex/fix-cli-stream-only

Conversation

@kixelated

@kixelated kixelated commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Treat explicit TCP and Unix qmux binds as a MoQ server side during validation and startup.
  • Bind every listener before reporting systemd readiness, including TCP and Unix stream listeners.
  • Keep explicit stream listeners public when they share a server with the LAN mesh, without exposing the mesh-created QUIC listener.
  • Compile the raw qmux listener features into moq-cli release builds.
  • Document the canonical listener flags and reject them on local-only commands.

Root cause

Both CLI validation and server startup use MoqSide::serves(), but it only checked the QUIC --listen bind and LAN discovery. The native server already supports stream-only operation, so a TCP-only or Unix-only configuration was parsed and then treated as if no server had been requested. Also, moq-cli disabled moq-native default features without explicitly enabling tcp and uds, which made those flags depend on workspace feature unification instead of the released CLI feature graph.

Stream sockets are bound asynchronously by Server::listen(). The CLI previously moved Server into a spawned serve task and immediately notified systemd, so READY=1 could precede the socket bind and could even be emitted when the bind later failed. The CLI now attaches ordinary-session routing before the stream accept loops capture it, awaits listen(), and gives the spawned task an already-bound Listener. A failed bind therefore aborts initialization before readiness.

LAN dispatch used the presence of an explicit QUIC bind as a server-wide public flag. That rejected ordinary requests arriving on explicit TCP and Unix listeners, while changing the flag to cover every listener would also expose the mesh-created QUIC port. Public access is now decided per transport. Local-only command rejection also omitted Unix credential allowlist flags, and the CLI documentation overstated the protection from a socket that is deliberately created with mode 0666.

Public API changes

  • Add the documented, additive moq_native::listen::Config::has_explicit_bind() query.
  • Include tcp and uds in the moq-cli dependency feature set.

Test plan

  • nix develop --command just fix
  • nix develop --command env CARGO_TARGET_DIR=/home/kixelated/work/moq/target/codex-cli-stream-only CARGO_INCREMENTAL=0 just check
  • nix develop --command env CARGO_TARGET_DIR=/home/kixelated/work/moq/target/codex-cli-stream-only CARGO_INCREMENTAL=0 cargo test -p moq-cli a_stream_bind_failure_prevents_readiness -- --nocapture
  • nix develop --command cargo test -p moq-cli --no-default-features --features quinn
  • nix develop --command cargo test -p moq-native --lib --no-default-features --features aws-lc-rs,tcp,uds stream_
  • nix develop --command cargo test -p moq-cli --no-default-features --features quinn,cluster-lan explicit_stream_listeners_are_public_without_exposing_mesh_quic
  • nix develop --command cargo test -p moq-cli --no-default-features --features quinn token_verb
  • nix develop --command bun remark doc/bin/cli.md rs/moq-cli/README.md --quiet --frail

The rs/moq-cli documentation sync is included. This does not change the wire protocol, FFI, gateways, catalog, or container format.

Closes #2834

(Written by GPT-5)

Co-Authored-By: GPT-5 <noreply@openai.com>
@kixelated
kixelated marked this pull request as ready for review August 16, 2026 00:06

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ba3004f64

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rs/moq-cli/src/args.rs Outdated
/// Whether a listener has to be bound at all.
pub fn serves(&self) -> bool {
self.server.resolved().bind.is_some() || self.lan()
self.server.has_explicit_listener() || self.lan()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat stream binds as public in LAN mode

When --cluster-lan is combined with only --listen-tcp-bind or --listen-unix-bind, this now starts the server, but spawn_server still passes moq.server.bind.is_some() as the public argument to cluster::serve. Because the QUIC bind was not explicitly set, cluster::serve considers the server mesh-only and closes every non-peer request with 404, including requests arriving on the explicitly configured TCP or Unix listener. The public-listener decision must include these stream binds as well.

Useful? React with 👍 / 👎.

Comment thread rs/moq-cli/src/args.rs Outdated
Comment on lines +323 to +324
#[cfg(unix)]
let ignored = ignored.or_else(|| listen.unix.bind.is_some().then_some("--listen-unix-bind"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject Unix allowlist flags on local commands

When token or devices is invoked with --listen-unix-allow-uid, --listen-unix-allow-gid, or --listen-unix-allow-pid but no Unix bind, these newly exposed CLI flags populate listen.unix.allow, while this check examines only listen.unix.bind. The local command therefore succeeds while silently ignoring the supplied MoQ listener security configuration; inspect the allowlist fields here just as the bind is inspected.

Useful? React with 👍 / 👎.

Co-Authored-By: GPT-5 <noreply@openai.com>
@kixelated
kixelated marked this pull request as draft August 16, 2026 00:12

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39b4c2f416

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread doc/bin/cli.md Outdated
Comment on lines +91 to +93
- `--listen-unix-bind <path>` hosts qmux over a Unix socket. The socket's
filesystem permissions control access, and an optional peer-credential
allowlist can restrict it further.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not present the Unix socket as permission-restricted

When this listener is placed in a traversable directory such as /tmp or /run, the documentation implies that its socket permissions provide an access boundary, but StreamListeners::start unconditionally changes the socket to mode 0o666 and the allowlist defaults to None. Consequently, any local user who can traverse the parent directory can connect and publish or consume through this CLI; document that a restrictive parent directory or an explicit credential allowlist is required, or expose a configurable socket mode.

Useful? React with 👍 / 👎.

Co-Authored-By: GPT-5 <noreply@openai.com>
@kixelated
kixelated marked this pull request as ready for review August 16, 2026 00:39

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca54c81a8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rs/moq-cli/src/args.rs
/// Whether a listener has to be bound at all.
pub fn serves(&self) -> bool {
self.server.resolved().bind.is_some() || self.lan()
self.server.has_explicit_bind() || self.lan()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bind stream listeners before reporting readiness

With only --listen-tcp-bind or --listen-unix-bind, this now lets startup continue, but those sockets are bound later inside Server::listen() in the spawned serve task; spawn_moq calls notify_ready() immediately after spawning that task. As a result, systemd can receive READY=1 before the socket exists, and even receives it when the requested address or path cannot be bound, causing traffic to be routed to an unavailable process. Bind the stream listener before notifying readiness and add a regression test that verifies readiness is withheld on bind failure. (Written by GPT-5.6 Sol)

AGENTS.md reference: AGENTS.md:L123-L123

Useful? React with 👍 / 👎.

Co-Authored-By: GPT-5 <noreply@openai.com>

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: c7a166df58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@kixelated
kixelated merged commit 8a838ee into dev Aug 16, 2026
2 checks passed
@kixelated
kixelated deleted the codex/fix-cli-stream-only branch August 16, 2026 01:10
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