Files
Radix-Skills/skills/devops/gitea-issue-agent/references/identity-and-safety.md
T
dennis 236053cd7f Initial import: 10 Radix skills across 3 categories
Kategoriserer danske regnskabs-/ERP-skills, ERP-data-afstemnings-
skill og to devops-workflows (gitea-issue-agent, kanban-workflows)
som Radix-medlemmers AI-agenter kan dele.

Struktur:
  skills/<kategori>/<skill-navn>/SKILL.md
  skills/<kategori>/<skill-navn>/{references,templates,scripts}/

Indekseret af index.json (genereret af scripts/rebuild_index.py).
Kør `python3 scripts/rebuild_index.py --check` i CI for at fange
synkroniseringsfejl.
2026-06-15 14:41:04 +02:00

102 lines
4.5 KiB
Markdown

# Identity and safety in the Gitea issue agent
## Two identities, one Gitea server
The setup has two Gitea users that should remain separate:
| Identity | Token stored in | Used for | What it posts |
| --- | --- | --- | --- |
| **Service-bruger** (e.g. `hermes-issues`) | `GITEA_TOKEN` in `~/.hermes/.env` | All plugin tool calls: scan, comment, create PR | Comments and PRs attributed to the bot |
| **Personal user** (e.g. `dennis`) | `tea` login + `~/.netrc` | Local `git push` of branches the agent created | Commits and merges attributed to you |
The plugin's `gitea_agent_status` reports `authenticated_user`. If it
reports your personal login, the bot will post comments as you — fix
the `GITEA_TOKEN` before scheduling any cron job.
## Why the Hermes safety-guards exist (and why the agent can't bypass them)
Hermes has three layers of "agent cannot edit" protection, all by
design:
1. **`~/.hermes/config.yaml`** — gates plugin load, model selection,
toolsets, gateway config. An agent that could rewrite this could
give itself new tools, change providers, or open outbound network
channels. The `patch` tool explicitly refuses:
`Refusing to write to Hermes config file: ... Agent cannot modify
security-sensitive configuration.`
2. **`~/.hermes/.env`** — contains API keys, tokens, passwords. The
`write_file`, `patch`, and `execute_code` tools all refuse to
modify it.
3. **`execute_code` with file writes** — when a script is going to
write files under `~/.hermes/`, the safety guard blocks it
unconditionally: `BLOCKED: execute_code script timed out without
user response.`
**The right move when blocked:** give the user the exact one-line
edit (or `cat > file <<EOF ... EOF` block) and stop. Do not try
alternative tools, do not retry, do not work around it. The user
must run the edit themselves.
This is not a bug. It is the threat model.
## Approval-gate design rationale
The agent should never implement, push, or open a PR for an issue
that hasn't been approved. This protects against three classes of
mistake:
1. **Misread issue** — the user wanted "fix the X button", the agent
rewrote `X()` in 14 files. Approval forces a human to look at the
proposal first.
2. **Out-of-scope issue** — the user wanted to push back, not fix.
Approval makes "no" cheap (just don't reply).
3. **Bad agent day** — the LLM hallucinated, the issue got a wrong
proposal, the agent is in a weird state. Approval makes the loop
recoverable without reverting commits.
The two state markers (`proposal`, `pr_ready`) survive Hermes
restarts, plugin reloads, and Gitea restarts, because they live in
the issue's comment history. The agent never has to remember
anything to resume — it can re-scan and pick up where it left off.
## Approval matching — why it requires a known login by default
The default approval regex is permissive enough to handle Danish
("godkend", "godkender") and English ("approve", "approved", "ok",
"go") in either order with the agent mention. But without a
known-login check, **any user** with write access to the repo could
say "looks good, agent" in a comment and trigger a push. That's a
prompt-injection vector — a malicious screenshot, or a co-worker
joking, could authorize code execution.
Two safe modes:
- **Label-only mode** (the default until `GITEA_APPROVER_LOGIN` is
set): a maintainer applies one of three labels. Labels can only
be applied by users with write access, so the trust surface is
the maintainer set, not "anyone who can comment".
- **Login-gated mode** (once `GITEA_APPROVER_LOGIN` is set): a
comment from that specific user, matching the regex, AND
after the latest proposal comment. This is the strict mode.
If the user wants both, both work — labels OR login-comment. If they
want neither (auto-implement everything), they should set both
`GITEA_APPROVER_LOGIN` and approve a *meta-issue* saying "always
implement" — but that's not the default and not recommended.
## The first run is always manual
Before scheduling a cron, the user must:
1. Run a manual `gitea_issue_agent_scan` and confirm issues show up.
2. Pick a real issue and walk it through: scan → fetch images →
analyze → propose → wait → approve → implement → test → push →
PR.
3. Confirm the PR body links to the issue, the commit message is
reasonable, and `git log` shows the expected author/email.
4. **Then** schedule a cron. The cron prompt itself should be
minimal — "scan, propose for new issues, implement approved" —
with a clear hand-off to the skill for the details.