New tools/gitea/client-access.md: the credential file (~/.config/secrets/gitea, 0600) behind a global 'store --file' helper, the git 2.56 credential-store trap (the key=value block shape parses to an empty get; the file must be one http://user:token@host:port URL per line), the GIT_TERMINAL_PROMPT=0 verification loop, the lfs.locksverify key that silences the URL echo, and the rotation procedure. Cross-linked from the gitea index and management pages. Both workstation remotes are now bare URLs; the token lives in one file.
99 lines
3.5 KiB
Markdown
99 lines
3.5 KiB
Markdown
---
|
|
type: reference
|
|
title: Gitea Client Access
|
|
description: Token-based HTTP access from client workstations — the credential store layout, the git 2.56 store-format trap, and the verification loop.
|
|
tags:
|
|
- gitea
|
|
- git
|
|
- secrets
|
|
verified: 2026-10-09
|
|
---
|
|
|
|
# Gitea Client Access
|
|
|
|
Clients (workstations, agent hosts) reach Gitea over plain HTTP on the LAN:
|
|
`http://192.168.0.143:3000/dank/<repo>.git`. Authentication is a Gitea HTTP token sent as
|
|
the password for user `dank`. SSH is available on `:2222` (see
|
|
[[architecture|architecture]]); HTTP + token is what the agent hosts use.
|
|
|
|
## The law: the token never enters a URL, a config file, or a shell rc
|
|
|
|
A remote URL of the shape `http://dank:<token>@host/org.git` stores the credential in
|
|
`.git/config`, which is copied by every clone, printed by `git remote -v`, and echoed by
|
|
the LFS lock warning during `git push`. Keep the URL bare:
|
|
|
|
```
|
|
http://192.168.0.143:3000/dank/command-center.git
|
|
```
|
|
|
|
The credential lives in one file, mode 0600, outside every repository:
|
|
|
|
| Item | Value |
|
|
|---|---|
|
|
| Credential file | `~/.config/secrets/gitea` (0600, dir 0700) |
|
|
| Helper (global) | `git config --global credential.helper 'store --file ~/.config/secrets/gitea'` |
|
|
| Scope | every repo on the host that talks to `192.168.0.143:3000` |
|
|
|
|
## The git 2.56 store-format trap
|
|
|
|
`git credential fill` **reads** `protocol=`/`host=`/`username=`/`password=` blocks on
|
|
stdin, and the man page shows the same shape for `~/.git-credentials`. `git
|
|
credential-store` (git 2.56.0, verified) does **not** parse that shape in the file: a
|
|
key=value block yields a silent empty `get`, so git falls through to askpass and dies with
|
|
`could not read Username`. Write the file as one URL per line:
|
|
|
|
```
|
|
http://dank:<token>@192.168.0.143:3000
|
|
```
|
|
|
|
The host line must carry the port (`192.168.0.143:3000`) — git keys the lookup on
|
|
`protocol` + `host:port`.
|
|
|
|
Verify the file answers before trusting it, with prompts disabled so a failure is loud
|
|
rather than a hang:
|
|
|
|
```
|
|
printf 'protocol=http\nhost=192.168.0.143:3000\n\n' | git credential-store --file ~/.config/secrets/gitea get
|
|
```
|
|
|
|
Two lines come back (`username=`, `password=`). Silence means the format is wrong.
|
|
|
|
## Verification loop
|
|
|
|
Run every step with `GIT_TERMINAL_PROMPT=0`; anything that needs the token from a file the
|
|
helper cannot read fails immediately instead of blocking on a prompt.
|
|
|
|
```
|
|
GIT_TERMINAL_PROMPT=0 git ls-remote --heads origin main # read auth
|
|
GIT_TERMINAL_PROMPT=0 git push --dry-run origin main # write auth
|
|
git remote get-url origin # no '@' present
|
|
grep -rl '<token>' ~/.gitconfig */.git/config # no plaintext copies
|
|
```
|
|
|
|
## LFS lock warning
|
|
|
|
`git push` on a repo with git-lfs prints `Locking support detected on remote … info/lfs.locksverify true`
|
|
and echoes the remote URL — one more place a URL-embedded token leaks. Silence it per
|
|
repo with the bare URL:
|
|
|
|
```
|
|
git config lfs.http://192.168.0.143:3000/dank/<repo>.git/info/lfs.locksverify true
|
|
```
|
|
|
|
## Rotating the token
|
|
|
|
Rotate in the Gitea UI (Settings → Applications), then rewrite only the credential file:
|
|
|
|
```
|
|
umask 077 && printf 'http://dank:%s@192.168.0.143:3000\n' '<new-token>' > ~/.config/secrets/gitea
|
|
```
|
|
|
|
Nothing else changes: no remote URL, no rc file, no repository. The old token remains valid
|
|
until it is deleted in the UI, so delete it there as part of the rotation.
|
|
|
|
## See Also
|
|
|
|
- [[index|index]] — Gitea on dankclaw
|
|
- [[management|management]] — server-side operations
|
|
- [[architecture|architecture]] — ports (3000 HTTP, 2222 SSH) and the Caddy front
|