Skip to content

Commit d5b5a47

Browse files
jplewWaishnav
andauthored
feat: download native ChatGPT files into workspaces (#88)
* feat: stage native ChatGPT artifacts privately * feat: materialize staged artifacts in workspaces * fix: accept regional ChatGPT artifact hosts * test: harden artifact workspace materialization * feat: materialize native artifacts in one call * refactor: use one-shot native artifact downloads * test: make artifact security fixtures umask-independent * feat: download artifacts to requested paths * docs: describe artifact destination handoff * refactor: stage artifacts beside destination * refactor: remove retired artifact migration * fix: preserve raced artifact destinations * refactor: remove retired artifact store shims * fix: gate artifact downloads by platform * fix: keep downloaded artifacts private * fix: address final artifact handoff review --------- Co-authored-by: Waishnav <waishnavdeore@gmail.com>
1 parent 80423b5 commit d5b5a47

15 files changed

Lines changed: 1955 additions & 6 deletions

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ DEVSPACE_LOG_SHELL_COMMANDS=0
2727
# DEVSPACE_TRUST_PROXY=1
2828
# DEVSPACE_STATE_DIR=/home/waishnav/.local/share/devspace
2929
# DEVSPACE_WORKTREE_ROOT=/home/waishnav/.devspace/worktrees
30+
# Native-file download is opt-in. Files stream to a model-selected relative
31+
# path inside an already-open workspace without overwriting existing files.
32+
# DEVSPACE_ARTIFACTS=1
33+
# DEVSPACE_ARTIFACT_MAX_FILE_BYTES=104857600
3034
# DEVSPACE_AUTO_LOAD_AGENTS_MD=1
3135
# Skills are enabled by default. Set DEVSPACE_SKILLS=0 to hide them.
3236
# DEVSPACE_SKILLS=0

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ devspace doctor
180180
- [Setup Guide](https://github.com/Waishnav/devspace/blob/main/docs/setup.md)
181181
- [ChatGPT Coding Workflow](https://github.com/Waishnav/devspace/blob/main/docs/chatgpt-coding-workflow.md)
182182
- [Configuration Reference](https://github.com/Waishnav/devspace/blob/main/docs/configuration.md)
183+
- [Native File Download](https://github.com/Waishnav/devspace/blob/main/docs/artifact-exchange.md)
183184
- [Security Model](https://github.com/Waishnav/devspace/blob/main/docs/security.md)
184185
- [Troubleshooting Gotchas](https://github.com/Waishnav/devspace/blob/main/docs/gotchas.md)
185186

docs/artifact-exchange.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Download a native file
2+
3+
DevSpace can save a file attached or generated by an MCP host, such as ChatGPT,
4+
directly into an open workspace. Enable the tool with `DEVSPACE_ARTIFACTS=1`.
5+
6+
## Workflow
7+
8+
```text
9+
open_workspace
10+
-> download_artifact({ file, workspaceId, path })
11+
-> { path }
12+
```
13+
14+
1. Open the project with `open_workspace`.
15+
2. Pass the host-provided native `file`, the returned `workspaceId`, and an
16+
unused workspace-relative `path` to `download_artifact`.
17+
3. Use the returned path with the ordinary DevSpace filesystem tools.
18+
19+
```text
20+
download_artifact({
21+
file: <native file value supplied by the MCP host>,
22+
workspaceId: "ws_123",
23+
path: "public/images/generated-image.png"
24+
})
25+
```
26+
27+
DevSpace creates missing parent directories and refuses to overwrite an existing
28+
file. After the download, normal tools can inspect, move, rename, replace, or
29+
delete it.
30+
31+
## Safety and limits
32+
33+
The `file` input must be the native value supplied by the MCP host. DevSpace does
34+
not accept pasted download URLs or local source paths. It validates the complete
35+
file-object shape, trusted OpenAI download hosts, and redirects before streaming.
36+
Malformed references, unknown fields, absolute paths, traversal, and symlinked
37+
parents are rejected.
38+
39+
Downloads are streamed under `DEVSPACE_ARTIFACT_MAX_FILE_BYTES` and published as
40+
owner-only files without overwriting an existing destination. The tool is
41+
available on Linux, macOS, FreeBSD, OpenBSD, and NetBSD; it is not registered on
42+
Windows.

docs/configuration.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,38 @@ npx @waishnav/devspace config set publicBaseUrl https://devspace.example.com
3939
| `DEVSPACE_WORKTREE_ROOT` | Directory for managed Git worktrees. Defaults to `~/.devspace/worktrees`. |
4040
| `DEVSPACE_STATE_DIR` | Directory for SQLite state. Defaults to `~/.local/share/devspace`. |
4141

42+
## Native Artifact Download
43+
44+
Native-file download is disabled by default. Enable it when ChatGPT needs to hand
45+
an attached or generated file into an already-open workspace:
46+
47+
```bash
48+
DEVSPACE_ARTIFACTS=1 npx @waishnav/devspace serve
49+
```
50+
51+
This feature currently supports Linux, macOS, FreeBSD, OpenBSD, and NetBSD. It
52+
is not registered on Windows because the secure publication path depends on
53+
descriptor-anchored directory operations.
54+
55+
| Variable | Default | Purpose |
56+
| --- | --- | --- |
57+
| `DEVSPACE_ARTIFACTS` | `0` | Expose `download_artifact` for trusted native files. |
58+
| `DEVSPACE_ARTIFACT_MAX_FILE_BYTES` | `104857600` | Maximum streamed size of one file (100 MiB). |
59+
60+
The same settings may be persisted in `~/.devspace/config.json` as
61+
`artifactsEnabled` and `artifactMaxFileBytes`.
62+
63+
`download_artifact` accepts the native file object supplied by the MCP connector,
64+
a `workspaceId` returned by `open_workspace`, and a relative workspace `path`.
65+
DevSpace safely creates missing parent directories, refuses to overwrite an
66+
existing destination, and returns only the normalized workspace-relative path.
67+
It does not accept conflict modes, expected hashes, arbitrary URL strings, local
68+
paths, embedded credentials, or extra object fields.
69+
70+
There is no artifact root, total quota, TTL, pinning, persistent database record,
71+
or background artifact cleanup service. See [Native File Download](artifact-exchange.md)
72+
for the supported connector shape and security boundaries.
73+
4274
## OAuth
4375

4476
DevSpace uses a single-user OAuth approval flow.
@@ -158,6 +190,7 @@ DEVSPACE_OAUTH_OWNER_TOKEN="$(openssl rand -base64 32)" \
158190
DEVSPACE_ALLOWED_ROOTS="$HOME/personal,$HOME/work" \
159191
DEVSPACE_PUBLIC_BASE_URL="https://devspace.example.com" \
160192
DEVSPACE_WORKTREE_ROOT="$HOME/.devspace/worktrees" \
193+
DEVSPACE_ARTIFACTS="1" \
161194
DEVSPACE_TOOL_MODE="minimal" \
162195
DEVSPACE_WIDGETS="full" \
163196
npx @waishnav/devspace serve

docs/security.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,33 @@ Managed worktrees reduce accidental edits to your active checkout, but they are
9292
not a security boundary. They are a workflow boundary for isolated coding
9393
sessions.
9494

95+
## Native File Download
96+
97+
Native file download is an opt-in, one-shot transfer into an already-open
98+
workspace. `download_artifact` accepts the MCP host's native file value, the
99+
`workspaceId` returned by `open_workspace`, and an unused relative destination
100+
path. It returns only the workspace-relative path and does not create a
101+
persistent artifact service or reusable artifact ID.
102+
103+
DevSpace accepts only the documented native-file object and trusted OpenAI
104+
download hosts and redirects. Arbitrary URL strings, local source paths,
105+
credentials, malformed references, and unknown object fields are rejected.
106+
107+
Absolute paths, traversal, symlinked parents, and existing destinations also
108+
fail closed. Downloads stream under the configured per-file limit and are
109+
published without overwrite as owner-only files. DevSpace does not extract or
110+
execute transferred content.
111+
95112
## Logs
96113

97114
By default, DevSpace logs requests and tool calls. Shell command previews are
98115
disabled unless `DEVSPACE_LOG_SHELL_COMMANDS=1`.
99116

100117
Do not enable shell command logging if commands may contain secrets.
118+
119+
Artifact tool logs contain bounded workspace ID, validated hostname,
120+
workspace-relative output path, byte count, hash, duration, and status metadata.
121+
`download_artifact` does not log the opaque file value. Raw content, connector
122+
references, native file IDs, bearer credentials, presigned URLs, host paths,
123+
temporary paths, and base64 chunks are never included in tool logs or tool
124+
results.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"dev": "node scripts/dev-server.mjs",
2929
"postinstall": "node scripts/fix-node-pty-permissions.mjs",
3030
"start": "node dist/cli.js serve",
31-
"test": "tsx src/config.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/local-agent-runtime.test.ts && tsx src/local-agent-adapters.test.ts && tsx src/local-agent-availability.test.ts && tsx src/local-agent-profiles.test.ts && tsx src/local-agent-targets.test.ts && tsx src/local-agent-store.test.ts && tsx src/roots.test.ts && tsx src/skills.test.ts && tsx src/workspaces.test.ts && tsx src/review-checkpoints.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts",
31+
"test": "tsx src/config.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/local-agent-runtime.test.ts && tsx src/local-agent-adapters.test.ts && tsx src/local-agent-availability.test.ts && tsx src/local-agent-profiles.test.ts && tsx src/local-agent-targets.test.ts && tsx src/local-agent-store.test.ts && tsx src/roots.test.ts && tsx src/skills.test.ts && tsx src/workspaces.test.ts && tsx src/review-checkpoints.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts",
3232
"typecheck": "tsc -p tsconfig.json --noEmit"
3333
},
3434
"keywords": [],

0 commit comments

Comments
 (0)