8 Commits

Author SHA1 Message Date
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
8 changed files with 166 additions and 108 deletions
+101 -3
View File
@@ -13,6 +13,26 @@ name: Provision Coder Templates
# CODER_URL e.g. https://code.octoturge.com
# CODER_SESSION_TOKEN a token from `coder tokens create`, ideally under a
# dedicated service account rather than a personal one
#
# Pushing each Dockerfile-having template's image to this instance's
# container registry uses Gitea's own built-in secrets.GITEA_TOKEN (no
# manually-created PAT needed) - build-images grants it write access via
# `permissions: packages: write` below. See
# https://docs.gitea.com/usage/actions/token-permissions/
#
# Any templates/<env>/ that has its own Dockerfile gets its image built and
# pushed here (build-images, on the dedicated "docker-build" runner - see
# templates/web/main.tf for why: that runner is scoped to this repo only and
# has host Docker socket access that the shared runner-1 deliberately
# doesn't). provision then just pulls the tag build-images produced, instead
# of building it itself at `terraform apply` time - keeps a slow toolchain
# compile off of "someone is waiting to create a workspace".
#
# Each template's image is built independently - one Dockerfile failing to
# build doesn't stop the others from building, and provision skips pushing
# only the specific template(s) whose image build failed this run (leaving
# their previous, already-working Coder template version in place) rather
# than skipping every template or pushing one with no matching image.
on:
push:
@@ -23,11 +43,82 @@ on:
workflow_dispatch: {}
jobs:
build-images:
# The docker-build runner's docker_host: "" setting already auto-injects
# /var/run/docker.sock into job containers - an explicit
# container.volumes mount for the same path here fails at container
# creation with "Duplicate mount point: /var/run/docker.sock".
runs-on: docker-build
# The default token permission mode denies package write unless a job
# explicitly asks for it - without this, docker push fails with
# "unauthorized: reqPackageAccess".
permissions:
packages: write
outputs:
failed_templates: ${{ steps.build.outputs.failed_templates }}
# docker:27-cli (Alpine) has no bash - only the POSIX /bin/sh (busybox
# ash) - but run: steps default to bash, which fails with "exec: bash:
# executable file not found in $PATH". Both run: steps below are plain
# POSIX shell already, so just run them under sh.
defaults:
run:
shell: sh
steps:
# actions/checkout is a JS action and needs Node in the job container -
# this job runs in docker:27-cli (Alpine, just the Docker CLI) so it has
# no Node, and actions/checkout fails immediately with "exec: node:
# executable file not found in $PATH". Alpine does have apk/git though,
# so clone directly instead.
- name: Checkout
run: |
set -e
apk add --no-cache git
git clone --depth 1 --branch "${{ github.ref_name }}" "${{ github.server_url }}/${{ github.repository }}.git" .
- name: Build and push every template's image (skips a tag that's already in the registry)
id: build
run: |
set -e
echo "${{ secrets.GITEA_TOKEN }}" | docker login git.octoturge.com -u "${{ github.actor }}" --password-stdin
FAILED=""
for dockerfile in templates/*/Dockerfile; do
[ -e "$dockerfile" ] || continue
dir="$(dirname "$dockerfile")"
name="$(basename "$dir")"
TAG="$(sha1sum "$dockerfile" | cut -d' ' -f1)"
IMAGE="git.octoturge.com/octo-tech/profiles-${name}:${TAG}"
echo "::group::${name}"
if docker manifest inspect "$IMAGE" >/dev/null 2>&1; then
echo "$IMAGE already in the registry (Dockerfile unchanged), skipping build."
elif docker build -t "$IMAGE" "$dir" && docker push "$IMAGE"; then
echo "Built and pushed $IMAGE"
else
echo "::warning::Failed to build/push $IMAGE - templates/$name will be skipped this run."
FAILED="$FAILED $name"
fi
echo "::endgroup::"
done
echo "failed_templates=${FAILED# }" >> "$GITHUB_OUTPUT"
provision:
# needs: build-images orders this after the image builds (so a fresh
# template push never points at a tag that isn't in the registry yet)
# without making every template's reprovisioning depend on ALL builds
# succeeding - if:always() overrides the default "skip if a dependency
# failed" behavior, since build-images only fails outright on an
# infra-level problem (e.g. registry login); a single template's build
# failure is reported via failed_templates instead and only skips that
# one template below.
needs: build-images
if: always()
runs-on: ubuntu-latest
env:
CODER_URL: ${{ secrets.CODER_URL }}
CODER_SESSION_TOKEN: ${{ secrets.CODER_SESSION_TOKEN }}
FAILED_TEMPLATES: ${{ needs.build-images.outputs.failed_templates }}
steps:
- name: Checkout (full history, needed to detect removed templates)
uses: actions/checkout@v4
@@ -44,9 +135,16 @@ jobs:
run: |
set -e
for dir in templates/*/; do
name="profiles-$(basename "$dir")"
echo "::group::Pushing $name from $dir"
coder templates push "$name" -d "$dir" --yes \
name="$(basename "$dir")"
full="profiles-$name"
case " $FAILED_TEMPLATES " in
*" $name "*)
echo "::warning::Skipping $full - its Docker image failed to build this run (see build-images), leaving the previous template version in place."
continue
;;
esac
echo "::group::Pushing $full from $dir"
coder templates push "$full" -d "$dir" --yes \
-m "auto-provisioned from ${GITHUB_SHA:0:12}"
echo "::endgroup::"
done
+9 -16
View File
@@ -143,12 +143,11 @@ else
fi
fi
fi
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/tea/config.yml"
if command -v tea >/dev/null 2>&1 && [ -f "$TEA_CONFIG" ]; then
TEA_URL="$(awk '/^logins:/{f=1} f && /^ url:/{print $2; exit}' "$TEA_CONFIG")"
TEA_TOKEN="$(awk '/^logins:/{f=1} f && /^ token:/{print $2; exit}' "$TEA_CONFIG")"
[ -n "$TEA_URL" ] && [ -n "$TEA_TOKEN" ] && DID_GITEA=1
fi
# `tea whoami` succeeds regardless of how the login was done (personal
# access token or OAuth) - more reliable than parsing tea's own
# config.yml, whose indentation and fields (no plaintext `token:` at all
# for an OAuth login) vary by auth method.
command -v tea >/dev/null 2>&1 && tea whoami >/dev/null 2>&1 && DID_GITEA=1
# --- SSH + GPG keys for the external git host(s) selected above ---
# Only asks if the user actually set up GitHub and/or Gitea just now -
@@ -186,13 +185,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
SSH_PUB_JSON="$(sed 's/\\/\\\\/g; s/"/\\"/g' "${SSH_KEY}.pub")"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"title\":\"coder-$(hostname)\",\"key\":\"${SSH_PUB_JSON}\"}" >/dev/null 2>&1; then
if tea ssh-keys add "${SSH_KEY}.pub" --title "coder-$(hostname)" >/dev/null 2>&1; then
echo "SSH key added to Gitea."
else
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually with: tea ssh-keys add ${SSH_KEY}.pub"
fi
fi
@@ -226,13 +222,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
GPG_ARMORED_JSON="$(gpg --armor --export "$GPG_KEY_ID" | awk '{printf "%s\\n", $0}')"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/gpg_keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"armored_public_key\":\"${GPG_ARMORED_JSON}\"}" >/dev/null 2>&1; then
if gpg --armor --export "$GPG_KEY_ID" | tea api -X POST /user/gpg_keys -F armored_public_key=@- >/dev/null 2>&1; then
echo "GPG key added to Gitea."
else
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually: gpg --armor --export $GPG_KEY_ID | tea api -X POST /user/gpg_keys -F armored_public_key=@-"
fi
fi
fi
+9 -16
View File
@@ -143,12 +143,11 @@ else
fi
fi
fi
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/tea/config.yml"
if command -v tea >/dev/null 2>&1 && [ -f "$TEA_CONFIG" ]; then
TEA_URL="$(awk '/^logins:/{f=1} f && /^ url:/{print $2; exit}' "$TEA_CONFIG")"
TEA_TOKEN="$(awk '/^logins:/{f=1} f && /^ token:/{print $2; exit}' "$TEA_CONFIG")"
[ -n "$TEA_URL" ] && [ -n "$TEA_TOKEN" ] && DID_GITEA=1
fi
# `tea whoami` succeeds regardless of how the login was done (personal
# access token or OAuth) - more reliable than parsing tea's own
# config.yml, whose indentation and fields (no plaintext `token:` at all
# for an OAuth login) vary by auth method.
command -v tea >/dev/null 2>&1 && tea whoami >/dev/null 2>&1 && DID_GITEA=1
# --- SSH + GPG keys for the external git host(s) selected above ---
# Only asks if the user actually set up GitHub and/or Gitea just now -
@@ -186,13 +185,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
SSH_PUB_JSON="$(sed 's/\\/\\\\/g; s/"/\\"/g' "${SSH_KEY}.pub")"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"title\":\"coder-$(hostname)\",\"key\":\"${SSH_PUB_JSON}\"}" >/dev/null 2>&1; then
if tea ssh-keys add "${SSH_KEY}.pub" --title "coder-$(hostname)" >/dev/null 2>&1; then
echo "SSH key added to Gitea."
else
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually with: tea ssh-keys add ${SSH_KEY}.pub"
fi
fi
@@ -226,13 +222,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
GPG_ARMORED_JSON="$(gpg --armor --export "$GPG_KEY_ID" | awk '{printf "%s\\n", $0}')"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/gpg_keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"armored_public_key\":\"${GPG_ARMORED_JSON}\"}" >/dev/null 2>&1; then
if gpg --armor --export "$GPG_KEY_ID" | tea api -X POST /user/gpg_keys -F armored_public_key=@- >/dev/null 2>&1; then
echo "GPG key added to Gitea."
else
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually: gpg --armor --export $GPG_KEY_ID | tea api -X POST /user/gpg_keys -F armored_public_key=@-"
fi
fi
fi
+9 -16
View File
@@ -143,12 +143,11 @@ else
fi
fi
fi
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/tea/config.yml"
if command -v tea >/dev/null 2>&1 && [ -f "$TEA_CONFIG" ]; then
TEA_URL="$(awk '/^logins:/{f=1} f && /^ url:/{print $2; exit}' "$TEA_CONFIG")"
TEA_TOKEN="$(awk '/^logins:/{f=1} f && /^ token:/{print $2; exit}' "$TEA_CONFIG")"
[ -n "$TEA_URL" ] && [ -n "$TEA_TOKEN" ] && DID_GITEA=1
fi
# `tea whoami` succeeds regardless of how the login was done (personal
# access token or OAuth) - more reliable than parsing tea's own
# config.yml, whose indentation and fields (no plaintext `token:` at all
# for an OAuth login) vary by auth method.
command -v tea >/dev/null 2>&1 && tea whoami >/dev/null 2>&1 && DID_GITEA=1
# --- SSH + GPG keys for the external git host(s) selected above ---
# Only asks if the user actually set up GitHub and/or Gitea just now -
@@ -186,13 +185,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
SSH_PUB_JSON="$(sed 's/\\/\\\\/g; s/"/\\"/g' "${SSH_KEY}.pub")"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"title\":\"coder-$(hostname)\",\"key\":\"${SSH_PUB_JSON}\"}" >/dev/null 2>&1; then
if tea ssh-keys add "${SSH_KEY}.pub" --title "coder-$(hostname)" >/dev/null 2>&1; then
echo "SSH key added to Gitea."
else
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually with: tea ssh-keys add ${SSH_KEY}.pub"
fi
fi
@@ -226,13 +222,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
GPG_ARMORED_JSON="$(gpg --armor --export "$GPG_KEY_ID" | awk '{printf "%s\\n", $0}')"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/gpg_keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"armored_public_key\":\"${GPG_ARMORED_JSON}\"}" >/dev/null 2>&1; then
if gpg --armor --export "$GPG_KEY_ID" | tea api -X POST /user/gpg_keys -F armored_public_key=@- >/dev/null 2>&1; then
echo "GPG key added to Gitea."
else
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually: gpg --armor --export $GPG_KEY_ID | tea api -X POST /user/gpg_keys -F armored_public_key=@-"
fi
fi
fi
+9 -16
View File
@@ -143,12 +143,11 @@ else
fi
fi
fi
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/tea/config.yml"
if command -v tea >/dev/null 2>&1 && [ -f "$TEA_CONFIG" ]; then
TEA_URL="$(awk '/^logins:/{f=1} f && /^ url:/{print $2; exit}' "$TEA_CONFIG")"
TEA_TOKEN="$(awk '/^logins:/{f=1} f && /^ token:/{print $2; exit}' "$TEA_CONFIG")"
[ -n "$TEA_URL" ] && [ -n "$TEA_TOKEN" ] && DID_GITEA=1
fi
# `tea whoami` succeeds regardless of how the login was done (personal
# access token or OAuth) - more reliable than parsing tea's own
# config.yml, whose indentation and fields (no plaintext `token:` at all
# for an OAuth login) vary by auth method.
command -v tea >/dev/null 2>&1 && tea whoami >/dev/null 2>&1 && DID_GITEA=1
# --- SSH + GPG keys for the external git host(s) selected above ---
# Only asks if the user actually set up GitHub and/or Gitea just now -
@@ -186,13 +185,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
SSH_PUB_JSON="$(sed 's/\\/\\\\/g; s/"/\\"/g' "${SSH_KEY}.pub")"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"title\":\"coder-$(hostname)\",\"key\":\"${SSH_PUB_JSON}\"}" >/dev/null 2>&1; then
if tea ssh-keys add "${SSH_KEY}.pub" --title "coder-$(hostname)" >/dev/null 2>&1; then
echo "SSH key added to Gitea."
else
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually with: tea ssh-keys add ${SSH_KEY}.pub"
fi
fi
@@ -226,13 +222,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
GPG_ARMORED_JSON="$(gpg --armor --export "$GPG_KEY_ID" | awk '{printf "%s\\n", $0}')"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/gpg_keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"armored_public_key\":\"${GPG_ARMORED_JSON}\"}" >/dev/null 2>&1; then
if gpg --armor --export "$GPG_KEY_ID" | tea api -X POST /user/gpg_keys -F armored_public_key=@- >/dev/null 2>&1; then
echo "GPG key added to Gitea."
else
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually: gpg --armor --export $GPG_KEY_ID | tea api -X POST /user/gpg_keys -F armored_public_key=@-"
fi
fi
fi
+9 -16
View File
@@ -143,12 +143,11 @@ else
fi
fi
fi
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/tea/config.yml"
if command -v tea >/dev/null 2>&1 && [ -f "$TEA_CONFIG" ]; then
TEA_URL="$(awk '/^logins:/{f=1} f && /^ url:/{print $2; exit}' "$TEA_CONFIG")"
TEA_TOKEN="$(awk '/^logins:/{f=1} f && /^ token:/{print $2; exit}' "$TEA_CONFIG")"
[ -n "$TEA_URL" ] && [ -n "$TEA_TOKEN" ] && DID_GITEA=1
fi
# `tea whoami` succeeds regardless of how the login was done (personal
# access token or OAuth) - more reliable than parsing tea's own
# config.yml, whose indentation and fields (no plaintext `token:` at all
# for an OAuth login) vary by auth method.
command -v tea >/dev/null 2>&1 && tea whoami >/dev/null 2>&1 && DID_GITEA=1
# --- SSH + GPG keys for the external git host(s) selected above ---
# Only asks if the user actually set up GitHub and/or Gitea just now -
@@ -186,13 +185,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
SSH_PUB_JSON="$(sed 's/\\/\\\\/g; s/"/\\"/g' "${SSH_KEY}.pub")"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"title\":\"coder-$(hostname)\",\"key\":\"${SSH_PUB_JSON}\"}" >/dev/null 2>&1; then
if tea ssh-keys add "${SSH_KEY}.pub" --title "coder-$(hostname)" >/dev/null 2>&1; then
echo "SSH key added to Gitea."
else
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually with: tea ssh-keys add ${SSH_KEY}.pub"
fi
fi
@@ -226,13 +222,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
GPG_ARMORED_JSON="$(gpg --armor --export "$GPG_KEY_ID" | awk '{printf "%s\\n", $0}')"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/gpg_keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"armored_public_key\":\"${GPG_ARMORED_JSON}\"}" >/dev/null 2>&1; then
if gpg --armor --export "$GPG_KEY_ID" | tea api -X POST /user/gpg_keys -F armored_public_key=@- >/dev/null 2>&1; then
echo "GPG key added to Gitea."
else
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually: gpg --armor --export $GPG_KEY_ID | tea api -X POST /user/gpg_keys -F armored_public_key=@-"
fi
fi
fi
+9 -16
View File
@@ -143,12 +143,11 @@ else
fi
fi
fi
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/tea/config.yml"
if command -v tea >/dev/null 2>&1 && [ -f "$TEA_CONFIG" ]; then
TEA_URL="$(awk '/^logins:/{f=1} f && /^ url:/{print $2; exit}' "$TEA_CONFIG")"
TEA_TOKEN="$(awk '/^logins:/{f=1} f && /^ token:/{print $2; exit}' "$TEA_CONFIG")"
[ -n "$TEA_URL" ] && [ -n "$TEA_TOKEN" ] && DID_GITEA=1
fi
# `tea whoami` succeeds regardless of how the login was done (personal
# access token or OAuth) - more reliable than parsing tea's own
# config.yml, whose indentation and fields (no plaintext `token:` at all
# for an OAuth login) vary by auth method.
command -v tea >/dev/null 2>&1 && tea whoami >/dev/null 2>&1 && DID_GITEA=1
# --- SSH + GPG keys for the external git host(s) selected above ---
# Only asks if the user actually set up GitHub and/or Gitea just now -
@@ -186,13 +185,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
SSH_PUB_JSON="$(sed 's/\\/\\\\/g; s/"/\\"/g' "${SSH_KEY}.pub")"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"title\":\"coder-$(hostname)\",\"key\":\"${SSH_PUB_JSON}\"}" >/dev/null 2>&1; then
if tea ssh-keys add "${SSH_KEY}.pub" --title "coder-$(hostname)" >/dev/null 2>&1; then
echo "SSH key added to Gitea."
else
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the SSH key to Gitea automatically (may already be added). Add manually with: tea ssh-keys add ${SSH_KEY}.pub"
fi
fi
@@ -226,13 +222,10 @@ if [ "$DID_GITHUB" -eq 1 ] || [ "$DID_GITEA" -eq 1 ]; then
fi
if [ "$DID_GITEA" -eq 1 ]; then
GPG_ARMORED_JSON="$(gpg --armor --export "$GPG_KEY_ID" | awk '{printf "%s\\n", $0}')"
if curl -fsS -X POST "${TEA_URL%/}/api/v1/user/gpg_keys" \
-H "Authorization: token ${TEA_TOKEN}" -H "Content-Type: application/json" \
-d "{\"armored_public_key\":\"${GPG_ARMORED_JSON}\"}" >/dev/null 2>&1; then
if gpg --armor --export "$GPG_KEY_ID" | tea api -X POST /user/gpg_keys -F armored_public_key=@- >/dev/null 2>&1; then
echo "GPG key added to Gitea."
else
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually at: ${TEA_URL%/}/user/settings/keys"
echo "Couldn't add the GPG key to Gitea automatically (may already be added). Add manually: gpg --armor --export $GPG_KEY_ID | tea api -X POST /user/gpg_keys -F armored_public_key=@-"
fi
fi
fi
+11 -9
View File
@@ -193,16 +193,18 @@ resource "docker_volume" "home_volume" {
}
}
# Builds the full Web Applications toolchain (Rust/Tauri 2, Bun/Node/pnpm,
# Python CV/ONNX, DB clients - see ./Dockerfile) from this template's own
# directory, so no external registry push is required. The tag embeds the
# Dockerfile's hash so a Dockerfile edit forces a rebuild on next apply/push,
# while an unchanged Dockerfile reuses the cached image.
# Pulls the full Web Applications toolchain (Rust/Tauri 2, Bun/Node/pnpm,
# Python CV/ONNX, DB clients - see ./Dockerfile) instead of building it here.
# The image is built and pushed by .gitea/workflows/coder-templates.yml's
# build-web-image job, tagged with the same Dockerfile hash this resource
# computes - so a Dockerfile edit always resolves to the matching image, and
# an unchanged Dockerfile resolves to one already built (CI skips rebuilding
# it, and this pull is normally a same-host cache hit rather than a real
# network pull, since CI and this Coder deployment share one Docker daemon).
# Moves the ~15-20min Rust toolchain compile off of "someone is waiting to
# create a workspace" and onto CI, where it runs once per Dockerfile change.
resource "docker_image" "web" {
name = "coder-profiles-web:${filesha1("${path.module}/Dockerfile")}"
build {
context = path.module
}
name = "git.octoturge.com/octo-tech/profiles-web:${filesha1("${path.module}/Dockerfile")}"
keep_locally = true
}