settings: three tiers - wikitool.json (instance), .wikitool-local.json (checkout), secrets by reference incl. 1Password CLI; new command config set (#207)
CI / verify (push) Successful in 8m5s
CI / pwsh (push) Successful in 2m34s
Release / release (push) Successful in 36s
Release / wiki-mirror (push) Skipped

Every settings field declares its tier; a value in the wrong file is an error naming
file, key and tier. A field naming a program or affecting a gate cannot be declared
instance. Secrets are references only: {"ref": "<name>"} via WIKITOOL_SECRET_<NAME> or
a user-only secrets file, {"ref": "op://..."} via op read (locked 1Password: exit 42).
The preflight records op as an optional tool. doctor gains one line per tier, docs
verify checks a committed wikitool.json for plaintext secrets, CI resolves a real
op:// value through 1password/load-secrets-action. No feature reads its settings
this way yet; without the two files every other command is unchanged.

Files changed:
- .gitea/workflows/ci.yml
- .gitignore
- AGENTS.md
- CHANGES.md
- INSTALL.md
- VERSION
- docs/explanation/README.md
- docs/explanation/configuration-tiers.md
- docs/how-to/README.md
- docs/how-to/use-1password-for-settings.md
- docs/reference/commands/README.md
- docs/reference/commands/configuration.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/types-instructions-and-docs.md
- docs/reference/configuration.md
- docs/reference/exit-codes.md
- instructions/dev/doc-pull-through.md
- instructions/dev/testing-conventions.md
- instructions/preflight.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/_util.py
- tools/chemenu/commands/config_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/config.py
- tools/chemenu/config_shapes.py
- tools/chemenu/prerequisites.py
- tools/chemenu/settings.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_preflight.py
- tools/chemenu/tests/test_preflight_pwsh.py
- tools/chemenu/tests/test_settings.py
- tools/chemenu/toolpaths.py
- tools/preflight.ps1
- tools/preflight.sh
- tools/prerequisites.txt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Opus 5.5 committed 2026-10-10 15:34:28 +02:00
1 parent 059a0a1840
commit f6aaadc413
40 files changed
+2246 -31

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
# Use 1Password for settings
Keep secrets and private values (host names, internal URLs) out of the working tree by storing
them in 1Password and leaving only an `op://` reference in the settings. The committed
`wikitool.json` then works on every machine signed in to the same 1Password account, and in CI.
What the files and references are: [configuration reference](../reference/configuration.md#tiered-settings).
Why, and what this does not protect against: [configuration-tiers.md](../explanation/configuration-tiers.md).
## On a desktop
1. **Install the 1Password CLI** (`op`) and turn on its integration with the 1Password desktop
app, so `op` asks the app instead of keeping a session of its own. 1Password's own
documentation describes both steps for each platform.
2. **Run the preflight again** - `tools/preflight.sh`, or in PowerShell 7
`pwsh -NoProfile -ExecutionPolicy Bypass -File tools/preflight.ps1`. It records `op` in
`.wikitool-tools.json` and shows it as `OK`; without `op` the line reads `ABSENT`, which is no
problem until a reference needs it.
3. **Make a vault of its own for this instance**, and put each secret or private value into an
item there. A vault of its own limits what an unlocked `op` can reach.
4. **Copy each value's reference** (`op://<vault>/<item>/<field>`) - the 1Password app offers it
on the field - and tell the agent which setting it belongs to:
> Set `<section>.<field>` to the reference `op://<vault>/<item>/<field>`.
The agent runs `tools/wikitool config set <section>.<field> --ref op://<vault>/<item>/<field>`,
which writes the reference into `wikitool.json`. Never paste the value itself into the chat:
the agent should never see it.
5. **Check it:** `tools/wikitool doctor`. The `settings-secrets` line says how many references
resolve. When the desktop app asks to approve access, that is the prompt doing its job - a
locked app makes the line a `WARN`, and a command that needs the value stops with exit 42 until
you unlock it.
## Without 1Password
A reference by name works the same way without `op`:
- set the reference: `tools/wikitool config set <section>.<field> --ref <name>`;
- put the value into `WIKITOOL_SECRET_<NAME>` (the name upper-cased) in the environment, or into
the secrets file `~/.config/chemenu/<instance_id>/secrets.json` as `{"<name>": "<value>"}`,
readable by you only (`chmod 600`). The `instance_id` is in `wikitool.json`.
## In CI
There are two ways, and which one fits depends on the form of the references:
- **`op` itself, with a service-account token** - for settings that hold `op://` references.
Install `op` in the job, run the preflight so it records it, and set `OP_SERVICE_ACCOUNT_TOKEN`;
the references then resolve exactly as on a desktop.
- **1Password's action resolves the values first** - for settings that hold references by name.
`1password/load-secrets-action` with a service-account token reads an `op://` reference into a
variable before `wikitool` starts; name the variable `WIKITOOL_SECRET_<NAME>` and use
`{"ref": "<name>"}` in the settings. This repository's own CI does this, in
`.gitea/workflows/ci.yml`. An `op://` reference in the settings is not resolved this way: it
still needs `op`.
Give the service account access to the instance's own vault only.