coily ops forgejo: wrap forgejo admin CLI verbs for the kai-server deploy #55

Open
opened 2026-05-23 20:54:03 +00:00 by coilysiren · 0 comments
Owner

Originally filed by @coilysiren on 2026-05-05T10:36:44Z - https://github.com/coilysiren/coily/issues/57

Proposal

Add a `coily ops forgejo ...` verb group that wraps the in-pod `forgejo` CLI on the kai-server k3s deploy. Each leaf is a fixed-shape `k3s kubectl -n forgejo exec deploy/forgejo -- forgejo `, run through the privileged-op gate (audit + scope binding) like every other `ops` verb.

Spawned from the forgejo deploy. Pairs with #50 (the broader `coily ops ` rename) - this issue carves out the forgejo-shaped surface inside that group regardless of whether #50 lands first.

Why

Three shapes recur for managing this Forgejo instance from outside the pod:

  1. Initial bootstrap - admin user create, regenerate keys, doctor checks. One-shot, but high-friction (had to wave through the harness deny-rule on `kubectl exec` to mint the admin during the deploy).
  2. Ongoing admin - rotate user passwords, list/promote users, sync repo releases, run doctor.
  3. Backups + recovery - `forgejo dump` on a CronJob (per the deploy plan's followup) and ad-hoc dumps.

All three want the same shape: "run a fixed-shape forgejo CLI verb against the running pod, log it, no sudo, no escape hatch."

Without a wrapper each one is bare `ssh kai-server 'k3s kubectl -n forgejo exec ...'`, which (a) is gated by the harness's `kubectl exec` deny-rule (rightly), (b) leaves no audit row, (c) varies subtly per invocation and creates a documentation maintenance burden.

Verb selection (forgejo 15.0.1 `forgejo --help` survey)

Strong fit for wrapping (admin-shaped, safe, repeatable):

  • `coily ops forgejo admin user create` - mirror the rootless-image flow used in the deploy plan
  • `coily ops forgejo admin user list`
  • `coily ops forgejo admin user change-password`
  • `coily ops forgejo admin user delete`
  • `coily ops forgejo admin user must-change-password`
  • `coily ops forgejo admin regenerate hooks` / `keys`
  • `coily ops forgejo admin auth list`
  • `coily ops forgejo doctor check --run `
  • `coily ops forgejo doctor recreate-table`
  • `coily ops forgejo dump` - destination is a sibling PVC, ties into the planned backup CronJob
  • `coily ops forgejo manager flush-queues` / `logging pause` / `logging resume`
  • `coily ops forgejo actions generate-runner-token` - lines up with the deploy plan's deferred Actions-runner decision

Skip / explicit reject:

  • `forgejo serv` / `forgejo hook` / `forgejo keys` - documented as internal SSH-shell-only, do not expose
  • `forgejo migrate` - destructive enough that it should stay manual, not a coily verb
  • `forgejo migrate-storage` - same
  • `forgejo dump-repo` / `restore-repo` - operate on filesystem paths inside the pod that aren't mounted out, not useful through the wrapper

Borderline (decide during implementation):

  • `forgejo embedded` - extracts embedded resources, niche
  • `forgejo cert` - we don't run forgejo's self-signed cert path, cert-manager handles TLS at the ingress
  • `forgejo generate` - secret/key generation, but we mint these via SSM not from inside the pod

Mechanical scope

  • New `cmd/ops/forgejo/` (or wherever #50 puts the `ops` group) with one leaf per verb above. Each leaf renders a fixed remote command, runs it through the same audit + ssh path as `coily ssh kubectl` (which itself needs #56 fixed first or the same not-actually-sudo wrapper).
  • Pin the namespace (`forgejo`) and pod selector (`deploy/forgejo`) in code, not as flags. No free-form passthrough.
  • Audit-log verb names: `ops.forgejo.admin.user.create`, `ops.forgejo.dump`, etc.
  • README on the verb group: when to use it vs raw kubectl, link back to the deploy plan.

Out of scope

  • The Postgres-side admin verbs (`pg_dump` etc.) - separate issue if/when needed, different pod and different security shape.
  • A general `coily ops kubectl exec ...` allowlist - explicitly rejected by Kai during the forgejo deploy, the right unit of grouping is per-app verbs.
  • The harness deny-rule on `kubectl exec` - that one stays. `coily ops forgejo` is the affordance, not a bypass.

Dependencies

  • #56 (drop the sudo wrap on `coily ssh kubectl`) should land first or this group will hit the same sudo wall.
  • #50 (the `ops` rename) determines where this lives in the command tree but doesn't block the implementation - if #50 lands later, rename then.
_Originally filed by @coilysiren on 2026-05-05T10:36:44Z - [https://github.com/coilysiren/coily/issues/57](https://github.com/coilysiren/coily/issues/57)_ ## Proposal Add a \`coily ops forgejo ...\` verb group that wraps the in-pod \`forgejo\` CLI on the kai-server k3s deploy. Each leaf is a fixed-shape \`k3s kubectl -n forgejo exec deploy/forgejo -- forgejo <verb>\`, run through the privileged-op gate (audit + scope binding) like every other \`ops\` verb. Spawned from the [forgejo deploy](https://github.com/coilysiren/infrastructure/blob/main/docs/forgejo-deploy-plan.md). Pairs with #50 (the broader \`coily ops <tool>\` rename) - this issue carves out the forgejo-shaped surface inside that group regardless of whether #50 lands first. ## Why Three shapes recur for managing this Forgejo instance from outside the pod: 1. **Initial bootstrap** - admin user create, regenerate keys, doctor checks. One-shot, but high-friction (had to wave through the harness deny-rule on \`kubectl exec\` to mint the admin during the deploy). 2. **Ongoing admin** - rotate user passwords, list/promote users, sync repo releases, run doctor. 3. **Backups + recovery** - \`forgejo dump\` on a CronJob (per the deploy plan's followup) and ad-hoc dumps. All three want the same shape: \"run a fixed-shape forgejo CLI verb against the running pod, log it, no sudo, no escape hatch.\" Without a wrapper each one is bare \`ssh kai-server 'k3s kubectl -n forgejo exec ...'\`, which (a) is gated by the harness's \`kubectl exec\` deny-rule (rightly), (b) leaves no audit row, (c) varies subtly per invocation and creates a documentation maintenance burden. ## Verb selection (forgejo 15.0.1 \`forgejo --help\` survey) Strong fit for wrapping (admin-shaped, safe, repeatable): - \`coily ops forgejo admin user create\` - mirror the rootless-image flow used in the deploy plan - \`coily ops forgejo admin user list\` - \`coily ops forgejo admin user change-password\` - \`coily ops forgejo admin user delete\` - \`coily ops forgejo admin user must-change-password\` - \`coily ops forgejo admin regenerate hooks\` / \`keys\` - \`coily ops forgejo admin auth list\` - \`coily ops forgejo doctor check --run <name>\` - \`coily ops forgejo doctor recreate-table\` - \`coily ops forgejo dump\` - destination is a sibling PVC, ties into the planned backup CronJob - \`coily ops forgejo manager flush-queues\` / \`logging pause\` / \`logging resume\` - \`coily ops forgejo actions generate-runner-token\` - lines up with the deploy plan's deferred Actions-runner decision Skip / explicit reject: - \`forgejo serv\` / \`forgejo hook\` / \`forgejo keys\` - documented as internal SSH-shell-only, do not expose - \`forgejo migrate\` - destructive enough that it should stay manual, not a coily verb - \`forgejo migrate-storage\` - same - \`forgejo dump-repo\` / \`restore-repo\` - operate on filesystem paths inside the pod that aren't mounted out, not useful through the wrapper Borderline (decide during implementation): - \`forgejo embedded\` - extracts embedded resources, niche - \`forgejo cert\` - we don't run forgejo's self-signed cert path, cert-manager handles TLS at the ingress - \`forgejo generate\` - secret/key generation, but we mint these via SSM not from inside the pod ## Mechanical scope - New \`cmd/ops/forgejo/\` (or wherever #50 puts the \`ops\` group) with one leaf per verb above. Each leaf renders a fixed remote command, runs it through the same audit + ssh path as \`coily ssh kubectl\` (which itself needs #56 fixed first or the same not-actually-sudo wrapper). - Pin the namespace (\`forgejo\`) and pod selector (\`deploy/forgejo\`) in code, not as flags. No free-form passthrough. - Audit-log verb names: \`ops.forgejo.admin.user.create\`, \`ops.forgejo.dump\`, etc. - README on the verb group: when to use it vs raw kubectl, link back to the deploy plan. ## Out of scope - The Postgres-side admin verbs (\`pg_dump\` etc.) - separate issue if/when needed, different pod and different security shape. - A general \`coily ops kubectl exec ...\` allowlist - explicitly rejected by Kai during the forgejo deploy, the right unit of grouping is per-app verbs. - The harness deny-rule on \`kubectl exec\` - that one stays. \`coily ops forgejo\` is the affordance, not a bypass. ## Dependencies - #56 (drop the sudo wrap on \`coily ssh kubectl\`) should land first or this group will hit the same sudo wall. - #50 (the \`ops\` rename) determines where this lives in the command tree but doesn't block the implementation - if #50 lands later, rename then.
coilysiren added
P4
and removed
P3
labels 2026-05-31 06:59:48 +00:00
Sign in to join this conversation.
No labels
P0
P1
P2
P3
P4
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-bridge/coily#55
No description provided.