The old bash script configured itself through `GITTALLY_*` environment
variables. The blanket rename rewrote those literals, so the converter
was looking for `WERKATOR_*` — a spelling no host has ever written. Fed
a real legacy file it would have found nothing and written an almost
empty configuration, without an error, which is the same silent failure
this rename is otherwise careful to avoid.
The conversion has served its purpose with the vm2176 to vm4006
migration, so it goes instead of being repaired. What remains is the
setup of a new instance: the preconditions, the credential prompt, and
the machine configuration written mode 600 — now carrying the host's
public URL as well, since that is host-specific too. Everything the
repository builds comes from `init` and its templates.
It also stops emitting a legacy `branches:` section, which step 18 is
about to reject outright.
`docs/plan/00-legacy-analysis.md` and `13-nginx-tls.md` get the real
`GITTALLY_*` spelling back: they record what the old script read.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`gitTally` is the name of another product in the git space, so the
rename is a precaution; nothing about what the build system does changes.
The name follows one rule: `Werkator` where it is prose, capitalized
where it is a Kotlin type and its file, lowercase everywhere a machine
reads it — the command, packages, paths, configuration keys and values,
the Gitea check context. Environment variables keep their convention and
are uppercase throughout.
Every configuration file is still found under its pre-rename name
(`ConfigFiles`): `.gittally.yml` at the repository root, in a build
worktree and as committed on a branch, `.git/gittally/.gittally.yml` for
the machine layer. The current name wins where both exist, and the old
file is then ignored rather than merged — two files side by side are a
half-done rename, not a layering. Without the fallback an installation
that updated without renaming would not fail: a configuration that is
not found leaves every setting at its default, so it would come up
looking healthy while having forgotten its credentials and its builds.
`docs/werkator-migrationsplan.md` lists what the fallback does not
cover and has to be moved by hand — above all the state directory
`.git/werkator/`, which holds the build history, the control token and
the worktrees, and has no fallback of its own.
`docs/migration-from-legacy.md` is deleted with this: it mapped the
legacy script's environment variables, and every host it addressed has
long since moved to the YAML configuration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Finishes the small items of the security audit in
docs/prs/2026-07-08-PR#000: TODO 3, 4 and 7.
The three mutating endpoints of BuildsApiController no longer accept the
control token as a `token` query parameter — only the X-GitTally-Token
header, which the bundled UI has always used. URLs end up in access logs,
proxy logs, browser history and Referer headers, and the token never
expires, so a historical log capture would yield a valid credential.
`config:print` masks git.token as `***` on both the raw and the --full
path and names the new --show-secrets flag in a leading YAML comment, so
the output stays parseable when piped. The setup script points at
--show-secrets where it used to steer the operator to the plain token.
`server.bindAddress` now defaults to 127.0.0.1: neither the UI nor the
API authenticates read access, so reaching GitTally should require the
host's reverse proxy. Existing .gittally.yml files keep their explicit
value; the managed nginx container needs `0.0.0.0` set deliberately,
which is noted in the release notes, docs/configuration.md and
docs/deployment.md.
Released as v0.9.9, which also carries the previous two commits.
Co-Authored-By: Claude <noreply@anthropic.com>
Works off the security audit in docs/prs/2026-07-08-PR#000: TODO 1, 8, 9
and 10, the four items that need no design decision.
New `SecretFiles` creates files holding secrets with mode 0600 and their
directories with 0700 *at creation*, as a file attribute, instead of
writing at the umask default and chmod-ing afterwards — that left a
window in which the Gitea token was world-readable, which matters on a
multi-tenant host. It is used by `init` for .git/gittally/.gittally.yml
and by `ControlTokenService` for the control token; the shell setup
script now writes its YAML in a `umask 077` subshell for the same reason.
`ControlTokenService.matches` hashes both sides with SHA-256 before
`MessageDigest.isEqual`, so the comparison always runs over two 32-byte
buffers and cannot return early on a length mismatch.
`GitService.checkout` and `fetchBranch` pass `--` before the refname, so
a branch named like an option cannot be read as one. `resetHardToOrigin`
keeps its plain form: `git reset --hard -- <commit>` is rejected outright
and its argument is already `origin/`-prefixed.
Co-Authored-By: Claude <noreply@anthropic.com>