~bigbes/sourcehut-root

72581ff94e21863373e2c72a01eb75332cb22f32 — Eugene Blikh 2 days ago 10a4d66 master
docs(sourcehut-ci): fix factual errors found in full audit

Verified the skill against the actual upstream sources mirrored in this
workspace and fixed every concrete claim that didn't match the code:

- Secrets management URL is builds.sr.ht/secrets, not meta.sr.ht/secrets
  (route lives in builds.sr.ht/buildsrht/blueprints/secrets.py; meta has
  no /secret* route). Updated SKILL.md, manifest.md, secrets-and-oauth.md.

- SSH key secret installation path: the worker uses the manifest entry
  verbatim, so name references land at ~/.ssh/<name>, not ~/.ssh/<uuid>
  (builds.sr.ht/worker/tasks.go SendSecrets).

- ubuntu/lts now points to resolute (26.04 LTS); oldlts points to noble.
  Added jammy and questing to the shipped-versions list.

- hut todo subcommands: rewrote the block to match v0.8.0 — `create` and
  `comment` only accept --stdin (no -t/-s/-b), `update-status` (not
  `update`), `list` reads --tracker (persistent flag on `hut todo`).

- hut pages acl update --id is required (MarkFlagRequired in
  hut/pages.go), not optional.
M skills/sourcehut-ci/SKILL.md => skills/sourcehut-ci/SKILL.md +1 -1
@@ 154,7 154,7 @@ secrets:
  - github-deploy-key            # by name also works
```

Secrets come in three flavors registered at `meta.sr.ht/secrets`: **SSH keys** (mounted at `~/.ssh/id_*` with appropriate permissions), **PGP keys** (imported into the build user's keyring), and **files** (placed at a path you specify with a mode you specify). Plain "environment variable" secrets aren't a separate type — use a file secret containing `KEY=value` and `source` it, or use the OAuth flow described above.
Secrets come in three flavors registered at `builds.sr.ht/secrets` (on builds.sr.ht, not meta.sr.ht): **SSH keys** (mounted at `~/.ssh/id_*` with appropriate permissions), **PGP keys** (imported into the build user's keyring), and **files** (placed at a path you specify with a mode you specify). Plain "environment variable" secrets aren't a separate type — use a file secret containing `KEY=value` and `source` it, or use the OAuth flow described above.

Watch out for `set -x` echoing secret values to the log. If a task references a secret-derived value, run `set +x` before the sensitive command and `set -x` after. See `references/secrets-and-oauth.md` for the full picture, including why `oauth:` is almost always better than `secrets:` for sr.ht-internal services.


M skills/sourcehut-ci/references/hut.md => skills/sourcehut-ci/references/hut.md +5 -5
@@ 95,7 95,7 @@ hut pages publish -d <fqdn> [-s <subdir>] [-p https|gemini] [--site-config <path
hut pages unpublish -d <fqdn> [-p https|gemini]
hut pages list
hut pages acl list -d <fqdn>
hut pages acl update <user> [--id <site-id>] [--publish]
hut pages acl update <user> --id <site-id> [--publish]
```

Input to `publish` can be a `.tar.gz` or a directory; passing `-` (or omitting the path on a non-terminal stdin) reads from stdin. **No symlinks, no special files, mode 644 only** — `pages.sr.ht` rejects them. The reliable invocation is:


@@ 170,11 170,11 @@ oauth: todo.sr.ht/TRACKERS:RW
```

```
hut todo ticket create -t <tracker> -s "<subject>" [-b <body>]
hut todo ticket update <ticket-ref> --status <STATUS> --resolution <RESOLUTION>
hut todo ticket comment <ticket-ref> -b <body>
hut todo ticket create --tracker <tracker> [--stdin]
hut todo ticket update-status <ticket-ref> -s <STATUS> [-r <RESOLUTION>]
hut todo ticket comment <ticket-ref> [--stdin] [-s <STATUS>] [-r <RESOLUTION>]
hut todo ticket assign <ticket-ref> -u <user>
hut todo ticket list -t <tracker>
hut todo ticket list --tracker <tracker> [-s <status>]
```

Useful for "open a ticket on flaky test" / "close the auto-generated ticket on green build" patterns.

M skills/sourcehut-ci/references/images.md => skills/sourcehut-ci/references/images.md +3 -3
@@ 65,9 65,9 @@ Self-hosted instances also commonly ship a **subset** of the upstream catalog. T

- Like Debian, but Canonical's spin. `apt` for packages.
- Aliases (2026):
  - `ubuntu/lts` = `ubuntu/noble` (24.04 LTS).
  - `ubuntu/oldlts` = `ubuntu/jammy` (22.04 LTS).
  - Other shipped: `focal` (20.04 LTS), `oracular` (24.10), `plucky` (25.04).
  - `ubuntu/lts` = `ubuntu/resolute` (26.04 LTS).
  - `ubuntu/oldlts` = `ubuntu/noble` (24.04 LTS).
  - Other shipped: `focal` (20.04 LTS), `jammy` (22.04 LTS), `oracular` (24.10), `plucky` (25.04), `questing` (25.10).
- Default arch is `amd64`, not `x86_64`. Slower boot than Alpine. Larger image.

### Fedora (`fedora/<version>`)

M skills/sourcehut-ci/references/manifest.md => skills/sourcehut-ci/references/manifest.md +1 -1
@@ 168,7 168,7 @@ Important: tasks are *separate login sessions*. Environment variables `export`ed

## `secrets` (optional, list of UUIDs or names)

Each entry is either a UUID or the human-readable name (3–512 chars) of a secret registered at <https://meta.sr.ht/secrets>. See `secrets-and-oauth.md` for the full discussion.
Each entry is either a UUID or the human-readable name (3–512 chars) of a secret registered at <https://builds.sr.ht/secrets> (on builds.sr.ht, not meta.sr.ht). See `secrets-and-oauth.md` for the full discussion.

```yaml
secrets:

M skills/sourcehut-ci/references/secrets-and-oauth.md => skills/sourcehut-ci/references/secrets-and-oauth.md +2 -2
@@ 51,7 51,7 @@ The scope catalog is at `https://meta.sr.ht/oauth2`. When in doubt, check there.

## Stored secrets (`secrets:` directive)

Secrets are registered once on your account at `https://meta.sr.ht/secrets` and referenced in manifests by either UUID **or** the human-readable name you gave the secret. The Python validator (`buildsrht/manifest.py`) parses each entry as a UUID first; on failure it falls back to a 3–512 character string treated as a name lookup.
Secrets are registered once on your account at `https://builds.sr.ht/secrets` (on **builds.sr.ht**, not meta.sr.ht — meta hosts OAuth clients and account SSH/PGP keys; build-secrets live on the service that consumes them) and referenced in manifests by either UUID **or** the human-readable name you gave the secret. `hut builds secret` is read-only (`list`/`share`); use the web UI or the GraphQL API to create them. The Python validator (`buildsrht/manifest.py`) parses each entry as a UUID first; on failure it falls back to a 3–512 character string treated as a name lookup.

```yaml
secrets:


@@ 65,7 65,7 @@ builds.sr.ht installs each secret into the VM before tasks run. Three secret typ

### SSH key secret

When registered, paste the **private key** (e.g. contents of `~/.ssh/id_ed25519`). At build time, the worker writes it to `~/.ssh/<secret-uuid>` with mode 600. The **first** SSH-key secret in the manifest's `secrets:` list also gets symlinked to `~/.ssh/id_rsa`, which is what most tools look for by default — additional SSH-key secrets only show up under their UUID filenames, so you have to point ssh at them explicitly (`ssh -i ~/.ssh/<uuid>` or a `Host` block in `~/.ssh/config`).
When registered, paste the **private key** (e.g. contents of `~/.ssh/id_ed25519`). At build time, the worker writes it to `~/.ssh/<reference>` with mode 600 — `<reference>` is whatever string you used in the manifest's `secrets:` list, so a UUID reference lands at `~/.ssh/<uuid>` and a name reference lands at `~/.ssh/<name>` (see `builds.sr.ht/worker/tasks.go` `SendSecrets`). The **first** SSH-key secret in the list also gets symlinked to `~/.ssh/id_rsa`, which is what most tools look for by default — additional SSH-key secrets only show up under their `<reference>` filenames, so you have to point ssh at them explicitly (`ssh -i ~/.ssh/<reference>` or a `Host` block in `~/.ssh/config`).

The worker does **not** populate `~/.ssh/known_hosts` — host-key checking is `StrictHostKeyChecking=no` for the initial `git clone` from `sources:` (set via `GIT_SSH_COMMAND`), but for any SSH you do inside tasks, `ssh-keyscan -H <host> >> ~/.ssh/known_hosts` first (or accept the StrictHostKey prompt would hang the build).