This repository has been archived on 2026-10-18. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Miles WardandClaude Fable 5.1 04a86ead95 v0.2: covered codes, service marks, and an audit log
Codes are covered until revealed. A reveal is a server-side, per-session
window (60 s, two periods): POST /api/accounts/{id}/reveal opens it and
returns the code, GET /api/codes only ever returns codes for accounts in
that window, and /hide closes it early. The browser therefore never holds
a code it has not asked for by name, which is what makes the log honest.

Settings -> Log is an audit trail in the style of Daito: one line per
event with who, how long ago and from which address. It records what the
server observed - sign-ins and failed attempts (under the name tried),
reveals, accounts added / renamed / removed, delivery and credential
changes, test messages. Entries are JSON lines in audit.jsonl (owner-only,
newest 5,000 kept, compacted at twice that). The address comes from
X-Forwarded-For / X-Real-IP when parseable, else the TCP peer via
ConnectInfo; in Docker bridge networking that peer is the gateway, which
the README and template now say.

The account list shows each service's mark instead of an initial. The
pack (crates/webui/src/icons.js, generated by scripts/fetch-icons.py) is
~175 marks from Simple Icons (CC0) plus Font Awesome Free brands (CC BY
4.0) for Amazon, AWS, Microsoft, LinkedIn, Slack, Xbox, Salesforce and
Yahoo, which Simple Icons no longer carries. Matching is by issuer name,
then shorter word prefixes, then the label's mail domain; unmatched
accounts keep the initial tile. Marks that would vanish against a theme's
tile fall back to ink for that theme only.

The setup and Delivery platform pickers are plain text; the coloured dots
are gone.

Router tests cover the reveal window, session scoping, 401s, and the
forwarded address landing in the log.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-09 02:08:47 -04:00

3.8 KiB

Publishing to Gitea

Releases are cut by hand. Each one needs a Gitea personal access token with the write:repository and write:package scopes, which is why none of this is automated: the token should only ever exist in your own shell or keychain.

On a Mac that has pushed before, git already holds the token in the login keychain and nothing needs exporting. Elsewhere, create one at Gitea → Settings → Applications → Generate New Token and export it once per shell session:

export GITEA_TOKEN='<paste-your-token>'

1. Cut the version

Bump version in the workspace Cargo.toml, update the IMAGE_TAG and GIT_REF defaults in scripts/build-and-publish-unraid.sh, add a line to the README changelog, and commit. Then tag:

git tag -a v0.2 -m "OpenMFA v0.2"

Tags are vMAJOR.MINOR[.PATCH] — v0.1, v0.2, … — and the image carries the same number without the v (0.1, 0.1.1, 0.2) plus a moving latest.

2. Push the code and the tag

git push origin main --follow-tags

With a token in the environment rather than the keychain, prefix the command with git -c "http.extraHeader=Authorization: token $GITEA_TOKEN".

3. Build the image

The Dockerfile cross-compiles to x86_64-unknown-linux-musl from whatever architecture the builder runs on, so this is fast on Apple Silicon — no QEMU. --provenance=false --sbom=false matters: Unraid's Docker cannot load the attestation manifests BuildKit attaches by default.

docker build --pull --platform linux/amd64 --provenance=false --sbom=false -f deploy/docker/Dockerfile -t gitea.milesward.dev/mward4/openmfa:0.2 -t gitea.milesward.dev/mward4/openmfa:latest .

4. Push the image

Never run docker login or docker logout for gitea.milesward.dev on a Mac where git keeps the token in the keychain. Docker's osxkeychain credential helper maps to the same keychain item as git's: login fails with "The specified item already exists in the keychain (-25299)", and logout silently deletes the credential git was using, so the next git push fails with a bare 401. Write the auth into a throwaway config instead — a config that already contains an auths entry makes the CLI skip the helper:

export DOCKER_CONFIG="$(mktemp -d)" && printf '{"auths":{"gitea.milesward.dev":{"auth":"%s"}}}' "$(printf 'mward4:%s' "$GITEA_TOKEN" | base64 | tr -d '\n')" > "$DOCKER_CONFIG/config.json" && docker push gitea.milesward.dev/mward4/openmfa:0.2 && docker push gitea.milesward.dev/mward4/openmfa:latest; rm -rf "$DOCKER_CONFIG"; unset DOCKER_CONFIG

On a Colima host, export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock" first: an isolated DOCKER_CONFIG has no currentContext, and the CLI would otherwise look for /var/run/docker.sock.

On a fresh machine, scripts/build-and-publish-unraid.sh does the clone, build and push in one pass using that same private-config approach:

GITEA_TOKEN="$GITEA_TOKEN" ./scripts/build-and-publish-unraid.sh

5. Verify the pull

The repo is public, so this needs no credentials — which is exactly how Unraid will fetch it:

docker pull gitea.milesward.dev/mward4/openmfa:0.2

6. Deploy on Unraid

Add a container with Repository set to:

gitea.milesward.dev/mward4/openmfa:0.2

(or :latest). Map /var/lib/openmfa to /mnt/user/appdata/openmfa, publish port 8720, and leave networking on bridge. Or import deploy/unraid/openmfa.xml into /boot/config/plugins/dockerMan/templates-user/ to get all of that prefilled.

To upgrade an existing container, change the tag and apply. The vault, key, settings and admin account all live in the appdata mount and carry over.

Afterwards

If a token was exported, make sure it is not left in the shell:

unset GITEA_TOKEN