mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 14:09:42 +02:00
30 pages covering install, concepts, the dashboard, the agent CLIs, unattended
runs, remote and Docker cases, security and the HTTP API, plus a sidebar and a
footer. The wiki repo has no CI and no review, so docs/wiki is the source of
truth and .github/workflows/wiki-sync.yml mirrors it on every push to master.
The workflow refuses to mirror when docs/wiki is missing or holds no pages,
because it deletes before it copies and would otherwise publish the deletion of
every page. The footer carries a {{VERSION}} placeholder stamped at publish
time rather than a hand-written version, which went stale on every release.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
102 lines
5.1 KiB
Markdown
102 lines
5.1 KiB
Markdown
# Web Tabs
|
|
|
|
Open any dashboard you run, Grafana, Uptime Kuma, Portainer, a status page on port 4000, as
|
|
a tab beside your agent sessions. Codeman becomes one mission control instead of Codeman
|
|
plus a pile of browser tabs.
|
|
|
|
A web tab is **not a session**. There is no PTY, no tmux, and no respawn behind it, the same
|
|
way a docker case is not a run mode.
|
|
|
|
## Adding one
|
|
|
|
1. Click the chevron next to **Run**.
|
|
2. Under **Web / URL**, pick **Add URL**.
|
|
3. Name it, paste the URL, optionally hit **Test**, and **Save**.
|
|
|
|
It opens immediately and appears in the dropdown from then on. Web tabs share the tab strip
|
|
with sessions, continue the same `Alt+1` to `Alt+9` numbering, and carry a globe icon so
|
|
they never read as a running agent.
|
|
|
|
**Closing a tab is not deleting it.** The tab's `x` closes; the `x` on its **dropdown row**
|
|
deletes the saved dashboard. Each dropdown row also has a gear for editing the URL.
|
|
|
|
Switching tabs does not reload a dashboard. Frames stay alive in the background, so one that
|
|
took a while to authenticate is still there when you come back. Past six live frames, the
|
|
least recently viewed is dropped to bound memory.
|
|
|
|
## Why dashboards are proxied
|
|
|
|
A plain cross-origin iframe fails three ways at once in the setup Codeman actually ships in:
|
|
|
|
| Blocker | What happens |
|
|
| ------------------- | ----------------------------------------------------------------------------------------------- |
|
|
| **Mixed content** | Production is HTTPS, and browsers hard-block `http://` iframes on an HTTPS page. No override, and none at all on iOS Safari. |
|
|
| **Framing refusal** | Grafana, Portainer, Home Assistant and many others send `X-Frame-Options: DENY`. |
|
|
| **Codeman's CSP** | `default-src 'self'` blocks a cross-origin frame before it starts. |
|
|
|
|
So by default the dashboard is served **through Codeman's own origin**: the browser loads a
|
|
path on Codeman, and Codeman relays to the dashboard, stripping the framing refusal,
|
|
rewriting redirects, cookies and root-absolute URLs, and relaying WebSockets so live panels
|
|
still update.
|
|
|
|
A useful side effect: the dashboard is fetched **by the Codeman server**, so a tailnet-only
|
|
or localhost-only dashboard works from any device that can reach Codeman, including a phone
|
|
that is not on your tailnet.
|
|
|
|
There is also a `direct` mode, a plain cross-origin iframe, which is cheaper but only works
|
|
for an HTTPS dashboard that permits framing.
|
|
|
|
## The Test button, and what it does not test
|
|
|
|
**Test** probes from the server and tells you which mode applies. It verifies
|
|
**server-to-upstream reachability and nothing else**. It does not exercise the browser
|
|
sandbox, cookies, CORS, CSP, or any reverse proxy in front of Codeman.
|
|
|
|
A passing Test does not guarantee the embedded page renders.
|
|
|
|
## The sandbox, and when to turn it off
|
|
|
|
Because a proxied dashboard is served from Codeman's own address, the browser considers it
|
|
same-origin with Codeman. Unchecked, its JavaScript could read the Codeman page and call the
|
|
API that spawns agents.
|
|
|
|
So the frame is sandboxed **without** same-origin access by default. The page runs in an
|
|
opaque origin: it cannot touch Codeman, and it gets no cookies or local storage of its own.
|
|
|
|
Unchecking **Open sandboxed** grants a real origin. Do that only for a dashboard you fully
|
|
trust, and only when you need it, which in practice means one with its own login that stores
|
|
a session in a cookie.
|
|
|
|
Either way, Codeman never forwards its own credentials upstream. The `Authorization` header
|
|
and the `codeman_session` cookie are stripped on the way out, so `CODEMAN_PASSWORD` cannot
|
|
leak into a dashboard.
|
|
|
|
## Known incompatibility: cookie-authenticated reverse proxies
|
|
|
|
If Codeman itself sits behind Cloudflare Access, Authelia, oauth2-proxy, or similar, a
|
|
**sandboxed** tab may render unstyled or broken while the Codeman page around it works fine.
|
|
|
|
The reason: an opaque-origin frame's stylesheet, script, and API requests do not carry the
|
|
proxy's authentication cookie. The proxy redirects them to the login provider, and CORS or
|
|
CSP kills them there.
|
|
|
|
Trusted mode keeps a real origin and the cookie, so it works. Test cannot catch this, because
|
|
it checks the server's reach, not the browser's.
|
|
|
|
## Security notes
|
|
|
|
The proxy authenticates on an in-memory capability embedded in the path, which is why it is
|
|
exempt from the cookie and Origin checks that every API route enforces. That exemption is
|
|
fenced to safe methods and non-API paths, and there is a test pinning it in place.
|
|
|
|
Two failure modes that only appear inside a sandboxed frame, and that curl can never
|
|
reproduce, are handled: runtime-built root-absolute URLs escaping the injected base, and
|
|
same-host requests being CORS-checked with a null origin. Both present as the dashboard's own
|
|
"Failed to fetch" while the page itself renders fine.
|
|
|
|
## Read next
|
|
|
|
- [The Dashboard](The-Dashboard) - the tab strip these share.
|
|
- [Security](Security) - why the sandbox default is what it is.
|
|
- [`docs/web-tabs.md`](https://github.com/Ark0N/Codeman/blob/master/docs/web-tabs.md) - the full reference.
|