Skip to content

Commit 94e41d3

Browse files
authored
Add arbitrary mux server command argument parsing (#738)
## Summary - add a new `additional_arguments` module variable to pass extra arguments to `mux server` - parse `additional_arguments` in `run.sh` with quoted-group support so values like paths with spaces are preserved - keep existing `add-project` behavior while allowing additional arbitrary flags - add Terraform and Bun tests covering `additional_arguments` behavior - document the new option in the module README and bump example version references to `1.2.0` ## Why The module previously only supported the `add-project` flag. This change lets users pass additional `mux server` arguments without waiting for new module variables. ## Validation - `shellcheck --severity=warning --format=gcc registry/coder/modules/mux/run.sh` - `terraform -chdir=registry/coder/modules/mux test -verbose` - `bun test registry/coder/modules/mux/main.test.ts` ## Breaking changes None. --- Generated with Mux (exec agent) using GPT-5.
1 parent 480bf4b commit 94e41d3

5 files changed

Lines changed: 115 additions & 7 deletions

File tree

registry/coder/modules/mux/README.md

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Automatically install and run [Mux](https://github.com/coder/mux) in a Coder wor
1414
module "mux" {
1515
count = data.coder_workspace.me.start_count
1616
source = "registry.coder.com/coder/mux/coder"
17-
version = "1.1.0"
17+
version = "1.2.0"
1818
agent_id = coder_agent.main.id
1919
}
2020
```
@@ -37,7 +37,7 @@ module "mux" {
3737
module "mux" {
3838
count = data.coder_workspace.me.start_count
3939
source = "registry.coder.com/coder/mux/coder"
40-
version = "1.1.0"
40+
version = "1.2.0"
4141
agent_id = coder_agent.main.id
4242
}
4343
```
@@ -48,7 +48,7 @@ module "mux" {
4848
module "mux" {
4949
count = data.coder_workspace.me.start_count
5050
source = "registry.coder.com/coder/mux/coder"
51-
version = "1.1.0"
51+
version = "1.2.0"
5252
agent_id = coder_agent.main.id
5353
# Default is "latest"; set to a specific version to pin
5454
install_version = "0.4.0"
@@ -63,19 +63,34 @@ Start Mux with `mux server --add-project /path/to/project`:
6363
module "mux" {
6464
count = data.coder_workspace.me.start_count
6565
source = "registry.coder.com/coder/mux/coder"
66-
version = "1.1.0"
66+
version = "1.2.0"
6767
agent_id = coder_agent.main.id
6868
add-project = "/path/to/project"
6969
}
7070
```
7171

72+
### Pass Arbitrary `mux server` Arguments
73+
74+
Use `additional_arguments` to append additional arguments to `mux server`.
75+
The module parses quoted values, so grouped arguments remain intact.
76+
77+
```tf
78+
module "mux" {
79+
count = data.coder_workspace.me.start_count
80+
source = "registry.coder.com/coder/mux/coder"
81+
version = "1.2.0"
82+
agent_id = coder_agent.main.id
83+
additional_arguments = "--open-mode pinned --add-project '/workspaces/my repo'"
84+
}
85+
```
86+
7287
### Custom Port
7388

7489
```tf
7590
module "mux" {
7691
count = data.coder_workspace.me.start_count
7792
source = "registry.coder.com/coder/mux/coder"
78-
version = "1.1.0"
93+
version = "1.2.0"
7994
agent_id = coder_agent.main.id
8095
port = 8080
8196
}
@@ -89,7 +104,7 @@ Run an existing copy of Mux if found, otherwise install from npm:
89104
module "mux" {
90105
count = data.coder_workspace.me.start_count
91106
source = "registry.coder.com/coder/mux/coder"
92-
version = "1.1.0"
107+
version = "1.2.0"
93108
agent_id = coder_agent.main.id
94109
use_cached = true
95110
}
@@ -103,7 +118,7 @@ Run without installing from the network (requires Mux to be pre-installed):
103118
module "mux" {
104119
count = data.coder_workspace.me.start_count
105120
source = "registry.coder.com/coder/mux/coder"
106-
version = "1.1.0"
121+
version = "1.2.0"
107122
agent_id = coder_agent.main.id
108123
install = false
109124
}

registry/coder/modules/mux/main.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { describe, expect, it } from "bun:test";
22
import {
33
executeScriptInContainer,
4+
execContainer,
5+
findResourceInstance,
6+
readFileContainer,
7+
removeContainer,
8+
runContainer,
49
runTerraformApply,
510
runTerraformInit,
611
testRequiredVariables,
@@ -40,6 +45,57 @@ describe("mux", async () => {
4045
}
4146
}, 60000);
4247

48+
it("parses custom additional_arguments", async () => {
49+
const state = await runTerraformApply(import.meta.dir, {
50+
agent_id: "foo",
51+
install: false,
52+
log_path: "/tmp/mux.log",
53+
additional_arguments:
54+
"--open-mode pinned --add-project '/workspaces/my repo'",
55+
});
56+
57+
const instance = findResourceInstance(state, "coder_script");
58+
const id = await runContainer("alpine/curl");
59+
60+
try {
61+
const setup = await execContainer(id, [
62+
"sh",
63+
"-c",
64+
`apk add --no-cache bash >/dev/null
65+
mkdir -p /tmp/mux
66+
cat <<'EOF' > /tmp/mux/mux
67+
#!/usr/bin/env sh
68+
i=1
69+
for arg in "$@"; do
70+
echo "arg$i=$arg"
71+
i=$((i + 1))
72+
done
73+
EOF
74+
chmod +x /tmp/mux/mux`,
75+
]);
76+
expect(setup.exitCode).toBe(0);
77+
78+
const output = await execContainer(id, ["sh", "-c", instance.script]);
79+
if (output.exitCode !== 0) {
80+
console.log("STDOUT:\n" + output.stdout);
81+
console.log("STDERR:\n" + output.stderr);
82+
}
83+
expect(output.exitCode).toBe(0);
84+
85+
await execContainer(id, ["sh", "-c", "sleep 1"]);
86+
const log = await readFileContainer(id, "/tmp/mux.log");
87+
expect(log).toContain("arg1=server");
88+
expect(log).toContain("arg2=--port");
89+
expect(log).toContain("arg3=4000");
90+
expect(log).toContain("arg4=--open-mode");
91+
expect(log).toContain("arg5=pinned");
92+
expect(log).toContain("arg6=--add-project");
93+
expect(log).toContain("arg7=/workspaces/my repo");
94+
} finally {
95+
await removeContainer(id);
96+
}
97+
}, 60000);
98+
4399
it("runs with npm present", async () => {
44100
const state = await runTerraformApply(import.meta.dir, {
45101
agent_id: "foo",

registry/coder/modules/mux/main.tf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ variable "add-project" {
5555
default = null
5656
}
5757

58+
variable "additional_arguments" {
59+
type = string
60+
description = "Additional command-line arguments to pass to `mux server` (for example: `--add-project /path --open-mode pinned`)."
61+
default = ""
62+
}
63+
5864
variable "install_version" {
5965
type = string
6066
description = "The version or dist-tag of Mux to install."
@@ -142,6 +148,7 @@ resource "coder_script" "mux" {
142148
PORT : var.port,
143149
LOG_PATH : var.log_path,
144150
ADD_PROJECT : var.add-project == null ? "" : var.add-project,
151+
ADDITIONAL_ARGUMENTS : var.additional_arguments,
145152
INSTALL_PREFIX : var.install_prefix,
146153
OFFLINE : !var.install,
147154
USE_CACHED : var.use_cached,

registry/coder/modules/mux/mux.tftest.hcl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ run "auth_token_in_url" {
7979
}
8080
}
8181

82+
run "custom_additional_arguments" {
83+
command = plan
84+
85+
variables {
86+
agent_id = "foo"
87+
additional_arguments = "--open-mode pinned --add-project '/workspaces/my repo'"
88+
}
89+
90+
assert {
91+
condition = strcontains(resource.coder_script.mux.script, "--open-mode pinned --add-project '/workspaces/my repo'")
92+
error_message = "mux launch script must include the configured additional arguments"
93+
}
94+
}
95+
8296
run "custom_version" {
8397
command = plan
8498

registry/coder/modules/mux/run.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@ function run_mux() {
2020
if [ -n "${ADD_PROJECT}" ]; then
2121
set -- "$@" --add-project "${ADD_PROJECT}"
2222
fi
23+
24+
# Parse additional user-supplied server arguments while preserving quoted groups.
25+
if [ -n "${ADDITIONAL_ARGUMENTS}" ]; then
26+
local parsed_additional_arguments
27+
if ! parsed_additional_arguments="$(printf "%s\n" "${ADDITIONAL_ARGUMENTS}" | xargs -n1 printf "%s\n" 2> /dev/null)"; then
28+
echo "❌ Failed to parse additional_arguments. Ensure quotes are balanced."
29+
exit 1
30+
fi
31+
while IFS= read -r parsed_arg; do
32+
[ -n "$parsed_arg" ] || continue
33+
set -- "$@" "$parsed_arg"
34+
done << EOF
35+
$${parsed_additional_arguments}
36+
EOF
37+
fi
38+
2339
echo "🚀 Starting mux server on port $port_value..."
2440
echo "Check logs at ${LOG_PATH}!"
2541
MUX_SERVER_AUTH_TOKEN="$auth_token_value" PORT="$port_value" "$MUX_BINARY" "$@" > "${LOG_PATH}" 2>&1 &

0 commit comments

Comments
 (0)