DID_GITEA detection and the SSH/GPG key uploads to Gitea were reading
tea's config.yml directly with awk, assuming 2-space indentation and a
plaintext `token:` field. Neither holds: the real format uses 6-space
indentation for fields under each login, and a login done via OAuth
(tea's default flow) has no token field in the file at all - it's held
elsewhere. Confirmed live: a workspace with a genuinely active `tea`
OAuth login was still reporting "not logged in" and skipping the whole
key-setup step because of this.
Replaced with tea's own subcommands, which handle auth internally
regardless of method:
- detection: `tea whoami`
- SSH key upload: `tea ssh-keys add`
- GPG key upload: `tea api -X POST /user/gpg_keys -F armored_public_key=@-`
Verified all three directly against the live account (disposable test
SSH + GPG keys, added then removed) - SSH upload succeeded; the GPG
upload correctly failed for an unrelated, expected reason (Gitea
requires the key's email to match a verified account email, and the
test key used a throwaway address), confirming the request itself is
well-formed.
The SSH/GPG key-generation question only fires when gh/tea are actually
logged in (DID_GITHUB/DID_GITEA), which is correct - but if login was
declined, failed, or never completed, the section was skipped with zero
explanation. From the user's side that looked like a missing feature
rather than an unfinished login.
Confirmed on a live workspace: gh was never installed, and tea was
installed but `tea login add` never actually completed (no
~/.config/tea/config.yml), so the gate correctly stayed closed - the
user just had no way to know why. Now prints a one-line hint (only when
gh or tea is installed at all) pointing at the login command and the
--force re-run.
Browse Lite (antfu.browse-lite, kept in the earlier Open VSX audit)
launches an embedded browser preview via a real Chrome/Chromium binary,
which templates/web's image never provided - it failed with "No Chrome
installation found, or no Chrome executable set in the settings".
Ubuntu's own chromium-browser apt package is a snap wrapper and doesn't
work in a container, so this installs Google Chrome's official .deb
instead (amd64 only, matching this repo's single x86_64 Docker host).
Also points browse-lite.chromeExecutable at it explicitly rather than
relying on auto-detection.
Verified the new apt-key/repo/install layer builds cleanly in isolation
on octo-winsrv (google-chrome-stable 152.0.7977.64).
- Every template's coder_agent startup script now unconditionally
installs git and gnupg as base packages (guarded on `command -v`, so
it's a fast no-op where already present, e.g. templates/web's baked
image). Not every base image ships gnupg by default.
- cli-setup-wizard.sh (all 6 templates) now tracks whether the user
actually ended up authenticated against GitHub and/or Gitea via the
existing gh/tea install-and-login prompts. If at least one succeeded,
it asks once more whether to auto-generate an SSH key (ed25519) and a
GPG signing key (ed25519, quick-gen) and register them with whichever
host(s) are in play - stays completely silent for "local git only"
(neither gh nor tea set up).
- GitHub: `gh ssh-key add` / `gh gpg-key add` (official gh CLI
subcommands).
- Gitea: direct calls against `/api/v1/user/keys` and
`/api/v1/user/gpg_keys`, reusing the token `tea login add` already
stored in tea's config.yml (parsed with a small awk extractor).
- Either upload failing (already added, API shape mismatch, etc.)
just prints the manual command/URL and moves on - never blocks the
rest of the wizard, consistent with every other step's style.
- git is configured to sign commits with the new key
(user.signingkey + commit.gpgsign) once a GPG key exists, whether
freshly generated or already present from a prior run.
README updated to document both additions.
code-server installs extensions from Open VSX by default (not the MS
Marketplace), and treats a single not-found extension as fatal to
startup - one bad ID in a profile takes the whole workspace down, as
seen live across two prior fixes for templates/web alone.
Checked every extension ID in all 6 templates against the Open VSX API
and dropped whichever 404'd:
- web: 91 -> 55 (mostly Pug/Tailwind-ecosystem extensions never
published to Open VSX, plus the 5 private octoturge.octoturge-*
devpacks, which can't resolve via any public registry)
- cobol: 27 -> 16 (rocketsoftware.rocket-cobol and Microsoft
IntelliCode/Remote-Containers, license-restricted to the MS
Marketplace, among others)
- python: 12 -> 8 (ms-python.vscode-pylance and the Remote-* family,
also MS-Marketplace-only by license)
- 3d-printing: 34 -> 24
- default and ttrpg: no changes needed, already clean
octoturge's private devpacks aren't republished anywhere here - if
wanted, they'd need a private/self-hosted Open VSX-compatible registry
or manual .vsix installation post-boot.
Blocked code-server startup entirely (extension install failure was
fatal, code-server never came up -> "connection was refused" on the
agent's proxy port). The id is also miscased in the profile (should be
89netraM, capital M) and the real extension is a Windows-only joke
("Hotheaded VS Code" - screams at you on errors), not something with
any use in a headless Linux code-server container, so dropping it
outright rather than fixing the casing.
The coder_agent's coder_script resources run as the unprivileged coder
user, which can't mkdir under root-owned /opt. Every template hit this
identically (mkdir: cannot create directory '/opt/coder': Permission
denied) since coder_script content is shared verbatim across all 6.
coder has passwordless sudo everywhere, so sudo mkdir + chown to the
running user unblocks the rest of each script's non-sudo writes.
- Drop `pip install --upgrade pip`: Debian-packaged pip 24.0 has no RECORD
file (dpkg-installed, not pip-installed), so self-upgrade fails trying
to uninstall in place. Unneeded - packages install fine under stock pip.
- Remove the pre-existing `ubuntu` user/group before `useradd --uid 1000
coder`: Ubuntu 24.04's base image already provisions a uid/gid 1000
`ubuntu` user, colliding with the explicit uid.
- Drop the now-pointless `pnpm setup || true` step: it was already
silently no-oping (EACCES trying to self-manage into PNPM_HOME as a
non-root user against a root-owned npm-global install) and standard
pnpm usage (install/run) works fine without it.
Verified via repeated rebuilds directly on the Coder host.
Removing the jetbrains module (previous commit) dropped the only thing in
these templates that used the hashicorp/http provider (the module fetched
IDE metadata via it internally). terraform init only installs providers the
current config declares, but any workspace whose state still has resources
from a template version that included the jetbrains module needs that
provider available to reconcile/destroy those entries - without it,
plan/apply fails with "Missing required provider ... hashicorp/http".
Re-declaring it in required_providers (all 6 templates) unblocks those
existing workspaces' next apply. Safe to remove again once every workspace
has updated past the jetbrains-module version.
- cli-setup-wizard.sh (identical across all 6 templates): add GitHub CLI
(gh, installed via the official apt repo) and Gitea CLI (tea, official
binary release to ~/.local/bin) as two more opt-in install-then-login
prompts, alongside the existing Copilot/Antigravity/Claude Code CLI
entries. Same pattern: skip if already installed, ask before installing,
attempt login, never hard-fail the wizard.
- main.tf (all 6 templates): remove the `module "jetbrains"` block - not
used, dropped per request.
- README.md: update the "Layout" blurb and CLI setup wizard tool list to
match.
templates/web (Coder's "Web Applications" profile) previously just pulled
codercom/enterprise-base:ubuntu and installed Bun at workspace start. Add a
Dockerfile that builds a complete dev image: build-essential/clang/llvm,
Tauri 2 / WebKit GUI prerequisites, Postgres/Redis/SQLite CLI clients,
protobuf-compiler, Python 3 + OpenCV/ONNX/CPU-torch, Node LTS + Bun/pnpm/
yarn, and a full Rust toolchain via rustup (rustfmt/clippy/rust-analyzer/
rust-src, musl+gnu x86_64/aarch64 targets, cargo-watch/cargo-edit/cross/
bacon) under a passwordless-sudo `coder` user.
main.tf now builds this Dockerfile via the docker provider's `docker_image`
resource (context = the template's own directory, tag keyed on the
Dockerfile's hash) instead of pulling the generic base image, and drops the
now-redundant standalone Bun-install coder_script since Bun ships baked into
the image and lands in the persistent home volume via Docker's normal
empty-volume-populated-from-image behavior. Also add rust-analyzer and Tauri
extensions to profile.code-profile, which was otherwise all web/Vue tooling
with nothing for the new Rust/Tauri side of the stack.
coder templates push -d templates/<env> only uploads that directory to the
Coder server, so main.tf's file() references reaching outside it via
../../profile-templates and ../../scripts failed at push/apply time
("Invalid function argument ... this function works only with files that
are distributed as part of the configuration source code"). Confirmed via
an actual failed run of coder-templates.yml once the runner network fix let
it get that far.
Fix: duplicate profile.code-profile, cli-setup-wizard.sh, and
install-skills.sh into each templates/<env>/ directory and drop the old
shared scripts/ and profile-templates/ directories.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds scripts/install-skills.sh: pulls this repo's extensions/ skill
bundles (SKILL.md-format) at workspace startup and installs them into
Claude Code (~/.claude/skills), GitHub Copilot CLI (~/.copilot/skills),
and Antigravity CLI (~/.gemini/config/skills). Every env gets the common
awesome-skills-plugin bundle; COBOL/3D/TTRPG additionally get their
matching skill(s) from custom-specialty-plugin via a per-template
SPECIALTY_SKILLS value.
Each template also installs Bun via a coder_script and hooks ~/.bun/bin
onto PATH in .bashrc (the bun.sh installer doesn't reliably do this in a
scripted shell). The CLI setup wizard now uses `bun install -g` instead
of `npm install -g` for GitHub Copilot CLI and Claude Code CLI.
All six templates re-validated with terraform init/validate against the
real coder-server container on octo-winsrv.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The old root main.tf tried to switch dev profiles inside one shared
container via a coder_parameter dropdown; the settings-application path
looked for a *.json cache file that never existed (the cache was written
as *.code-profile), so profile settings never actually applied, and VS
Code extensions were copied from extensions/ (which turns out to be
Claude Code plugin bundles, not real VS Code extension packages).
Replace it with one independent Coder template per environment
(templates/default, 3d-printing, cobol, python, ttrpg, web). Each reads
its matching profile-templates/*.code-profile file at template-push time
via file()/jsondecode(), feeds the extension ID list straight into the
code-server module's `extensions` input, and writes the raw settings.json
text via a coder_script - no runtime Gitea zip download needed anymore.
Also add scripts/cli-setup-wizard.sh, hooked into every new interactive
shell until completed, offering to install/log into GitHub Copilot CLI,
Google Antigravity CLI, and Claude Code CLI. VS Code extensions are
deliberately not asked about there since Terraform already handles them.
All six templates verified with `terraform init`/`validate` against the
real coder-server container on octo-winsrv.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>