feat: docker run to compose converter (#623)

* feat(convert): harden /api/convert endpoint with auth, validation, and tests

Applies authMiddleware to the docker run to compose endpoint, validates
that the payload is a non-empty string within an 8192 character budget,
rejects inputs containing null bytes, and wraps composerize in a
try/catch that surfaces a 422 with a clear message when the library
cannot produce a services block. Adds a Vitest suite covering the auth
gate, happy path, common flag coverage, boundary and null byte
placement variants, and malformed command handling.

* feat(editor): add From Docker Run tab to create stack dialog

Introduces a third tab in the Create New Stack dialog that accepts a
docker run command, calls the converter endpoint, and previews the
returned compose YAML before writing it to a new stack directory. Uses
the defensive toast pattern, clears the stale preview when the input
changes, and rolls back the empty stack directory if saving the
converted YAML fails so the user never ends up with an orphan stack.

* docs(stack-management): document docker run to compose converter

Adds a Convert from a docker run command section to the stack
management page covering how to use the new tab, the list of supported
flags, and troubleshooting for unparseable inputs. Screenshots show the
empty tab, a successful conversion with the compose preview, the
resulting stack in the editor, and the error toast surfaced when the
input cannot be converted. Appends a matching entry to the
troubleshooting page.
This commit is contained in:
Anso
2026-04-15 20:23:12 -04:00
committed by GitHub
parent a02ea948a0
commit b2f341b43d
9 changed files with 517 additions and 15 deletions
+66
View File
@@ -20,6 +20,72 @@ Click **Create Stack** in the left sidebar. Enter a name and click **Create**.
Sencho creates a new directory inside `COMPOSE_DIR` with a blank `compose.yaml` file. You'll land in the editor automatically.
## Convert from a docker run command
If you have a `docker run` command handy (from a README, a forum post, or your shell history), Sencho can turn it into a ready-to-deploy `compose.yaml` without hand translation.
Open the **Create New Stack** dialog and switch to the **From Docker Run** tab.
<Frame>
<img src="/images/stack-management/convert-tab-empty.png" alt="Create stack dialog on the From Docker Run tab" />
</Frame>
### How to use it
1. Enter a **Stack Name**. Same rules as the Empty tab (lowercase, hyphens, unique).
2. Paste your full command into **Paste your docker run command**. The whole command should be on one logical line; line continuations with `\` are fine.
3. Click **Convert**. Sencho parses the command and shows the resulting compose YAML in a read-only preview below.
4. Review the YAML. If it looks right, click **Create Stack**. Sencho creates the stack directory and writes the converted YAML into `compose.yaml`.
5. The editor opens on the new stack. Click **Start** to deploy it.
<Frame>
<img src="/images/stack-management/convert-tab-result.png" alt="Converted compose YAML preview before creating the stack" />
</Frame>
<Frame>
<img src="/images/stack-management/convert-stack-created.png" alt="Newly created stack loaded in the editor after conversion" />
</Frame>
### Supported flags
The converter handles the flags you reach for most often:
| Flag | Purpose |
|------|---------|
| `-d` / `--detach` | Detached mode (implied by compose) |
| `--name` | Container name |
| `-p` / `--publish` | Port mappings (`host:container`) |
| `-v` / `--volume` | Volumes and bind mounts |
| `-e` / `--env` | Environment variables |
| `--env-file` | Env file reference |
| `--restart` | Restart policy (`no`, `always`, `unless-stopped`, `on-failure`) |
| `--network` | Attach to a named network |
| `--label` | Container labels |
| `--user` | Run as a specific user |
| `--workdir` | Set the working directory |
| `--entrypoint` | Override the entrypoint |
| `--cap-add` / `--cap-drop` | Linux capabilities |
| `--privileged` | Privileged mode |
| `--read-only` | Read-only root filesystem |
| `--tmpfs` | Temporary filesystem mount |
The image tag is taken from the final positional argument (for example `nginx:alpine`). Any trailing command arguments are preserved as the service `command`.
### Troubleshooting
<Frame>
<img src="/images/stack-management/convert-tab-error.png" alt="Error toast shown when the converter cannot parse the input" />
</Frame>
If the converter cannot produce a usable compose file, the request fails with a clear error toast. Common causes:
- **Not a docker run command.** The input must begin with `docker run` and include an image reference. Free-form text, `docker compose` commands, and shell pipelines are rejected.
- **Unrecognized flag.** The parser supports the flags listed above. Rare flags (such as `--userns`, `--ipc`, custom runtime options) may not be recognized. Remove the flag, convert the rest, and add it back by hand in the editor.
- **Quoting issues.** Multi-line commands with embedded quotes sometimes confuse the parser. Paste the command as a single line with escaped quotes, or simplify the command first.
- **Command is too long.** The endpoint accepts commands up to 8192 characters. Longer inputs are rejected; trim anything you do not need and convert in pieces.
When a flag is not supported, paste the output you do get into the **Empty** tab as a starting point and fill in the rest by editing `compose.yaml` directly.
## The stack list
All discovered stacks appear in the left sidebar. Each shows a color-coded status indicator:
Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

+17
View File
@@ -561,3 +561,20 @@ docker logs -f sencho
```
The backend logs all route errors and service failures to stdout. This is the first place to look when the UI shows an error with no useful message.
---
## "Could not parse command" when converting docker run
**Symptom:** The **From Docker Run** tab in the Create Stack dialog returns an error toast saying the command could not be parsed.
**Cause:** The input is not a well-formed `docker run` command, or it uses a flag the converter does not recognize.
**Fix:**
- Make sure the command starts with `docker run` and ends with an image reference (e.g. `nginx:alpine`).
- Check the [list of supported flags](/features/stack-management#supported-flags). Rare flags (such as `--userns` or custom runtime options) are not recognized. Remove the flag before converting and add it back manually in the editor afterwards.
- Collapse multi-line commands into a single line. Mixed quoting across `\`-continued lines is a common source of parse errors.
- Commands longer than 8192 characters are rejected. Trim anything non-essential and run the converter on the reduced command.
When only part of a command is supported, convert what you can, paste the resulting YAML into the **Empty** tab as a starting point, and hand-edit the rest in `compose.yaml`.