Skip to content
Open
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
1 change: 0 additions & 1 deletion .github/workflows/deploy-cp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@ jobs:
DD_AUTH_COOKIE_DOMAIN="$DD_AUTH_COOKIE_DOMAIN" \
DD_AUTH_COOKIE_SECRET="$DD_AUTH_COOKIE_SECRET" \
bake apps/dd-shell/workload.json.tmpl
bake apps/ee-proxy/workload.json.tmpl
} | jq -cs '.')
# EE_CAPTURE_SOCKET tells EE (post-capture-socket patch) to tee
Expand Down
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Zero shared secrets. Cloudflare handles tunnel/DNS routing only; DD owns auth in

| Caller | Endpoint | Auth |
| --- | --- | --- |
| Human browser | CP `/`, agent `/`, dd-shell terminal | DD GitHub App OAuth broker + signed DD session cookie |
| Human browser | CP `/`, agent `/` | DD GitHub App OAuth broker + signed DD session cookie |
| Agent → CP | `/register`, `/ingress/replace` | Intel ITA token verified in-code |
| CI → agent | `/deploy`, `/exec`, `/logs/{app}` | GitHub Actions OIDC JWT verified in-code (`repository_owner == DD_OWNER`) |
| Anyone | `/health`, `/cp/attest`, `/api/agents`, workload URLs | Public read-only or self-authenticating content |
Expand Down Expand Up @@ -111,12 +111,26 @@ The agent verifies the OIDC token against GitHub's JWKS, checks `repository_owne

## Terminal access

Each VM runs `dd-shell` as a workload on a `-shell` labelled subdomain (for example `app-shell.devopsdefender.com` or `<agent>-shell.devopsdefender.com`). DD gates it behind the same GitHub App broker session as the dashboards. The shell UI separates observed read-only workload logs from controlled read-write PTY sessions. Read-only viewing does not change integrity state because it cannot send input or signals; read-write PTYs are controlled as soon as they exist and keep encrypted transcript history inside the enclave.

The shell is installable as a small PWA. Browser notifications are always
delivered by default when permission is granted; on mobile, install the shell
from the browser so the service worker can present notifications through the
platform notification surface while the shell is active.
Each VM runs `dd-sessiond` as the local session supervisor. `dd-sessiond` owns
PTYs, child process groups, resize/close control, and encrypted transcript
history inside the enclave.

Native clients use a paired device key against the agent's `/noise/ws` endpoint.
The bootstrap flow fetches `/health`, appraises `noise.quote_b64` with Intel
Trust Authority, checks that the quote binds `noise.pubkey_hex` into TDX
`report_data`, and then runs Noise_IK over WebSocket. The exposed session RPC surface is
`shell.list_recipes`, `shell.list_sessions`, `shell.create_session`,
`shell.replay_session`, `shell.resize_session`, `shell.close_session`, and the
streaming `shell.attach_session` method. Session control and PTY bytes flow
inside the Noise transport to the agent and then to local `dd-sessiond`; the CP
is used for enrollment brokering and route discovery, not for shell/log/session
bytes or paired-device trust storage.

Client implementations live outside this repo in
[`devopsdefender/dd-client`](https://github.com/devopsdefender/dd-client),
which contains the shared client core, CLI, and native app workspace.
The browser remains dashboard and enrollment UI only. Shell/session workflows
belong in `dd-client`.

## STONITH

Expand Down
69 changes: 32 additions & 37 deletions apps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,34 +117,34 @@ it does not create a read-write terminal or any input path into the workload.

DD separates terminal access by capability:

- **Read-only workload terminals** show workload logs in the dd-shell xterm UI.
- **Read-only workload terminals** show workload logs in the terminal UI.
They are for oracle-style services where an operator should be able to inspect
output without sending input, resizing a PTY, interrupting, or closing the
process. Opening a read-only terminal is observation only, so it leaves the
workload's user-facing integrity state clean.
- **Read-write PTY sessions** are created inside `dd-shell`. They are for
- **Read-write PTY sessions** are owned by `dd-sessiond`. They are for
confidential shells and ZDR coding agents such as Codex or Claude. These
sessions are reconnectable and write encrypted transcript records under
`DD_SHELL_DIR`. A read-write PTY is controlled as soon as it exists because
the holder can send stdin, resize the terminal, and deliver terminal signals.
sessions are reconnectable and write encrypted transcript records. A
read-write PTY is controlled as soon as it exists because the holder can send
stdin, resize the terminal, and deliver terminal signals.

The shell UI treats both as terminal views, but only read-write sessions get
WebSocket input, resize, and close controls. Workloads do not opt into
read-write access by putting metadata in `workload.json`; the boundary is the
dd-shell API surface. Internally DD may still call this taint tracking, but the
API/UI should speak in integrity terms: clean for observed-only logs,
controlled for interactive PTYs or other human control paths.
The native client treats both as terminal views, but only read-write sessions
get input, resize, and close controls. Workloads do not opt into read-write
access by putting metadata in `workload.json`; the boundary is the session
protocol exposed by `dd-agent` over Noise.
Internally DD may still call this taint tracking, but the API/UI should speak in
integrity terms: clean for observed-only logs, controlled for interactive PTYs
or other human control paths.

The renderer uses vendored xterm assets and recognizes WezTerm-compatible
notification escapes after the user grants browser notification permission:
Native clients may recognize WezTerm-compatible notification escapes:

```sh
printf '\033]9;%s\033\\' 'job finished'
printf '\033]777;notify;%s;%s\033\\' 'oracle' 'new result available'
```

For mobile web, this is the first step toward a PWA-style shell inbox: read-only
workload cards, read-write Codex/Claude session cards, and push-backed
The native desktop/mobile app is the target for shell inbox workflows:
read-only workload cards, read-write Codex/Claude session cards, and
notifications for long-running jobs.

Per-workload ingress is **boot-time only** today. Workloads POSTed later via
Expand Down Expand Up @@ -175,7 +175,8 @@ inline in two places so both lifecycle points behave identically:
| `busybox` | |||
| `cloudflared` ||||
| `dd-agent` | |||
| `dd-shell` | |||
| `dd-sessiond` ||||
| `dd-shell` ||||
| `human-readonly` | || |
| `dd-management` || | |
| `podman-static` | |||
Expand All @@ -185,29 +186,23 @@ inline in two places so both lifecycle points behave identically:
Additional examples:

- `apps/human-readonly`: tiny preview-only read-only oracle. It emits logs for
dd-shell's read-only terminal, serves `/oracle.json` on port 8082, gets a
vanity `oracle.<agent-hostname>` address, and appears in the dashboards. It
is a shell workload recipe, not a `devopsdefender` binary subcommand.
native clients, serves `/oracle.json` on port 8082, gets a vanity
`oracle.<agent-hostname>` address, and appears in the dashboards. It is a
shell workload recipe, not a `devopsdefender` binary subcommand.
- `apps/oracle-readonly`: standalone oracle example with the same scraper and
vanity-address metadata; copy this shape into real oracle app repos.
- `apps/confidential-shell`: runs dd-shell with
`DD_SHELL_DIR=/var/lib/easyenclave/data/dd-shell` so read-write PTY
transcript history survives on the workload disk.
- `apps/codex-podman-shell`: alternative read-write shell workload. It exposes
the normal `-shell` label, stores encrypted dd-shell history under
`/var/lib/easyenclave/data/dd-shell`, and advertises a Codex recipe in the
shell UI. The normal shell recipe remains available. Launching Codex starts a
Podman-backed Node container with per-session home, workspace, cache, and tmp
directories supplied by dd-shell. The container installs `@openai/codex` on
first use, so `codex login` can be completed interactively from the browser
terminal. Session scratch is intentionally ephemeral in this first slice; the
encrypted transcript remains under `DD_SHELL_DIR`. Use this instead of
`dd-shell`, not alongside it, unless you give one of them a different
`hostname_label`.

CP stays slim: just `cloudflared` + `dd-management`. Preview agent VMs run a
small read-only oracle plus agent + podman for CI to prove registration,
scraping, vanity ingress, and dashboards end-to-end. Prod agent VMs use the
- `apps/confidential-shell`: legacy standalone shell workload for deployments
that still run the browser shell and PTY supervisor in one process. Scheduled
for removal once all clients use `dd-sessiond` over Noise.
- `apps/codex-podman-shell`: legacy read-write shell workload. It exposes the
normal `-shell` label and carries an older self-contained Codex recipe path.
Scheduled for removal; new deployments should use `dd-sessiond`.

CP stays slim: `cloudflared` + `dd-management` + static/web client assets as
needed. It must not carry shell, log, transcript, or PTY bytes.
Preview agent VMs run a small read-only oracle plus agent + podman for CI to
prove registration, scraping, vanity ingress, and dashboards end-to-end. Prod
agent VMs use the
same CPU-only boot shape without demo workloads for now. `dd-local-dogfood`
uses that same prod boot chain but is manually managed, sized larger by
default, and not relaunched by CI.
Expand Down
3 changes: 3 additions & 0 deletions apps/_infra/local-cp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ build_config_iso() {
DD_OWNER_ID="$EE_OWNER_ID" \
DD_OWNER_KIND="$EE_OWNER_KIND" \
bake "$REPO_ROOT/apps/dd-management/workload.json.tmpl"
DD_SESSIOND_DIR=/tmp/dd-shell \
DD_SESSIOND_SCRATCH_DIR=/tmp/dd-shell/sessions \
bake "$REPO_ROOT/apps/dd-sessiond/workload.json.tmpl"
DD_DOMAIN="$DD_DOMAIN" \
DD_HOSTNAME="$HOSTNAME" \
DD_ENV="$ENV_LABEL" \
Expand Down
1 change: 1 addition & 0 deletions apps/dd-agent/workload.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"DD_CONFIDENTIAL=${DD_CONFIDENTIAL}",
"DD_PORT=8080",
"DD_EXTRA_INGRESS=${DD_EXTRA_INGRESS}",
"DD_AGENT_DEVICES_PATH=/var/lib/easyenclave/data/dd-agent/devices.json",
"DD_ORACLES_B64=${DD_ORACLES_B64}"
]
}
4 changes: 0 additions & 4 deletions apps/dd-shell/workload.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
"env": [
"DD_MODE=shell",
"DD_SHELL_PORT=7682",
"DD_SHELL_DIR=/tmp/dd-shell",
"DD_SHELL_EE_SOCKET=/var/lib/easyenclave/agent.sock",
"DD_SESSIOND_HTTP_URL=http://127.0.0.1:7683",
"DD_SESSIOND_ATTACH_ADDR=127.0.0.1:7684",
"DD_ENV=${DD_ENV}",
"DD_OWNER=${DD_OWNER}",
"DD_OWNER_ID=${DD_OWNER_ID}",
Expand Down
21 changes: 0 additions & 21 deletions assets/xterm/LICENSE

This file was deleted.

7 changes: 0 additions & 7 deletions assets/xterm/README.md

This file was deleted.

2 changes: 0 additions & 2 deletions assets/xterm/addon-fit.js

This file was deleted.

Loading
Loading