Image building steps
This commit is contained in:
@@ -10,6 +10,7 @@ manual-fallback recipes, and host prerequisites: [docs/automation.md](../docs/au
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| [`workflows/deploy-stack.yml`](workflows/deploy-stack.yml) | `git pull` + (optional) SOPS decrypt + per-host compose resolution + `docker compose up -d`. Replaces the old per-repo `deploy.sh`. |
|
||||
| [`workflows/build-image.yml`](workflows/build-image.yml) | Build + push a Docker image from a source repo to the Gitea container registry. Tags `latest` + UTC timestamp (`YYYY-MM-DDTHHMMSSZ`). Called from `amacocian/<name>` repos. |
|
||||
|
||||
### Composite actions
|
||||
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
name: Build image
|
||||
|
||||
# Reusable workflow. Builds a Docker image from the caller repo and pushes
|
||||
# it to the Gitea container registry at `gitea.alexandru.macocian.me`.
|
||||
#
|
||||
# Companion to `deploy-stack.yml`: the source repos (`amacocian/<name>`)
|
||||
# produce images here; the deployment repos (`Charlie/<stack>`) consume
|
||||
# them via the `image:` field in their compose files and call
|
||||
# `deploy-stack.yml` to roll out.
|
||||
#
|
||||
# Caller pattern (from a source repo, e.g. amacocian/newsletter2atom):
|
||||
#
|
||||
# on:
|
||||
# push:
|
||||
# branches: [main]
|
||||
# workflow_dispatch:
|
||||
# jobs:
|
||||
# build:
|
||||
# uses: https://sys-gitea-runner:${{ secrets.RUNNER_REPO_PAT }}@gitea.alexandru.macocian.me/Charlie/project-charlie/.gitea/workflows/build-image.yml@main
|
||||
# secrets: inherit
|
||||
#
|
||||
# Tags pushed on every successful build:
|
||||
# - `latest`
|
||||
# - `YYYY-MM-DDTHHMMSSZ` (UTC build timestamp, immutable)
|
||||
#
|
||||
# Optional extra tags (e.g. semver, branch name, short SHA) can be supplied
|
||||
# via the `extra-tags` input — one per line. Empty lines / `#` comments
|
||||
# are ignored.
|
||||
#
|
||||
# Required caller secrets — both `sys-gitea-runner` PATs. Set once at the
|
||||
# owning user/org level (Settings → Actions → Secrets) so every source
|
||||
# repo under that namespace inherits them via `secrets: inherit`:
|
||||
#
|
||||
# RUNNER_REPO_PAT `read:repository` -- fetch this workflow file
|
||||
# + clone the caller source
|
||||
# RUNNER_REGISTRY_PAT `write:package` -- docker login + push to the
|
||||
# Gitea container registry
|
||||
#
|
||||
# Kept as two distinct PATs so the high-privilege package-write token is
|
||||
# never used for git over HTTPS (and vice versa).
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
image:
|
||||
description: |
|
||||
Fully-qualified image name without tag, e.g.
|
||||
`gitea.alexandru.macocian.me/amacocian/newsletter2atom`.
|
||||
Defaults to `gitea.alexandru.macocian.me/${{ github.repository }}`
|
||||
(lowercased), which matches the convention where the caller repo
|
||||
is the image's home.
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
context:
|
||||
description: Docker build context. Relative to the caller repo root.
|
||||
required: false
|
||||
type: string
|
||||
default: "."
|
||||
dockerfile:
|
||||
description: Path to the Dockerfile, relative to `context`.
|
||||
required: false
|
||||
type: string
|
||||
default: "Dockerfile"
|
||||
build-args:
|
||||
description: |
|
||||
Multi-line `KEY=VALUE` list passed as `--build-arg`. Empty lines
|
||||
and `#` comments are ignored. Values containing `=` are preserved
|
||||
as-is after the first `=`.
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
extra-tags:
|
||||
description: |
|
||||
Additional tags (one per line) to push alongside `latest` and
|
||||
the UTC timestamp. Whitespace-trimmed; empty lines and `#`
|
||||
comments ignored. The image reference itself is NOT included —
|
||||
just the tag portion (e.g. `v1.2.3`, `main`, `pr-42`).
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
push:
|
||||
description: |
|
||||
Push the built image to the registry. Set to `false` for
|
||||
build-only smoke tests (e.g. PR validation).
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
ref:
|
||||
description: Git ref to check out in the caller repo. Defaults to the triggering ref.
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
secrets:
|
||||
RUNNER_REPO_PAT:
|
||||
description: |
|
||||
`sys-gitea-runner` PAT with `read:repository`. Used in the
|
||||
absolute-URL `uses:` form to fetch this workflow file and to
|
||||
clone the caller's source inside the job. Same name and
|
||||
contract as the secret consumed by `deploy-stack.yml`.
|
||||
required: true
|
||||
RUNNER_REGISTRY_PAT:
|
||||
description: |
|
||||
`sys-gitea-runner` PAT with `write:package`. Used by
|
||||
`docker login` against `gitea.alexandru.macocian.me`. Kept
|
||||
separate from `RUNNER_REPO_PAT` so the package-write PAT is
|
||||
never exposed during git clone (and vice versa).
|
||||
required: true
|
||||
outputs:
|
||||
image:
|
||||
description: Full image reference without tag (e.g. `gitea.../amacocian/foo`).
|
||||
value: ${{ jobs.build.outputs.image }}
|
||||
timestamp-tag:
|
||||
description: The UTC timestamp tag pushed for this build.
|
||||
value: ${{ jobs.build.outputs.timestamp-tag }}
|
||||
digest:
|
||||
description: The image digest reported by `docker push` (sha256:...).
|
||||
value: ${{ jobs.build.outputs.digest }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: self-hosted
|
||||
outputs:
|
||||
image: ${{ steps.resolve.outputs.image }}
|
||||
timestamp-tag: ${{ steps.resolve.outputs.timestamp-tag }}
|
||||
digest: ${{ steps.push.outputs.digest }}
|
||||
steps:
|
||||
- name: Resolve image, ref, and timestamp
|
||||
id: resolve
|
||||
shell: bash
|
||||
env:
|
||||
IMAGE_INPUT: ${{ inputs.image }}
|
||||
REF_INPUT: ${{ inputs.ref }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
image="$IMAGE_INPUT"
|
||||
if [ -z "$image" ]; then
|
||||
# github.repository on Gitea is `<owner>/<repo>`; lowercase to
|
||||
# satisfy registry naming rules (mixed case in repo names is
|
||||
# legal on Gitea but illegal as an image name).
|
||||
repo="$(printf '%s' "${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')"
|
||||
image="gitea.alexandru.macocian.me/${repo}"
|
||||
fi
|
||||
ref="$REF_INPUT"
|
||||
if [ -z "$ref" ]; then
|
||||
ref="${GITHUB_REF_NAME:-main}"
|
||||
fi
|
||||
# UTC ISO-ish, filename-/tag-safe: 2026-05-22T095126Z
|
||||
ts="$(date -u +%Y-%m-%dT%H%M%SZ)"
|
||||
echo "image=$image" >> "$GITHUB_OUTPUT"
|
||||
echo "ref=$ref" >> "$GITHUB_OUTPUT"
|
||||
echo "timestamp-tag=$ts" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::building ${image}:${ts} (+ latest) from ref ${ref}"
|
||||
|
||||
- name: Check out source
|
||||
shell: bash
|
||||
env:
|
||||
REF: ${{ steps.resolve.outputs.ref }}
|
||||
REPO: ${{ github.repository }}
|
||||
REPO_PAT: ${{ secrets.RUNNER_REPO_PAT }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Manual clone — sidesteps the question of which `actions/checkout`
|
||||
# mirror this Gitea instance proxies. Same one-shot auth pattern
|
||||
# as deploy-stack.yml's auto-provisioning step: PAT lives only in
|
||||
# an `http.extraheader` for this single clone, never persisted to
|
||||
# `.git/config`.
|
||||
rm -rf src
|
||||
auth=$(printf '%s' "sys-gitea-runner:${REPO_PAT}" | base64 -w0)
|
||||
git -c "http.extraheader=Authorization: Basic ${auth}" \
|
||||
clone --depth=1 --branch "${REF}" \
|
||||
"https://gitea.alexandru.macocian.me/${REPO}.git" src
|
||||
|
||||
- name: Log in to Gitea container registry
|
||||
shell: bash
|
||||
env:
|
||||
REGISTRY_PAT: ${{ secrets.RUNNER_REGISTRY_PAT }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# `docker login --password-stdin` keeps the PAT out of the
|
||||
# process list. Gitea masks `${{ secrets.* }}` in logs.
|
||||
printf '%s' "$REGISTRY_PAT" | \
|
||||
docker login gitea.alexandru.macocian.me \
|
||||
--username sys-gitea-runner \
|
||||
--password-stdin
|
||||
|
||||
- name: Assemble tag and build-arg lists
|
||||
id: args
|
||||
shell: bash
|
||||
env:
|
||||
IMAGE: ${{ steps.resolve.outputs.image }}
|
||||
TS_TAG: ${{ steps.resolve.outputs.timestamp-tag }}
|
||||
EXTRA_TAGS: ${{ inputs.extra-tags }}
|
||||
BUILD_ARGS: ${{ inputs.build-args }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Tag list: always latest + timestamp. Dedupe so callers that
|
||||
# pass `latest` in extra-tags don't get a noisy double-push.
|
||||
declare -A seen=()
|
||||
tag_args=()
|
||||
add_tag() {
|
||||
local t="$1"
|
||||
[ -z "$t" ] && return 0
|
||||
if [ -z "${seen[$t]+x}" ]; then
|
||||
seen[$t]=1
|
||||
tag_args+=(-t "${IMAGE}:${t}")
|
||||
fi
|
||||
}
|
||||
add_tag "latest"
|
||||
add_tag "$TS_TAG"
|
||||
while IFS= read -r raw; do
|
||||
line="${raw%%#*}"
|
||||
line="$(printf '%s' "$line" | awk '{$1=$1;print}')"
|
||||
[ -z "$line" ] && continue
|
||||
add_tag "$line"
|
||||
done <<< "$EXTRA_TAGS"
|
||||
|
||||
# Build-args: one --build-arg per non-empty / non-comment line.
|
||||
ba_args=()
|
||||
while IFS= read -r raw; do
|
||||
line="${raw%%#*}"
|
||||
line="$(printf '%s' "$line" | awk '{$1=$1;print}')"
|
||||
[ -z "$line" ] && continue
|
||||
case "$line" in
|
||||
*=*) ba_args+=(--build-arg "$line") ;;
|
||||
*) echo "::error::invalid build-arg (missing '='): $raw"; exit 1 ;;
|
||||
esac
|
||||
done <<< "$BUILD_ARGS"
|
||||
|
||||
# Serialise both arrays into single-line, shell-quoted strings
|
||||
# so the next step can `eval set --` them safely. printf %q
|
||||
# handles spaces, quotes, glob chars, etc.
|
||||
printf '%s\n' "$(printf '%q ' "${tag_args[@]}")" > /tmp/charlie-build-tag-args
|
||||
printf '%s\n' "$(printf '%q ' "${ba_args[@]:-}")" > /tmp/charlie-build-ba-args
|
||||
|
||||
{
|
||||
echo "tag-list<<EOF"
|
||||
for t in "${!seen[@]}"; do echo " ${IMAGE}:${t}"; done
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build image
|
||||
shell: bash
|
||||
env:
|
||||
CONTEXT: ${{ inputs.context }}
|
||||
DOCKERFILE: ${{ inputs.dockerfile }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag_args=$(cat /tmp/charlie-build-tag-args)
|
||||
ba_args=$(cat /tmp/charlie-build-ba-args)
|
||||
eval "set -- $tag_args $ba_args"
|
||||
# `--pull` keeps the base image fresh on long-lived runners.
|
||||
# No buildx / multi-arch by default — every host in the fleet
|
||||
# is linux/amd64. Add a `platforms` input + `docker buildx`
|
||||
# branch here if/when that changes.
|
||||
# Dockerfile path is interpreted relative to the build context,
|
||||
# matching the `inputs.dockerfile` doc string.
|
||||
cd src
|
||||
docker build \
|
||||
--pull \
|
||||
-f "${CONTEXT%/}/${DOCKERFILE}" \
|
||||
"$@" \
|
||||
"${CONTEXT}"
|
||||
|
||||
- name: Push image
|
||||
id: push
|
||||
if: ${{ inputs.push }}
|
||||
shell: bash
|
||||
env:
|
||||
IMAGE: ${{ steps.resolve.outputs.image }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag_args=$(cat /tmp/charlie-build-tag-args)
|
||||
eval "set -- $tag_args"
|
||||
# `docker push -t` doesn't exist; the tag list was passed to
|
||||
# `docker build -t` already, so push each resolved tag. Walk
|
||||
# the same list by stripping the leading `-t` flags.
|
||||
tags=()
|
||||
while [ "$#" -gt 0 ]; do
|
||||
if [ "$1" = "-t" ]; then
|
||||
tags+=("$2")
|
||||
shift 2
|
||||
else
|
||||
shift
|
||||
fi
|
||||
done
|
||||
for ref in "${tags[@]}"; do
|
||||
echo "::notice::pushing ${ref}"
|
||||
docker push "${ref}"
|
||||
done
|
||||
# Capture the digest of the timestamp tag — stable, immutable
|
||||
# reference suitable for pinning in compose files.
|
||||
ts_ref="${IMAGE}:${{ steps.resolve.outputs.timestamp-tag }}"
|
||||
digest="$(docker inspect --format '{{index .RepoDigests 0}}' "${ts_ref}" 2>/dev/null | awk -F'@' '{print $2}')"
|
||||
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::pushed digest ${digest}"
|
||||
|
||||
- name: Logout + cleanup
|
||||
if: always()
|
||||
shell: bash
|
||||
env:
|
||||
IMAGE: ${{ steps.resolve.outputs.image }}
|
||||
TS_TAG: ${{ steps.resolve.outputs.timestamp-tag }}
|
||||
run: |
|
||||
set -u
|
||||
docker logout gitea.alexandru.macocian.me >/dev/null 2>&1 || true
|
||||
# Best-effort local image GC: drop the just-built tags so the
|
||||
# runner host doesn't accumulate them forever. The registry has
|
||||
# the canonical copies. `latest` is kept because other builds /
|
||||
# caches on the host may legitimately reference it.
|
||||
docker rmi -f "${IMAGE}:${TS_TAG}" >/dev/null 2>&1 || true
|
||||
rm -f /tmp/charlie-build-tag-args /tmp/charlie-build-ba-args
|
||||
rm -rf src
|
||||
@@ -43,6 +43,7 @@ runs `step ca bootstrap` at container start.
|
||||
| Kind | Path | Purpose |
|
||||
|---|---|---|
|
||||
| Reusable workflow | [`.gitea/workflows/deploy-stack.yml`](../.gitea/workflows/deploy-stack.yml) | The deployment task. Opens SSH session → per-host compose resolution + `git fetch && reset` + SOPS decrypt + `docker compose up -d` + cleanup, all on the target host. |
|
||||
| Reusable workflow | [`.gitea/workflows/build-image.yml`](../.gitea/workflows/build-image.yml) | Build + push a Docker image from a source repo (`amacocian/<name>`) to the Gitea container registry. Tags with `latest` and a UTC timestamp (`YYYY-MM-DDTHHMMSSZ`); deployment repos pin the timestamp tag to roll out. |
|
||||
| Composite action | [`.gitea/actions/charlie-ssh-open`](../.gitea/actions/charlie-ssh-open/action.yml) | Mints a 5-min SSH user cert for `sys-gitea-runner`, opens an SSH ControlMaster session to the target. Exports `CHARLIE_SSH_*` env to subsequent steps. |
|
||||
| Composite action | [`.gitea/actions/charlie-ssh-target`](../.gitea/actions/charlie-ssh-target/action.yml) | Runs a command on the target through the multiplex socket. Optional `workdir:` cd's into a directory first. |
|
||||
| Composite action | [`.gitea/actions/charlie-ssh-close`](../.gitea/actions/charlie-ssh-close/action.yml) | Tears down the multiplex + wipes the ephemeral cert. Idempotent; intended for `if: always()`. |
|
||||
@@ -197,6 +198,128 @@ jobs:
|
||||
Requires the `RUNNER_REPO_PAT` secret to be in scope (set at org level;
|
||||
callers pass via `secrets: inherit`).
|
||||
|
||||
## Inputs reference — `build-image.yml`
|
||||
|
||||
Source repos under `amacocian/*` (newsletter2atom, redlib, caddy, gitea-runner,
|
||||
cert-watch, gssh, invidious, monica, directoryadmin, …) use this workflow to
|
||||
build and push their container image to the Gitea registry. Deployment repos
|
||||
(`Charlie/<stack>`) then pin the timestamp tag in their compose file and
|
||||
trigger `deploy-stack.yml` to roll out.
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `image` | no | `gitea.alexandru.macocian.me/<github.repository>` (lowercased) | Fully-qualified image name without the tag. Override only if the image should not live at its repo's natural path. |
|
||||
| `context` | no | `.` | Docker build context, relative to the caller repo root. |
|
||||
| `dockerfile` | no | `Dockerfile` | Dockerfile path, relative to `context`. |
|
||||
| `build-args` | no | `""` | Multi-line `KEY=VALUE` list. Empty lines and `#` comments ignored. |
|
||||
| `extra-tags` | no | `""` | Additional tags (one per line) pushed alongside `latest` + the timestamp. Just the tag, not the full `image:tag` form. |
|
||||
| `push` | no | `true` | If `false`, build only — useful for PR validation. |
|
||||
| `ref` | no | The branch the workflow ran on | Git ref to check out and build. |
|
||||
|
||||
Every successful build pushes **two** tags:
|
||||
|
||||
| Tag | Mutability | Purpose |
|
||||
|---|---|---|
|
||||
| `latest` | mutable | Convenience for local pulls and one-off `docker run`. **Never reference from a stack compose file** — there's no way for `deploy-stack.yml` to know a new digest landed. |
|
||||
| `YYYY-MM-DDTHHMMSSZ` (UTC) | immutable | The tag deployment repos pin. Bumping it in `docker-compose.yml` and pushing the stack triggers a redeploy. Sortable lexicographically. |
|
||||
|
||||
Outputs (consumable by downstream jobs in the caller workflow):
|
||||
|
||||
| Output | Example | Use |
|
||||
|---|---|---|
|
||||
| `image` | `gitea.alexandru.macocian.me/amacocian/newsletter2atom` | The image ref without the tag. |
|
||||
| `timestamp-tag` | `2026-05-22T095126Z` | The tag the caller can write into the consumer stack's compose file (e.g. via a follow-up job that opens a PR against `Charlie/<stack>`). |
|
||||
| `digest` | `sha256:abc…` | The immutable content digest of the timestamp tag, in case you want to pin by digest instead of tag. |
|
||||
|
||||
Requires two `sys-gitea-runner` PATs — see [Secret placement](#secret-placement-image-source-repos) below.
|
||||
|
||||
### Caller — minimal
|
||||
|
||||
```yaml
|
||||
# amacocian/newsletter2atom/.gitea/workflows/build.yaml
|
||||
name: Build image
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: https://sys-gitea-runner:${{ secrets.RUNNER_REPO_PAT }}@gitea.alexandru.macocian.me/Charlie/project-charlie/.gitea/workflows/build-image.yml@main
|
||||
secrets: inherit
|
||||
```
|
||||
|
||||
### Caller — with build args and an extra tag
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
uses: https://sys-gitea-runner:${{ secrets.RUNNER_REPO_PAT }}@gitea.alexandru.macocian.me/Charlie/project-charlie/.gitea/workflows/build-image.yml@main
|
||||
with:
|
||||
dockerfile: docker/Dockerfile
|
||||
build-args: |
|
||||
VERSION=${{ github.ref_name }}
|
||||
COMMIT=${{ github.sha }}
|
||||
extra-tags: |
|
||||
${{ github.ref_name }}
|
||||
secrets: inherit
|
||||
```
|
||||
|
||||
### Runner-host prerequisites
|
||||
|
||||
Building runs **on the runner**, not on a remote host. The runner container
|
||||
therefore needs:
|
||||
|
||||
| Requirement | Why |
|
||||
|---|---|
|
||||
| `docker` binary inside the container (already shipped by `amacocian/gitea-runner`) | `docker build` / `docker push`. |
|
||||
| The host's `/var/run/docker.sock` bind-mounted into the runner | Build uses the host's docker daemon; no docker-in-docker. |
|
||||
| `sys-gitea-runner` PAT has `write:package` on the target image namespace | `docker login` + push to `gitea.alexandru.macocian.me`. |
|
||||
|
||||
Builds accumulate base-image layers in the runner host's docker storage.
|
||||
The workflow drops the timestamp-tagged image after pushing, but base
|
||||
layers stay cached (intentionally — speeds up subsequent builds). Run
|
||||
`docker system prune` on the runner host periodically.
|
||||
|
||||
### Secret placement (image-source repos)
|
||||
|
||||
`build-image.yml` runs from image-source repos that live **outside** the
|
||||
`Charlie` org — they sit under the personal namespace that owns the
|
||||
images. Gitea Actions secrets are scoped by where the workflow executes,
|
||||
not by who the PAT authenticates as, so the `Charlie`-org-level
|
||||
`RUNNER_REPO_PAT` is **not** visible to those callers. Both secrets must
|
||||
be set on the namespace hosting the source repos.
|
||||
|
||||
Set once, at the **user-level** Settings → Actions → Secrets on the
|
||||
account that owns the source repos. All repos under that personal
|
||||
namespace then inherit both via `secrets: inherit`:
|
||||
|
||||
| Secret | Gitea PAT scope | Used for |
|
||||
|---|---|---|
|
||||
| `RUNNER_REPO_PAT` | `read:repository` (All) | Resolving the absolute-URL `uses:` reference to this workflow + cloning the caller source inside the job. Same value as the `Charlie`-org secret of the same name (duplicate it — no cross-namespace inheritance). |
|
||||
| `RUNNER_REGISTRY_PAT` | `write:package` (All) | `docker login` + push to the Gitea container registry. |
|
||||
|
||||
Both PATs belong to the `sys-gitea-runner` system account. Keeping them
|
||||
as two distinct tokens means the package-write PAT is never used over
|
||||
HTTPS git (and the repo-read PAT can never be used to push images);
|
||||
revoking one doesn't take the other down.
|
||||
|
||||
#### Recipe — provisioning the registry PAT (one-time)
|
||||
|
||||
1. Log in to Gitea as `sys-gitea-runner`. Settings → Applications →
|
||||
"Generate New Token".
|
||||
2. Name: `gitea-runner-package-rw`. Repository and Organization Access:
|
||||
All. Permissions: `write:package`. Generate.
|
||||
3. Copy the token value (shown once).
|
||||
4. Log in to Gitea as the user that owns the image-source repos.
|
||||
Settings → Actions → Secrets → "Add Secret". Name:
|
||||
`RUNNER_REGISTRY_PAT`, value: the token. Save.
|
||||
5. Also add `RUNNER_REPO_PAT` here, value copied from the equivalent
|
||||
`Charlie`-org secret (or from the existing `gitea-runner-repo-ro`
|
||||
token if you can re-export it; otherwise mint a fresh `read:repository`
|
||||
PAT and store the new value in both places).
|
||||
6. Retire any prior `gitea-runner-package-ro` PAT — it's superseded.
|
||||
|
||||
## Inputs reference — `charlie-ssh-open`
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|
||||
@@ -80,6 +80,7 @@ If both runners are down, neither cross-deploy job has anywhere to land. Use the
|
||||
| Identity | Where used | Purpose |
|
||||
|---|---|---|
|
||||
| `sys-gitea-runner` (LDAP) | `~sys-gitea-runner/.git-credentials` (host); SSH user via cert (target host); `RUNNER_REPO_PAT` org secret | THE deployment identity. Member of `charlie-deploy`. Read-only on `Charlie` org. |
|
||||
| `sys-gitea-runner` (Gitea user) | `RUNNER_REPO_PAT` (`read:repository`) + `RUNNER_REGISTRY_PAT` (`write:package`), set per Gitea namespace | Image builds run from non-`Charlie` namespaces (the personal account that owns the source repos); both PATs are set there so [`build-image.yml`](../.gitea/workflows/build-image.yml) can fetch + clone + push. See [automation.md → Secret placement](automation.md#secret-placement-image-source-repos). |
|
||||
| `sys-host-<host>` (LDAP) | `/root/.git-credentials` + `/root/.docker/config.json` (host) | Root-level operations on each host: `sudo git ...`, `sudo docker pull`. Read-only on `Charlie` org. |
|
||||
|
||||
The act_runner registration credential is its **own** identity in Gitea. It can pick up jobs and report results; it cannot read other repos. When it needs to clone for `act`'s `uses:` resolution, it uses the `RUNNER_REPO_PAT` materialised by the entrypoint shim.
|
||||
|
||||
Reference in New Issue
Block a user