Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/mendix/run-local/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ run's process session), and `run status` reports them. Do **not**
| `--web-client-timeout` | `$MXCLI_WEB_CLIENT_TIMEOUT`, else `5m` | Limit for one web client bundle build; on timeout the tail of `deployment/log/web-client-build.log` is printed |
| `--ensure-db` | off | Provision local Postgres + app database if missing |
| `--app-port` / `--admin-port` / `--serve-port` | 8080 / 8090 / 6543 | Ports |
| `--listen-addr` | `127.0.0.1` | IP the app binds to. `0.0.0.0` (or `::`) makes it reachable from other machines; the network URLs are printed once it runs. Pair it with `--runtime-setting ApplicationRootUrl=http://<host>:<port>/` (or a real host in the configuration) or generated absolute URLs name the wildcard — a warning says so. The M2EE admin API always stays on loopback |
| `--listen-addr` | `127.0.0.1` | IP the app binds to. `0.0.0.0` (or `::`) makes it reachable from other machines; the network URLs are printed once it runs. If the app builds absolute URLs (SSO redirects, email links), pair it with `--runtime-setting ApplicationRootUrl=http://<host>:<port>/` (or a real host in the configuration): the runtime does not derive one from the bind address — a warning says so. The M2EE admin API always stays on loopback |
| `--db-host` / `--db-name` / `--db-user` / `--db-password` | 127.0.0.1:5432 / derived / mendix / mendix | Database; bracket IPv6 endpoints (`[::1]:5432`) |
| `--db-type` | `postgresql` | `hsqldb` runs on the runtime's built-in file database: no database server, no `--ensure-db`, works offline. Data lives in `<project>/deployment/data/database/hsqldb/`. Refused together with `--db-host`/`--db-user`/`--db-password`/`--ensure-db`. Local development only |
| `--setup` | off | Cache MxBuild+runtime + ensure DB, then exit (SessionStart bring-up) |
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Added

- **`mxcli run --local --listen-addr` — reach a local app from another machine** (mendixlabs/mxcli#1248) — the app always bound `127.0.0.1`, so a phone or a second laptop on the LAN could not open it. `--listen-addr 0.0.0.0` (or `::`) binds every interface and prints the URLs the app is reachable at; the default stays loopback. The M2EE admin API is unaffected and stays on `127.0.0.1` whatever the flag says — before, the one option set both binds, so widening the app would have put the admin API on the network too. mxcli itself still dials the app on loopback under a wildcard (health check, screenshots, "App is running at"), and brackets an IPv6 address. The value must be an IP address and is refused before the build otherwise. With no application root URL the runtime derives one from the bind address, so a wildcard bind warns at boot and names the `--runtime-setting ApplicationRootUrl=…` to pass.
- **`mxcli run --local --listen-addr` — reach a local app from another machine** (mendixlabs/mxcli#1248) — the app always bound `127.0.0.1`, so a phone or a second laptop on the LAN could not open it. `--listen-addr 0.0.0.0` (or `::`) binds every interface and prints the URLs the app is reachable at; the default stays loopback. The M2EE admin API is unaffected and stays on `127.0.0.1` whatever the flag says — before, the one option set both binds, so widening the app would have put the admin API on the network too. mxcli itself still dials the app on loopback under a wildcard (health check, screenshots, "App is running at"), and brackets an IPv6 address. The value must be an IP address and is refused before the build otherwise. The runtime does not derive an application root URL from the bind address (measured on 11.12.1: unset stays `null` under `0.0.0.0`), so a wildcard bind with none warns at boot and names the `--runtime-setting ApplicationRootUrl=…` to pass.
- **`mxcli search --fail-on-match` turns the search into a gate** — a pipeline that must refuse a change when a forbidden word turns up in the project's text had no exit status to read: `search` exited 0 whether it found something or not. With the flag it exits 1 when there is at least one hit and 0 when there is none, printing the results as before (a JSON array under `--json`). A search that cannot run, such as an unbalanced `"` or an unknown project, exits 2 so that 1 always means a match; the `SEARCH` statement still answers an unrunnable query with "No matches found.". Without the flag a hit exits 0 as before. Rules: docs-site "Full-Text Search".
- **`filemanager` — the classic file manager (`Forms$FileManager`) in MDL** (mendixlabs/mxcli#151) — `filemanager fileManager1 (Label: 'File', Type: Upload, MaxFileSize: 10, AllowedExtensions: '.xlsx', ShowFileInBrowser: false)` inside a data view on a `System.FileDocument` specialization. Before, there was no way to author one: `pluggablewidget 'Forms$FileManager'` had no definition, the bare keyword was refused as MDL-WIDGET25, and `describe page` printed a stored one as a NOT re-executable comment, so describe → exec dropped it. Omitted properties take Studio Pro's defaults (`Both`, 5 MB, any file, false); the written BSON has the property set of a Studio Pro-authored file manager. `alter page … set` changes all four properties. A file manager in no data container is MDL-WIDGET45 at `check`, and one in a data view on an entity that is not a FileDocument is refused by `exec` — both were mxbuild's CE6810 after a clean `exec`.

Expand Down
2 changes: 1 addition & 1 deletion cmd/mxcli/cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ func init() {
runCmd.Flags().Bool("setup", false, "Prepare prerequisites (cache MxBuild+runtime, ensure DB) and exit without booting — for a SessionStart hook")
runCmd.Flags().Int("app-port", 0, "HTTP port for the app (default 8080)")
runCmd.Flags().Int("admin-port", 0, "M2EE admin API port (default 8090)")
runCmd.Flags().String("listen-addr", "", "Address the app binds to (default 127.0.0.1, loopback only). Must be an IP address. Set 0.0.0.0 (or :: for IPv6 too) to reach the app from other machines on the network; the URLs it is reachable at are printed once it runs. Pair it with a reachable root URL — an ApplicationRootUrl naming a real host in the model, or --runtime-setting ApplicationRootUrl=http://<host>:<port>/ — because with none the runtime derives its root URL from this address, which no browser can open (a warning says so). The M2EE admin API is unaffected and always stays on 127.0.0.1.")
runCmd.Flags().String("listen-addr", "", "Address the app binds to (default 127.0.0.1, loopback only). Must be an IP address. Set 0.0.0.0 (or :: for IPv6 too) to reach the app from other machines on the network; the URLs it is reachable at are printed once it runs. If the app builds absolute URLs (SSO redirects, links in emails), pair it with a reachable root URL — an ApplicationRootUrl naming a real host in the model, or --runtime-setting ApplicationRootUrl=http://<host>:<port>/ — because the runtime does not derive one from this address (a warning says so). The M2EE admin API is unaffected and always stays on 127.0.0.1.")
runCmd.Flags().Int("serve-port", 0, "mxbuild --serve port (default 6543)")
runCmd.Flags().String("mxbuild-path", "", "Path to the mxbuild to build with, overriding resolution (Studio Pro's bundled mxbuild on macOS/Windows, the cached CDN download on Linux)")
runCmd.Flags().String("db-type", "", "Database type for a local run: postgresql (default) or hsqldb (the runtime's built-in file database — no server, no --db-host/--db-user/--db-password, data under <project>/deployment/data/database/hsqldb/)")
Expand Down
3 changes: 2 additions & 1 deletion cmd/mxcli/docker/localboot.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,8 @@ func runtimeConfigParams(o LocalRuntimeOptions, constants map[string]string) map
"MicroflowConstants": constants,
}
// Only set ApplicationRootUrl when the app is served behind an external URL;
// on a plain local run the runtime defaults it from the listen address.
// on a plain local run it stays unset (the runtime does not derive one from
// the listen address; see warnWildcardWithoutRootURL).
if o.ApplicationRootUrl != "" {
params["ApplicationRootUrl"] = o.ApplicationRootUrl
}
Expand Down
28 changes: 14 additions & 14 deletions cmd/mxcli/docker/runlocal.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,9 @@ type LocalRunOptions struct {
// ListenAddr is the address the app binds to. Empty means 127.0.0.1, which
// is loopback-only on purpose. Set it to 0.0.0.0 to let the app be reached
// from other machines on the network; pair that with a reachable
// ApplicationRootUrl (--runtime-setting), because the runtime otherwise
// derives its root URL from this address and 0.0.0.0 is not a host a
// browser can ask for. The M2EE admin API is unaffected and stays on
// loopback.
// ApplicationRootUrl (--runtime-setting) if the app builds absolute URLs,
// because the runtime does not derive one (see warnWildcardWithoutRootURL).
// The M2EE admin API is unaffected and stays on loopback.
ListenAddr string
// AdminPass is the M2EE admin password (default is a fixed local-dev value).
AdminPass string
Expand Down Expand Up @@ -352,21 +351,23 @@ func applicationRootURLFrom(settings *model.ProjectSettings) (rootURL, configNam
}

// warnWildcardWithoutRootURL warns when the app binds every interface but
// nothing gives the runtime the URL it is reached at. With no
// ApplicationRootUrl the runtime derives one from the listen address, so the
// absolute URLs it generates (OIDC/SAML redirect URIs, deep links, links in
// emails) name 0.0.0.0 or ::, which no browser can open — while the app itself
// answers fine, since the client uses relative URLs. A warning rather than a
// refusal: plenty of apps generate no absolute URL at all.
// nothing gives the runtime the URL it is reached at. The runtime does NOT
// derive one from the bind address: measured on 11.12.1,
// Core.getConfiguration().getApplicationRootUrl() is null after a boot with no
// ApplicationRootUrl, under 127.0.0.1 and 0.0.0.0 alike, and is the passed value
// under --runtime-setting. So anything that builds an absolute URL from it
// (OIDC/SAML redirect URIs, links in emails) has no host another machine can
// use, while the app itself answers fine — the client uses relative URLs. A
// warning rather than a refusal: plenty of apps build no absolute URL at all.
func warnWildcardWithoutRootURL(stderr io.Writer, listen string, port int, appRootURL string, settings map[string]any) {
if !isWildcardListenAddr(listen) || appRootURL != "" {
return
}
if _, ok := settings["ApplicationRootUrl"]; ok {
return
}
fmt.Fprintf(stderr, "Warning: --listen-addr %s with no application root URL — the runtime derives one from the bind address, "+
"so absolute URLs it generates (SSO redirects, deep links) will not open from another machine. "+
fmt.Fprintf(stderr, "Warning: --listen-addr %s with no application root URL — the runtime does not derive one, "+
"so absolute URLs the app builds from it (SSO redirects, links in emails) have no host another machine can open. "+
"Pass --runtime-setting ApplicationRootUrl=http://<this-host>:%d/ or set one naming a real host in the configuration.\n",
listen, port)
}
Expand All @@ -378,8 +379,7 @@ func warnWildcardWithoutRootURL(stderr io.Writer, listen string, port int, appRo
// mean "chosen". Passing that back would be a behaviour change for every
// existing project — and an actively wrong one under --app-port, where the
// stock value names a port the app is not serving on. A loopback host also adds
// nothing: with no ApplicationRootUrl the runtime derives one from the listen
// address, which is the same thing. So only a real host name — the case this
// nothing another machine could use. So only a real host name — the case this
// exists for, giving each app in a solution its own name — is honoured.
func customHostRootURL(rootURL string) bool {
if rootURL == "" {
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/tools/run-local.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ would make Studio Pro 11.13 fail to open it — a branch with no upstream, or
| `--app-port` | 8080 | App HTTP port |
| `--admin-port` | 8090 | M2EE admin API port |
| `--serve-port` | 6543 | `mxbuild --serve` port |
| `--listen-addr` | `127.0.0.1` | IP address the app binds to (not a host name). `0.0.0.0` binds all IPv4 interfaces, `::` all interfaces, so other machines on the network can open the app; the URLs it is reachable at are printed after boot. Without an application root URL the runtime derives one from this address, so absolute URLs it generates (SSO redirects, deep links) name the wildcard: pass `--runtime-setting ApplicationRootUrl=http://<host>:<port>/` or set a real host in the configuration (a warning says so). The M2EE admin API is unaffected and always binds `127.0.0.1` |
| `--listen-addr` | `127.0.0.1` | IP address the app binds to (not a host name). `0.0.0.0` binds all IPv4 interfaces, `::` all interfaces, so other machines on the network can open the app; the URLs it is reachable at are printed after boot. The runtime does not derive an application root URL from this address, so if the app builds absolute URLs (SSO redirects, links in emails) pass `--runtime-setting ApplicationRootUrl=http://<host>:<port>/` or set a real host in the configuration (a warning says so). The M2EE admin API is unaffected and always binds `127.0.0.1` |
| `--mxbuild-path` | resolved for this host | The mxbuild to build with, overriding resolution (Studio Pro on macOS/Windows, the cached CDN download on Linux). `MXCLI_MXBUILD_PATH` sets the same override from the environment; the flag wins |
| `--db-host` | 127.0.0.1:5432 | Database `host:port`; bracket IPv6 endpoints (`[::1]:5432`) |
| `--db-name` | derived from project | Database name |
Expand Down
Loading