dev_container: Handle devcontainer.metadata label as JSON object or array (#53557)
Sandro Meier
created
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Details
- The [devcontainer CLI writes the `devcontainer.metadata` label as a
bare JSON object](https://github.com/devcontainers/cli/issues/1054) when
there is only one metadata entry (e.g. docker-compose devcontainer with
a Dockerfile and no features)
- Zed's `deserialize_metadata` only accepted a JSON array, causing
deserialization to fail with `invalid type: map, expected a sequence`
- This made it impossible to attach to existing docker-compose
devcontainers created by the devcontainer CLI or VS Code
The fix tries parsing as an array first, then falls back to parsing as a
single object wrapped in a vec. This mirrors how the [devcontainer CLI
itself reads the
label](https://github.com/devcontainers/cli/blob/main/src/spec-node/imageMetadata.ts#L476-L493).
An upstream fix has also been submitted:
https://github.com/devcontainers/cli/pull/1199
## Reproduction
1. Create a docker-compose devcontainer with a Dockerfile and no
features:
`.devcontainer/devcontainer.json`:
```json
{
"name": "repro",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"remoteUser": "root"
}
```
`.devcontainer/docker-compose.yml`:
```yaml
services:
app:
build:
context: .
dockerfile: Dockerfile
command: sleep infinity
volumes:
- ..:/workspace
```
`.devcontainer/Dockerfile`:
```dockerfile
FROM ubuntu:24.04
```
2. `devcontainer up --workspace-folder .`
3. Open the folder in Zed, fails with metadata deserialization error
Release Notes:
- Fixed attaching to a devcontainer that has a single metadata element
which was started with `devcontainer-cli`