Commit Graph
6 Commits
Author SHA1 Message Date
Jeremy Ruppel 10717572ac feat: show template prerequisites in builder UI (#26523)
Surface base template prerequisites to admins before they create a
template in the Template Builder wizard.

Today, template prerequisites (Docker socket setup, Kubernetes auth, AWS
IAM policies) are only visible in the registry README after import.
Admins hit opaque provisioner errors and have to hunt for docs. This
change extracts the prerequisites from the README and serves them via
the API so the frontend can display them inline.

## How it works

Each base template README uses HTML comment markers (`<!--
prerequisites:start -->` / `<!-- prerequisites:end -->`) to delimit the
prerequisites section. At boot time, the base catalog loader reads the
README, extracts the content between markers via `strings.Index`, and
caches both the full README and the prerequisites string.

The prerequisites are served via a new `prerequisites` field on `GET
/api/v2/templatebuilder/bases`. The full README is included in the
composed template tar bundle and stored as the template version readme.

## Changes

- Add `README.md` with prerequisite markers to
`coderd/templatebuilder/bases/{docker,kubernetes,aws-linux}/`
- New `ExtractPrerequisites()` in `prerequisites.go` using literal
string matching
- `bases.go`: load README at boot, fail loudly if missing, extract
prerequisites
- `compose.go`: include README in `ComposeResult` and tar bundle
- `codersdk`: add `Prerequisites` field to `TemplateBuilderBase`
- Handler: populate prerequisites in bases response, set readme on
template version

<details>
<summary>Implementation notes</summary>

- Prerequisites extraction uses `strings.Index` for exact literal marker
matching; no regex or AST parser needed since we control the markers.
- YAML frontmatter is deliberately retained in the stored README. The
frontend `TemplateDocsPage` already strips it at render time via
`front-matter`.
- The prerequisite markers are HTML comments, invisible in rendered
markdown.
- The `RejectsMissingReadme` test enforces that every base template must
include a README.
- AWS Linux prerequisites span two H2 sections (`## Prerequisites` and
`## Required permissions / policy`), which is why heading-based parsing
was rejected in favor of explicit markers.

*Generated with the assistance of an AI coding agent. Reviewed by
@jeremyruppel.*
</details>

Relates to https://linear.app/codercom/issue/DEVEX-446
2026-06-23 11:36:07 -04:00
Jeremy Ruppel 87de6dc23e feat: add base template variables to API (#26425) 2026-06-17 12:22:35 -04:00
Jeremy Ruppel de31c7c18e feat: add TemplateBuilderCreateTemplate SDK types and client method (#26360)
Adds `POST /api/v2/templatebuilder/compose/template`, a synchronous
endpoint that composes a template from a base and modules, validates it
via a provisioner import job, and creates the template in a single
request.

The handler composes terraform files, bundles them as a tar, inserts the
file with hash-based dedup, creates a template version with an import
job, waits up to 2 minutes for the job to complete, classifies errors
for known failure modes (network-unreachable registry, DNS failures),
then creates the template on success. Canceled and failed jobs return
appropriate error responses.

Also adds `hclwrite.Format` to composed terraform output for canonical
HCL formatting.

Closes https://linear.app/codercom/issue/DEVEX-279

<details>
<summary>Implementation notes</summary>

- SDK types and client method in `codersdk/templatebuilder.go` with
validation tags matching the standard template creation path
(`template_display_name`, `lt=128`)
- `ClassifyProvisionerError` in `coderd/templatebuilder/errors.go`
detects DNS, connection refused, i/o timeout, and TLS handshake failures
and returns actionable messages
- `waitForProvisionerJob` polls with a ramp-up interval schedule (100ms,
200ms, 500ms, then 1s steady) and accepts an `onUpdate` callback for
future SSE streaming
- Audit logging for both template and template version creation
- TOCTOU name uniqueness: early check for fast feedback, DB unique
constraint catch for the race window (returns 409, not 500)
- Swagger annotations for all error responses (400, 404, 409, 504)

</details>

> 🤖 Generated by Coder Agents
2026-06-15 18:12:55 -04:00
Jeremy Ruppel b61b62f4b3 feat: add POST /api/v2/templatebuilder/compose endpoint (#26351)
> [!NOTE]
> This PR was authored by Coder Agents on behalf of @jeremyruppel.

Part 4 of DEVEX-277 (POST /api/v2/templatebuilder/compose).

Adds the HTTP handler, route wiring, and integration tests for the
compose endpoint.

The handler accepts a JSON request with a base template ID and optional
modules with variable overrides, renders them via `Compose`/`BundleTar`,
and returns the tar archive directly with `Content-Type:
application/x-tar`. The registry URL comes from the deployment config
(`CODER_TEMPLATE_BUILDER_REGISTRY_URL`).

RBAC uses `policy.ActionCreate` on
`rbac.ResourceTemplate.AnyOrganization()`.

Integration tests cover: base-only compose, base with modules, unknown
base/module errors, missing base template ID, and feature-disabled 404.
2026-06-15 11:07:16 -04:00
Jeremy Ruppel 9a6e348f5d feat: add GET /api/v2/templatebuilder/modules endpoint (#26117)
Implement `GET /api/v2/templatebuilder/modules`, which returns the
filtered list of modules available for a given base template. Reads from
the bundled catalog via `LoadModules()` and applies OS-compatibility
filtering based on the `base` query param.

Computed variables (e.g. `agent_id`) are excluded from the API response
at the `ToSDK()` conversion boundary since they are wired automatically
by the builder. The `Computed` field is removed from the SDK type. Adds
`CompatibleWithOS()` to `ModuleManifest` for OS filtering.

Returns 400 for unknown base IDs and 404 when the template builder is
disabled.

Depends on #26116

> [!NOTE]
> This PR was authored by Coder Agents on behalf of @jeremyruppel.
2026-06-12 17:53:48 -04:00
Jeremy Ruppel 776fbfa748 feat: add GET /api/v2/templatebuilder/bases endpoint (#26116)
Implement `GET /api/v2/templatebuilder/bases`, which returns the list of
base templates available in the template builder. Reads from the bundled
catalog by cross-referencing `templatebuilder.BaseTemplateIDs()` with
`examples.List()`, enriching each entry with the OS from the `exampleID
-> OS` map.

The endpoint is gated behind the template builder feature flag (returns
404 when disabled) and requires `policy.ActionRead` on
`rbac.ResourceTemplate`.

Depends on #26115

> [!NOTE]
> This PR was authored by Coder Agents on behalf of @jeremyruppel.
2026-06-12 17:40:02 -04:00