Commit Graph

31 Commits

Author SHA1 Message Date
octoturge 268fb97a1c docs: note that GITEA_TOKEN impersonates the pushing account, not the owner
Provision Coder Templates / build-images (push) Failing after 6s
Provision Coder Templates / provision (push) Successful in 2m1s
Documents what we just found the hard way: build-images's docker push
runs as whichever Gitea account authenticated the triggering push
(github.actor), which needs its own package-registry write access -
separate from that account having git push rights to the repo at all.
2026-08-27 01:54:07 +02:00
octoturge 32c71ccaf0 ci: trigger fresh credential prompt after clearing stale akadmin cache 2026-08-27 01:45:58 +02:00
octoturge 9798b522bd ci: use Gitea's built-in GITEA_TOKEN for registry push, drop manual PAT
Provision Coder Templates / build-images (push) Failing after 6s
Provision Coder Templates / provision (push) Has been cancelled
GITEA_PACKAGE_TOKEN was never a creatable secret name (GITEA_ prefix is
reserved), and Gitea Actions' built-in token can be granted registry
write access directly via `permissions: packages: write` (per
https://docs.gitea.com/usage/actions/token-permissions/) - the
"unauthorized: reqPackageAccess" issue noted earlier looks to have been
exactly this: the default restricted token mode denying package write
unless a job explicitly requests it, not an unfixable bug in the token
itself. Drops the manual-PAT requirement entirely - no secret to create
or maintain.
2026-08-27 01:40:07 +02:00
octoturge f27eb23804 ci: rename registry secret to PACKAGE_REGISTRY_TOKEN, fail loudly if unset
GITEA_PACKAGE_TOKEN was never actually creatable - Gitea Actions reserves
the GITEA_ prefix for its own built-in secrets, so Settings > Actions >
Secrets rejects a repo secret by that name. The workflow referenced a
secret that could never exist, so docker login always got an empty
password and failed with a confusing "interactive login from a non TTY
device" error. Renamed to PACKAGE_REGISTRY_TOKEN, and added an explicit
empty-secret check so a future misconfiguration fails with a clear
message instead of that confusing docker error.
2026-08-27 01:37:19 +02:00
octoturge ea4ab76724 ci: run build-images' shell steps under sh, not bash
Provision Coder Templates / build-images (push) Failing after 10s
Provision Coder Templates / provision (push) Successful in 2m0s
docker:27-cli (Alpine) has no bash, only the POSIX /bin/sh (busybox
ash). run: steps default to bash, so both steps in build-images failed
immediately with "exec: bash: executable file not found in $PATH" -
confirmed via the run's log right after the previous checkout fix
landed. Both steps are already plain POSIX shell, so declare shell: sh
as the job default instead of switching interpreters.
2026-08-27 01:31:28 +02:00
octoturge c1bc3566ba ci: replace actions/checkout with a raw git clone in build-images
Provision Coder Templates / build-images (push) Failing after 7s
Provision Coder Templates / provision (push) Successful in 2m0s
actions/checkout is a JS action and needs Node to run inside the job
container. The docker-build runner's job image (docker:27-cli, Alpine,
just the Docker CLI) has no Node, so the step failed immediately with
"exec: node: executable file not found in $PATH" - confirmed via the
run's actual log (build-images failed after 16s on every push since the
image-in-CI switch, including the just-merged duplicate-mount and
if:always() fixes). Alpine has apk/git, so clone directly instead.
2026-08-27 01:26:03 +02:00
octoturge 9482a0a2a7 ci: build every template's image independently, skip only failed ones
Provision Coder Templates / provision (push) Successful in 2m5s
Provision Coder Templates / build-images (push) Failing after 16s
Fixes a regression where the whole provision job (all 6 templates) was
skipped whenever build-web-image failed, since Actions skips a job whose
needs: dependency failed by default. Generalizes the single web-image
build step into a loop over every templates/*/Dockerfile, building and
pushing each independently so one failure doesn't block the rest, and
reports failures via a job output. provision now runs unconditionally
(if: always()) and skips pushing only the specific template(s) whose
image build failed this run, leaving their previous working version in
place instead of pushing one with no matching registry tag.
2026-08-27 01:18:25 +02:00
octoturge 278023e4c2 ci: drop redundant docker.sock mount in build-web-image
First real run of the new job failed at container creation:
"Error response from daemon: Duplicate mount point: /var/run/docker.sock".
The docker-build runner's config.yaml has docker_host: "" (not "-"),
which means act_runner already auto-injects the host socket into job
containers on its own - the workflow's explicit
container.volumes mount for the same path was a second, conflicting
request for it. Just dropping the explicit mount; the runner already
provides it.
2026-08-27 01:12:35 +02:00
octoturge 6de3196faa web: build image in CI, pull it in Terraform instead of building locally
Provision Coder Templates / build-web-image (push) Failing after 17s
Provision Coder Templates / provision (push) Has been skipped
templates/web's docker_image resource used a `build` block, so every
first-use of a new Dockerfile hash triggered a from-scratch build
(including the ~15-20min Rust toolchain compile) right at `terraform
apply` time - i.e. while someone was waiting to create a workspace.

Adds a build-web-image job to coder-templates.yml that builds and pushes
git.octoturge.com/octo-tech/profiles-web:<dockerfile-sha1> to this
instance's container registry, tagged identically to what
docker_image.web now computes and pulls (no build block). provision now
depends on build-web-image so a template never gets pushed pointing at
an image that isn't there yet. Skips the build entirely if that tag's
already in the registry, so an unrelated templates/* change doesn't
pay any cost.

Runs on a new dedicated "docker-build" runner (profiles-web-build),
scoped to just this repo via a repo-level registration token, with
host Docker socket access - deliberately not added to the existing
shared runner-1, which has no such access and stays untouched. Repo is
public, so the pulled image needs no registry auth; the push does, via
a new GITEA_PACKAGE_TOKEN repo secret (write:package scope).

Since CI and this Coder deployment share the same Docker daemon, the
"pull" is normally a same-host cache hit, not a real network pull.

Verified: `terraform validate` passes against the updated
templates/web/main.tf (run directly inside the coder-server container,
which has terraform embedded).
2026-08-27 01:10:58 +02:00
octoturge 730af0a335 cli-setup-wizard: stop parsing tea's config.yml, use tea itself
Provision Coder Templates / provision (push) Successful in 2m4s
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.
2026-08-27 00:49:20 +02:00
octoturge d60e44508a cli-setup-wizard: explain why SSH/GPG key setup got skipped
Provision Coder Templates / provision (push) Successful in 2m7s
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.
2026-08-27 00:14:11 +02:00
octoturge 93721b9096 web: install Google Chrome for the Browse Lite extension
Provision Coder Templates / provision (push) Successful in 2m22s
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).
2026-08-26 23:57:51 +02:00
octoturge 013567f02a feat: base git/gnupg install + auto SSH/GPG key setup for external git
Provision Coder Templates / provision (push) Successful in 2m11s
- 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.
2026-08-26 23:16:25 +02:00
octoturge e8a8f93f9d fix: strip extension IDs unresolvable via Open VSX from all profiles
Provision Coder Templates / provision (push) Successful in 2m3s
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.
2026-08-26 20:29:49 +02:00
octoturge 557d6a3d84 fix(web): drop unresolvable 89netram.hotheaded-vscode extension
Provision Coder Templates / provision (push) Successful in 2m6s
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.
2026-08-26 18:51:01 +02:00
octoturge 354536dad5 fix: use sudo for /opt/coder setup in cli_setup_wizard and install_skills
Provision Coder Templates / provision (push) Successful in 2m5s
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.
2026-08-26 18:38:46 +02:00
octoturge 1be7c00b84 fix(web): resolve Docker build failures in templates/web
Provision Coder Templates / provision (push) Successful in 2m5s
- 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.
2026-08-26 16:22:39 +02:00
octoturge 52cc84650a Re-declare hashicorp/http provider to unblock existing workspace state
Provision Coder Templates / provision (push) Successful in 2m3s
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.
2026-08-26 15:47:25 +02:00
octoturge 0c53bb6554 Add gh/tea to the CLI wizard, drop the JetBrains module from all templates
Provision Coder Templates / provision (push) Successful in 2m7s
- 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.
2026-08-26 14:58:51 +02:00
octoturge a302e21609 Bake full-stack toolchain into the web template's Docker image
Provision Coder Templates / provision (push) Successful in 2m20s
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.
2026-08-26 13:48:10 +02:00
octoturge 60e63edd61 Fix bogus templates/ self-match in delete-detection step
Provision Coder Templates / provision (push) Successful in 2m10s
git ls-tree -d --name-only \$SHA -- templates matched the templates/
directory entry itself (basename "templates"), so every run tried and
harmlessly failed to delete a nonexistent profiles-templates template.
Use 'templates/*' as the pathspec to list only the child directories.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 16:55:56 +02:00
octoturge 22429aa4e3 Make each Coder template self-contained (fix coder templates push failure)
Provision Coder Templates / provision (push) Successful in 2m10s
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>
2026-08-23 16:52:12 +02:00
octoturge 5b32539d65 Rename GITEA_ROTATION_TOKEN secret to ROTATION_PAT (GITEA_ prefix is reserved) 2026-08-23 16:20:13 +02:00
octoturge 9424746305 Document API/direct-URL fallback for missing Gitea Secrets tab
Provision Coder Templates / provision (push) Failing after 1m16s
Some Gitea/Forgejo versions drop the Secrets nav link from Settings ->
Actions while Runners and Variables still show, even though the page
and API underneath still work. Document the direct-URL and curl-based
workarounds so the token-rotation/auto-provisioning bootstrap isn't
blocked by it.
2026-08-15 12:32:42 +02:00
octoturge a5a760b24a Add daily Coder token auto-rotation workflow
This Coder deployment caps API token lifetime at 168h (7 days), so
rather than raising that cap deployment-wide, add
.gitea/workflows/rotate-coder-token.yml: runs daily, mints a new 168h
coder token, PUTs it into this repo's CODER_SESSION_TOKEN secret via
Gitea's actions/secrets API (confirmed against the live instance's
swagger.v1.json - PUT /repos/{owner}/{repo}/actions/secrets/{name} with
{"data": "..."}), then deletes the token(s) it replaced. Old token isn't
touched until the new one is confirmed live, so a failed run fails safe.

Needs a one-time GITEA_ROTATION_TOKEN secret (a Gitea PAT with
write:repository scope, no expiration) so the workflow can write to its
own repo's secrets going forward - documented in README. After that,
CODER_SESSION_TOKEN (used by coder-templates.yml) never needs manual
attention again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 12:02:22 +02:00
octoturge a9583535f0 Add Gitea Actions workflow to auto-provision Coder templates
.gitea/workflows/coder-templates.yml pushes every templates/<env>/ dir
to Coder as profiles-<env> on every push to main that touches
templates/**, scripts/**, or profile-templates/** - coder templates push
creates the template on first run and updates it thereafter, so adding a
new templates/<env>/ directory is enough to provision it, no workflow
edits needed.

It also diffs templates/ against the previous commit and runs
`coder templates delete profiles-<env>` for any directory that was
removed. Deletion fails (loudly, as a job warning, not a hard failure)
rather than succeeding if the template still has active workspaces,
since coder templates delete already refuses that server-side.

Runs on the ubuntu-latest self-hosted Gitea runner already registered on
this instance (confirmed via gitea-runner-1's /data/.runner labels) and
installs the coder CLI itself. Needs CODER_URL and CODER_SESSION_TOKEN
as repo/org Actions secrets - documented in README, left for the user to
set up since token creation needs their own Coder login.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 11:49:56 +02:00
octoturge f6c432d21d Install Agent Skills into all 3 AI CLIs, and use Bun instead of npm
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>
2026-08-15 11:41:09 +02:00
octoturge 1beaac6e4f Split single-container Coder template into per-env templates
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>
2026-08-15 11:28:26 +02:00
octoturge a684401736 'v1.5' 2026-07-06 18:52:25 +02:00
octoturge fdbe811cdc 'v1' 2026-07-06 18:06:28 +02:00
octoturge 9d189020de Initial commit 2026-07-06 18:00:53 +02:00