devcontainer-builder (0.1.0)

Download OpenAPI specification:

Builds a container image from a git repository's .devcontainer.json using a remote BuildKit builder, and pushes it to a registry.

No authentication of its own - the service is meant to sit behind cluster-internal networking (see the Helm chart's Service). Every response is application/json except GET /metrics (text/plain). Any other method/path returns 404 {"error":"not found"}.

Dev Containers

Turn a git repository into a real, pushed image.

`400` always means the *request itself* was unusab

400 always means the request itself was unusable - nothing was ever attempted, or a required piece of configuration to even attempt it (a registry, a host key pin) was missing:

  • {"error": "invalid JSON body"} - the request body isn't valid JSON at all.
  • {"error": "missing or invalid fields: repository (required); branch, image.{registry,name,tag}, gitCredentials.{username,token}, registryCredentials.{registry,username,password}, platforms, buildOptions.{noCache,cacheFrom,cacheTo,mode} (all optional)"} - the parsed body isn't a JSON object, or fails the shape check.
  • {"error": "unable to parse git repository URL: <repository>"} - repository doesn't match any accepted URL form.
  • {"error": "repository URL scheme \"<scheme>://\" is not allowed: ..."} - repository uses a scheme other than https:///ssh:///SCP-style (git:///http:// need the server's allowInsecureGitProtocols).
  • {"error": "repository URL must not contain credentials (user:token@...) - pass them in gitCredentials instead"}.
  • {"error": "buildOptions.cacheTo: cache type \"<type>\" is not allowed (allowed: registry, gha, inline)"} - likewise for cacheFrom.
  • {"error": "unable to derive an image name from repository path ...: provide image.name"}.
  • {"error": "no registry resolved for repository <repository>: provide image.registry or configure a matching registry mapping rule"} - no image.registry given and no registry mapping rule matched.
  • {"error": "SSH host key policy is \"pinned\" but no pinned key configured for host <host>"} - the resolved SSH credential has no pinnedHostKey under sshHostKeyPolicy: pinned.

429 means the instance is already running build.maxConcurrent builds; retry after Retry-After seconds.

500 always means a real external command was actually run and failed - the request was well-formed, but cloning or building it didn't work: {"error": "<command> <args...> exited with code <n>", "logId": "<id>"}. The body is the real command and exit code, not the real error text (a registry's real 401 body, git's real "Permission denied") - fetch that via GET /logs/{logId} (also returned on success, as gitCloneLogId/imageBuildLogId).

Request Body schema: application/json
required

image/gitCredentials/registryCredentials/buildOptions may each be omitted entirely; once present, their own required sub-fields apply. Unknown top-level fields are tolerated, not rejected.

repository
required
string non-empty

https://, ssh://, or git's own SCP-style [user@]host:path shorthand. Any other scheme is rejected with 400 (git:// and http:// only when the server enables allowInsecureGitProtocols), and so are credentials in the URL (https://user:token@...) - use gitCredentials.

null or string

Branch (or tag) to build. Omitted or null: the repository's default branch. Non-empty if given.

null or object
object

Per-request git credentials for the clone. Both fields required together.

object

Per-request registry push credentials. All three fields required together. Omit entirely to rely on the server's own ambient registryAuth for the target registry instead.

platforms
Array of strings[ items non-empty ^[a-z0-9]+/[a-z0-9_]+(?:/[a-z0-9]+)?$ ]

Overrides the chart's build.platforms for this request, e.g. ["linux/amd64", "linux/arm64"]. Omitted or empty means today's behavior (no --platform flag).

object
property name*
additional property
any

Responses

Request samples

Content type
application/json
Example
{}

Response samples

Content type
application/json
{
  • "image": "string",
  • "registry": "string",
  • "name": "string",
  • "tag": "string",
  • "branch": "string",
  • "commit": "string",
  • "gitCloneLogId": "string",
  • "imageBuildLogId": "string"
}

Images

Check or best-effort delete a previously-built image.

Checks whether a previously-built image still exis

Checks whether a previously-built image still exists in its registry, by talking to the registry's own HTTP API V2 directly (bearer-token challenge/exchange, then a manifest lookup).

query Parameters
registry
required
string non-empty

Non-empty.

name
required
string non-empty

Non-empty.

tag
required
string non-empty

Non-empty.

header Parameters
x-registry-username
string

Together with X-Registry-Password, explicit credentials for this call. Falls back to the service's ambient DOCKER_CONFIG auth for registry when omitted.

x-registry-password
string

See X-Registry-Username.

Responses

Response samples

Content type
application/json
{
  • "image": "string",
  • "exists": true
}

Best-effort deletion of a previously-built image's

Best-effort deletion of a previously-built image's manifest. Not all registries support this via the standard API (Docker Hub notably doesn't) - see 0008 for why that's treated as a normal outcome, not an error.

query Parameters
registry
required
string non-empty

Non-empty.

name
required
string non-empty

Non-empty.

tag
required
string non-empty

Non-empty.

header Parameters
x-registry-username
string

Together with X-Registry-Password, explicit credentials for this call. Falls back to the service's ambient DOCKER_CONFIG auth for registry when omitted.

x-registry-password
string

See X-Registry-Username.

Responses

Response samples

Content type
application/json
{
  • "image": "string",
  • "deleted": true,
  • "reason": "string"
}

Dev Container metadata

Read a built image's merged Dev Container configuration (lifecycle commands, VS Code customizations, ...) from its registry.

Reads a built image's `devcontainer.metadata` labe

Reads a built image's devcontainer.metadata label straight from its registry (no pull, no Docker daemon) and returns it merged the way the Dev Containers CLI merges it, plus ready-to-run lifecycle scripts and merged VS Code customizations - what a Coder template needs to run postCreateCommand & co. and pre-install extensions. Pass registry/name/tag exactly as POST /build returned them. See 0011.

query Parameters
registry
required
string non-empty

Non-empty. As POST /build returns it - a namespaced registry (ghcr.io/deepspacecartel) is fine.

name
required
string non-empty

Non-empty.

tag
required
string non-empty

Non-empty.

platform
string^[^/]+/[^/]+(/[^/]+)?$

os/arch[/variant] to read from a multi-platform image. Defaults to linux/amd64; ignored for a single-platform image.

header Parameters
x-registry-username
string

Together with X-Registry-Password, explicit credentials for this call. Falls back to the service's ambient DOCKER_CONFIG auth for registry when omitted.

x-registry-password
string

See X-Registry-Username.

Responses

Response samples

Content type
application/json
{
  • "image": "ghcr.io/deepspacecartel/devcontainer-builder-examples:sha-a1b2c3d",
  • "digest": "sha256:3f1c…",
  • "configuration": {
    },
  • "lifecycleScripts": {
    },
  • "vscode": {
    },
  • "warnings": [ ],
  • "metadata": [
    ]
}

Health

Kubernetes-style startup/liveness/readiness probes.

Kubernetes `startupProbe`. Always `200 {"status":"

Kubernetes startupProbe. Always 200 {"status":"started"} once the process is listening - checks nothing beyond that. A distinct route from GET /health/live even though the check is identical today (this service has no separate async startup phase), so a startupProbe (a generous total budget, to tolerate slow pod scheduling/image pulls) can be tuned independently of livenessProbe (tight, once actually started).

Responses

Response samples

Content type
application/json
{
  • "status": "started"
}

Liveness probe. Always `200 {"status":"ok"}` once

Liveness probe. Always 200 {"status":"ok"} once the process is listening - checks nothing beyond that.

Responses

Response samples

Content type
application/json
{
  • "status": "ok"
}

Readiness probe. `200` when `BUILDKIT_ENDPOINT` is

Readiness probe. 200 when BUILDKIT_ENDPOINT is configured, 503 when it isn't.

Responses

Response samples

Content type
application/json
{
  • "status": "ready",
  • "reason": "string"
}

Prometheus text-format metrics (`Content-Type: tex

Prometheus text-format metrics (Content-Type: text/plain), for a ServiceMonitor/node-exporter-style scrape. Node.js process/runtime defaults (prom-client's collectDefaultMetrics) plus:

  • devcontainer_builder_builds_total (counter, label status: success|failure|invalid_request|busy) - every POST /build attempt.
  • devcontainer_builder_build_duration_seconds (histogram, label status) - real build wall-clock time, bucketed toward minutes (not the sub-second defaults), since a build is a clone + image build + push.
  • devcontainer_builder_image_checks_total (counter, label result: exists|absent|error) - every GET /image call.
  • devcontainer_builder_image_deletes_total (counter, label result: deleted|unsupported|error) - every DELETE /image call.
  • devcontainer_builder_devcontainer_lookups_total (counter, label result: found|absent|no_metadata|error) - every GET /devcontainer call.

Responses

Configuration

Non-sensitive view of the service's own loaded configuration.

/config

Responses

Response samples

Content type
application/json
{
  • "buildkitConfigured": true,
  • "buildxBuilderName": "devcontainer-builder-remote",
  • "sshHostKeyPolicy": "tofu",
  • "defaultPlatforms": [ ],
  • "defaultBuildOptions": {
    },
  • "gitCredentials": [
    ],
  • "registryMappingRules": [
    ],
  • "insecureRegistries": [ ],
  • "allowInsecureGitProtocols": false,
  • "cloneTimeoutSeconds": 600,
  • "buildTimeoutSeconds": 3600,
  • "maxConcurrentBuilds": 4,
  • "registryAuth": [
    ]
}

Logs

Captured git clone / devcontainer build --push output, keyed by the id POST /build returns.

Full captured stdout+stderr of one `git clone` or

Full captured stdout+stderr of one git clone or one devcontainer build --push (including remote builder setup) - the id comes from POST /build's response (gitCloneLogId/imageBuildLogId on success, logId on a 500).

Not persisted beyond this pod's own lifetime (backed by the same ephemeral scratch space as an in-progress build, not a volume) and rotated: only the most recent commandLogRetention (default 10) files are kept per kind (git/docker) - an id from an old build may already be gone.

path Parameters
id
required
string^(git|docker)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f...

A log id returned by POST /build (gitCloneLogId/imageBuildLogId, or logId on a failure response).

Responses

Response samples

Content type
application/json
{
  • "error": "string",
  • "logId": "string"
}

Deletes one captured command-output log ahead of i

Deletes one captured command-output log ahead of its normal rotation. Idempotent - deleting an already-gone id also 404s.

path Parameters
id
required
string^(git|docker)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f...

A log id returned by POST /build (gitCloneLogId/imageBuildLogId, or logId on a failure response).

Responses

Response samples

Content type
application/json
{
  • "error": "string",
  • "logId": "string"
}