docs: Record this repo's configuration and the consumer register #77

Merged
ahmad merged 1 commit from feature/pa71-configuration-doc into main 2026-09-09 19:13:30 +00:00
Owner

Issue

Part of #71

Problem

This repository had no configuration document. Its own answer is short — one
name, the per-run token, and nothing registered on the repository at all — but
the short answer is not the useful one. The names a consuming repository must
hold before the standard release flow works are spread across eight README
sections and templates/release.yml, and nobody can currently answer "what does
a new app need in its vault and its Actions settings" without reading all of it.

That is the shape of #64: a name that lives in one place and is referenced from
another, with no register in between.

Solution

docs/CONFIGURATION.md in two parts.

This repository's own configuration. GITHUB_TOKEN, injected per run, used
by report-job-failure in pr.yml and by the tag-and-publish step in
release.yml. Verified against the repository's Actions settings: zero variables
and zero secrets are registered, and none is referenced.

The consumer's register. Every store name an action or the template reads,
grouped by the store it belongs in — four Forgejo secrets, five variables, and
eleven entries under OpenBao secret/<app> — each with which action reads it and
whether it is required.

It is deliberately not a second copy of the action interfaces. The README
documents each action's inputs (deploy-key, grafana-prom-token); the
register documents the store names behind them (VPS_DEPLOY_KEY_B64,
GRAFANA_PROM_TOKEN). Those are different namespaces, and confusing them is the
usual cause of a value that looks provisioned and arrives empty.

Three properties are recorded because each has cost a debugging session and none
is visible from a name: the GRAFANA_PROM_* set is all-or-nothing and
deploy-vps exits 1 on a partial one; the action replaces the host .env
rather than merging, so a name in the vault but absent from app-env reaches the
container empty; and the compose may rename a value between the store and the
process.

Review notes

The line worth checking hardest is the claim that nothing is registered on this
repository — it is what makes the first table complete, and it came from the
Actions settings rather than from the workflows.

EXAMPLE_SECRET and VITE_EXAMPLE in the template are placeholders inside
<…> markers, not names; the document says so rather than listing them.

Two observations recorded but not acted on: the template has no dashboard job,
so GRAFANA_URL and GRAFANA_SA_TOKEN are only needed by repositories that
wired grafana-dashboard in by hand; and the vault address is a literal in every
consumer's workflow rather than a variable.

Risks and trade-offs

Documentation only. All five validate steps pass locally by exit code, and
markdownlint-cli2 is clean on the new file as well as the README, though CI
only lints the README.

### Issue Part of #71 ### Problem This repository had no configuration document. Its own answer is short — one name, the per-run token, and nothing registered on the repository at all — but the short answer is not the useful one. The names a *consuming* repository must hold before the standard release flow works are spread across eight README sections and `templates/release.yml`, and nobody can currently answer "what does a new app need in its vault and its Actions settings" without reading all of it. That is the shape of #64: a name that lives in one place and is referenced from another, with no register in between. ### Solution `docs/CONFIGURATION.md` in two parts. **This repository's own configuration.** `GITHUB_TOKEN`, injected per run, used by `report-job-failure` in `pr.yml` and by the tag-and-publish step in `release.yml`. Verified against the repository's Actions settings: zero variables and zero secrets are registered, and none is referenced. **The consumer's register.** Every store name an action or the template reads, grouped by the store it belongs in — four Forgejo secrets, five variables, and eleven entries under OpenBao `secret/<app>` — each with which action reads it and whether it is required. It is deliberately not a second copy of the action interfaces. The README documents each action's **inputs** (`deploy-key`, `grafana-prom-token`); the register documents the **store names** behind them (`VPS_DEPLOY_KEY_B64`, `GRAFANA_PROM_TOKEN`). Those are different namespaces, and confusing them is the usual cause of a value that looks provisioned and arrives empty. Three properties are recorded because each has cost a debugging session and none is visible from a name: the `GRAFANA_PROM_*` set is all-or-nothing and `deploy-vps` exits 1 on a partial one; the action **replaces** the host `.env` rather than merging, so a name in the vault but absent from `app-env` reaches the container empty; and the compose may rename a value between the store and the process. ### Review notes The line worth checking hardest is the claim that nothing is registered on this repository — it is what makes the first table complete, and it came from the Actions settings rather than from the workflows. `EXAMPLE_SECRET` and `VITE_EXAMPLE` in the template are placeholders inside `<…>` markers, not names; the document says so rather than listing them. Two observations recorded but not acted on: the template has no `dashboard` job, so `GRAFANA_URL` and `GRAFANA_SA_TOKEN` are only needed by repositories that wired `grafana-dashboard` in by hand; and the vault address is a literal in every consumer's workflow rather than a variable. ### Risks and trade-offs Documentation only. All five `validate` steps pass locally by exit code, and `markdownlint-cli2` is clean on the new file as well as the README, though CI only lints the README.
docs: Record this repo's configuration and the consumer register
All checks were successful
PR / validate (pull_request) Successful in 19s
8189a41f81
This repository reads one name for itself, the per-run token, and holds
no variables or secrets. What was undocumented is the other half: the
store names a consuming repository must hold before the standard release
flow works, which store each belongs in, and which action reads it.

The README documents each action's inputs; those are a different
namespace from the store names behind them, and confusing the two is the
usual cause of a value that looks provisioned and arrives empty.

Also records the three properties that decide whether a value arrives at
all: the all-or-nothing Grafana set, that deploy-vps replaces the host
.env rather than merging into it, and that the compose may rename a
value between the store and the process.
ahmad changed title from WIP: docs: Record this repo's configuration and the consumer register to docs: Record this repo's configuration and the consumer register 2026-09-09 18:18:10 +00:00
Author
Owner

Self-verified against each acceptance criterion on 8189a41; PR / validate green.

  • Lists every variable and secret its workflows reference, and no variable it does not. .forgejo/workflows/ references exactly one name, secrets.GITHUB_TOKEN, in both workflows. Checked the other direction too: the repository has zero Actions variables and zero Actions secrets registered, so the first table is complete in both senses. The two names in the template that look like configuration — EXAMPLE_SECRET, VITE_EXAMPLE — are placeholders inside <…> markers and are named as such rather than listed.
  • Each row states name, type, scope, where the value lives, required, and a one-line description — never a value. The consumer register groups by store instead of repeating a "where it lives" column that would say the same thing on every row in a group.
  • The README links to the document. From the end of Consuming an action, where a reader has just been told this repository holds no secrets and credentials come from the caller — which is the sentence that raises the question the register answers.
  • Where an .env.example exists, the two agree. There is none here: no application, no compose, nothing deployed.

Gates run locally, by exit code: test-check-actions.py 0, check-actions.py 0, test-behaviour-harness.py 0, behaviour-tests.py 0, README lint 0. markdownlint-cli2 is also clean on the new file, though pr.yml only lints README.md.

The design decision worth a second look is what this document is not. Repeating each action's inputs would have made it the second list the conventions forbid, and the README's per-action sections are better at that job. What had no home is the mapping from a store name to the action that reads it — VPS_DEPLOY_KEY_B64 → deploy-key, GRAFANA_PROM_TOKEN → grafana-prom-token — plus the three properties that decide whether a value arrives at all. Those three are stated because each is invisible from the name and each has cost a session: the all-or-nothing Grafana set, the wholesale replacement of the host .env, and the compose renaming a value between the store and the process.

Self-verified against each acceptance criterion on `8189a41`; `PR / validate` green. - *Lists every variable and secret its workflows reference, and no variable it does not.* `.forgejo/workflows/` references exactly one name, `secrets.GITHUB_TOKEN`, in both workflows. Checked the other direction too: the repository has **zero** Actions variables and **zero** Actions secrets registered, so the first table is complete in both senses. The two names in the template that look like configuration — `EXAMPLE_SECRET`, `VITE_EXAMPLE` — are placeholders inside `<…>` markers and are named as such rather than listed. - *Each row states name, type, scope, where the value lives, required, and a one-line description — never a value.* The consumer register groups by store instead of repeating a "where it lives" column that would say the same thing on every row in a group. - *The README links to the document.* From the end of *Consuming an action*, where a reader has just been told this repository holds no secrets and credentials come from the caller — which is the sentence that raises the question the register answers. - *Where an `.env.example` exists, the two agree.* There is none here: no application, no compose, nothing deployed. Gates run locally, by exit code: `test-check-actions.py` 0, `check-actions.py` 0, `test-behaviour-harness.py` 0, `behaviour-tests.py` 0, README lint 0. `markdownlint-cli2` is also clean on the new file, though `pr.yml` only lints `README.md`. The design decision worth a second look is what this document is *not*. Repeating each action's inputs would have made it the second list the conventions forbid, and the README's per-action sections are better at that job. What had no home is the mapping from a store name to the action that reads it — `VPS_DEPLOY_KEY_B64` → `deploy-key`, `GRAFANA_PROM_TOKEN` → `grafana-prom-token` — plus the three properties that decide whether a value arrives at all. Those three are stated because each is invisible from the name and each has cost a session: the all-or-nothing Grafana set, the wholesale replacement of the host `.env`, and the compose renaming a value between the store and the process.
ahmad_bot approved these changes 2026-09-09 18:46:11 +00:00
ahmad_bot left a comment

Approved. The split between action inputs and store names is the right idea and it is the thing the other ten documents will each get wrong on their own — those really are two namespaces, and the register is the first place either has been written down as such.

Verified

  • The register matches templates/release.yml exactly, in both directions. Its secrets.* are OPENBAO_ROLE_ID, OPENBAO_SECRET_ID, DOCKER_HUB_USER, DOCKER_HUB_READ_PUBLIC and GITHUB_TOKEN — the first four are the register's four repository secrets and the fifth is the per-run token in the table above it. Its vars.* are ENABLE_VPS_DEPLOY, VPS_DEPLOY_DOMAIN, GRAFANA_PROM_URL, GRAFANA_PROM_USER plus the VITE_EXAMPLE placeholder; the register's five are those four plus GRAFANA_URL, which is not in the template and is labelled as such. Eleven vault entries, and every env.* name in the template resolves to one of them.
  • The only two names my sweep flagged are VPS_DEPLOY_KEY and VPS_HOST_KEY, and they are correctly absent: they are the decoded forms of the _B64 store names, produced by a step and handed to deploy-key/host-key. Excluding them is the register's own distinction doing its job — they are neither a store name nor an input.
  • Every input the register cites exists. grafana-dashboard really does take grafana-token beside grafana-url; deploy-vps takes deploy-host, deploy-user, deploy-key, host-key, deploy-path, deploy-domain, registry-token, grafana-prom-{url,user,token} and app-env. And registry-user is correctly not in the register: consumers pass github.actor, so there is no stored name behind it.
  • "The template has no dashboard job" is right — its jobs are version, publish, deploy, notify. So GRAFANA_URL and GRAFANA_SA_TOKEN really are only needed by repositories that wired grafana-dashboard in by hand.
  • EXAMPLE_SECRET (line 269) and VITE_EXAMPLE (line 211) are both inside <…> markers. Excluding them with a stated reason is better than listing them.
  • The three rules are each verified and each was worth the space. The GRAFANA_PROM_* set: deploy-vps/action.yml:141-149 exits 1 on a partial one. The replacement: the action builds { … } > .env.deploy — DEPLOY_DOMAIN, IMAGE_TAG, the app-env lines, COMPOSE_PROFILES and the three Grafana values, nothing else — so a vault name absent from app-env reaches the container empty. The rename: ahmad/namey reads ${APP_TELEGRAM_BOT_TOKEN} in its compose while the repository holds TELEGRAM_BOT_TOKEN, and the app's Telegram integration is inert in production as a result — a live instance of rule three, found on namey#79 an hour ago.
  • Only GITHUB_TOKEN is referenced by this repository's own workflows (plus NOTES and VERSION, which are step-local env: and not configuration).

The one claim I cannot check, and a correction to what I have said before about that. "Zero variables and zero secrets are registered on this repository" came from the Actions settings, and this identity gets 403 user should be the owner of the repo on both /actions/secrets and /actions/variables here — so I can confirm nothing is referenced, which is the half that makes the table complete for a reader, but not that nothing is registered.

I have twice told you that wall is universal for the review bot. It is not, and the pattern is per-organisation. Both endpoints answer for every Bayan/* and suhba/* repository and 403 for every ahmad/* and amtronics/* one:

Bayan/bayan-web  secrets 6  variables 14      ahmad/*            403 / 403  (7 repos)
Bayan/kidpoints  secrets 15 variables 16      amtronics/*        403 / 403  (2 repos)
Bayan/stem       secrets 2  variables 7
suhba/suhba-web  secrets 2  variables 6
suhba/suhba-docs secrets 2  variables 3
suhba/khitta     secrets 2  variables 11

So for the five #71 repositories left — bayan/bayan-web, bayan/kidpoints, suhba/suhba-web, suhba/suhba-docs, suhba/khitta — the bot can read the registration back and check the "set but read by nothing" half itself, which it could not do for trip or namey. Worth knowing before writing those five, and worth me correcting rather than leaving you to work around a limit that does not apply there.

No findings.

Approved. The split between *action inputs* and *store names* is the right idea and it is the thing the other ten documents will each get wrong on their own — those really are two namespaces, and the register is the first place either has been written down as such. **Verified** - **The register matches `templates/release.yml` exactly, in both directions.** Its `secrets.*` are `OPENBAO_ROLE_ID`, `OPENBAO_SECRET_ID`, `DOCKER_HUB_USER`, `DOCKER_HUB_READ_PUBLIC` and `GITHUB_TOKEN` — the first four are the register's four repository secrets and the fifth is the per-run token in the table above it. Its `vars.*` are `ENABLE_VPS_DEPLOY`, `VPS_DEPLOY_DOMAIN`, `GRAFANA_PROM_URL`, `GRAFANA_PROM_USER` plus the `VITE_EXAMPLE` placeholder; the register's five are those four plus `GRAFANA_URL`, which is not in the template and is labelled as such. Eleven vault entries, and every `env.*` name in the template resolves to one of them. - **The only two names my sweep flagged are `VPS_DEPLOY_KEY` and `VPS_HOST_KEY`**, and they are correctly absent: they are the *decoded* forms of the `_B64` store names, produced by a step and handed to `deploy-key`/`host-key`. Excluding them is the register's own distinction doing its job — they are neither a store name nor an input. - **Every input the register cites exists.** `grafana-dashboard` really does take `grafana-token` beside `grafana-url`; `deploy-vps` takes `deploy-host`, `deploy-user`, `deploy-key`, `host-key`, `deploy-path`, `deploy-domain`, `registry-token`, `grafana-prom-{url,user,token}` and `app-env`. And `registry-user` is correctly *not* in the register: consumers pass `github.actor`, so there is no stored name behind it. - **"The template has no `dashboard` job" is right** — its jobs are `version`, `publish`, `deploy`, `notify`. So `GRAFANA_URL` and `GRAFANA_SA_TOKEN` really are only needed by repositories that wired `grafana-dashboard` in by hand. - `EXAMPLE_SECRET` (line 269) and `VITE_EXAMPLE` (line 211) are both inside `<…>` markers. Excluding them with a stated reason is better than listing them. - **The three rules are each verified and each was worth the space.** The `GRAFANA_PROM_*` set: `deploy-vps/action.yml:141-149` exits 1 on a partial one. The replacement: the action builds `{ … } > .env.deploy` — `DEPLOY_DOMAIN`, `IMAGE_TAG`, the `app-env` lines, `COMPOSE_PROFILES` and the three Grafana values, nothing else — so a vault name absent from `app-env` reaches the container empty. The rename: `ahmad/namey` reads `${APP_TELEGRAM_BOT_TOKEN}` in its compose while the repository holds `TELEGRAM_BOT_TOKEN`, and the app's Telegram integration is inert in production as a result — a live instance of rule three, found on `namey#79` an hour ago. - Only `GITHUB_TOKEN` is referenced by this repository's own workflows (plus `NOTES` and `VERSION`, which are step-local `env:` and not configuration). **The one claim I cannot check, and a correction to what I have said before about that.** "Zero variables and zero secrets are registered on this repository" came from the Actions settings, and this identity gets `403 user should be the owner of the repo` on both `/actions/secrets` and `/actions/variables` here — so I can confirm nothing is *referenced*, which is the half that makes the table complete for a reader, but not that nothing is *registered*. I have twice told you that wall is universal for the review bot. **It is not, and the pattern is per-organisation.** Both endpoints answer for every `Bayan/*` and `suhba/*` repository and 403 for every `ahmad/*` and `amtronics/*` one: Bayan/bayan-web secrets 6 variables 14 ahmad/* 403 / 403 (7 repos) Bayan/kidpoints secrets 15 variables 16 amtronics/* 403 / 403 (2 repos) Bayan/stem secrets 2 variables 7 suhba/suhba-web secrets 2 variables 6 suhba/suhba-docs secrets 2 variables 3 suhba/khitta secrets 2 variables 11 So for the five `#71` repositories left — `bayan/bayan-web`, `bayan/kidpoints`, `suhba/suhba-web`, `suhba/suhba-docs`, `suhba/khitta` — **the bot can read the registration back and check the "set but read by nothing" half itself**, which it could not do for `trip` or `namey`. Worth knowing before writing those five, and worth me correcting rather than leaving you to work around a limit that does not apply there. No findings.
ahmad merged commit 8fa4fb972e into main 2026-09-09 19:13:30 +00:00
ahmad deleted branch feature/pa71-configuration-doc 2026-09-09 19:13:30 +00:00
Sign in to join this conversation.
No description provided.