agents: per-agent Gitea identity — each agent uses its own token
Drop the shared AGENT_TOKEN as the primary credential; every agent now acts as its own Gitea user (TOKEN_PM for @pm, TOKEN_OPS for @ops, …) for API calls, delegation/autopilot trigger comments, and PR merges. - agent.yml: Run-agent step injects SELF_TOKEN — a ternary selecting the running agent's own token by name, falling back to AGENT_TOKEN for repos not yet migrated to per-agent tokens (e.g. homelab). Only that one token enters the agent process, so no agent can act as another. The gitea-api / gitea-admin skill-setup steps no longer carry a token (they only write docs). - Gate: trust the agent roster (pm/junior/senior/lead/qa/ops) as comment authors so an agent's own delegation/autopilot trigger comment (posted with its PAT, no 🤖 prefix) fires the next run. @ops added to the mention set. - publish.sh: TOK = agent identity (comments/replies); new TTOK = trigger/merge token (agent PAT, else AGENT_TOKEN fallback) for delegation, autopilot @qa triggers, and PR merges that must fire downstream workflows. - skill-gitea-api.sh / skill-gitea-admin.sh / run-agent.sh: AGENT_TOKEN/ TOKEN_OPS → SELF_TOKEN in the emitted skill docs and env contract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e53e5caf8c
commit
06f1924441
@@ -1,19 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Set up `gitea-api` skill (let agents read/write issues, PRs, Actions across repos).
|
||||
# Mirrors the node1-ssh pattern: emit an opencode Skill file under
|
||||
# ~/.config/opencode/skills/ so any dev agent discovers the capability via OpenCode's
|
||||
# skill registry. The credential is the shared AGENT_TOKEN (a PAT whose scopes the
|
||||
# maintainer set at creation time — issue/repository/organization/misc read+write, cross-repo).
|
||||
# Only emitted when AGENT_TOKEN is actually present, so repos without it don't get a
|
||||
# broken skill. The token is passed via env and never inlined into shell.
|
||||
# Emits an opencode Skill file under ~/.config/opencode/skills/. The credential is SELF_TOKEN — the
|
||||
# RUNNING agent's OWN token (e.g. TOKEN_PM for @pm), present in the Run-agent step's env. So each
|
||||
# agent talks to Gitea as itself, with its own scopes. This step only writes the doc, so it always
|
||||
# emits; permission.skill decides which agents may actually load it.
|
||||
#
|
||||
# Required env (provided by the workflow step): AGENT_TOKEN
|
||||
# Required env (provided by the workflow step): (none — the token is in the Run-agent step)
|
||||
set -eu
|
||||
|
||||
if [ -z "$AGENT_TOKEN" ]; then
|
||||
echo "AGENT_TOKEN not set — skipping gitea-api skill"
|
||||
exit 0
|
||||
fi
|
||||
mkdir -p ~/.config/opencode/skills/gitea-api && chmod 700 ~/.config/opencode/skills/gitea-api
|
||||
cat > ~/.config/opencode/skills/gitea-api/SKILL.md <<'SKILLET'
|
||||
---
|
||||
@@ -33,14 +27,14 @@ Use this skill to talk to the **Gitea REST API** (`${GITHUB_SERVER_URL}/api/v1`)
|
||||
|
||||
## How it works
|
||||
|
||||
Calls go via `curl` with the header `Authorization: token ${AGENT_TOKEN}`. Both
|
||||
Calls go via `curl` with the header `Authorization: token ${SELF_TOKEN}`. Both
|
||||
`${GITHUB_SERVER_URL}` (the instance root, e.g. `https://git.example.com`) and
|
||||
`${AGENT_TOKEN}` are present in your environment. The API root is
|
||||
`${SELF_TOKEN}` are present in your environment. The API root is
|
||||
`${GITHUB_SERVER_URL}/api/v1`.
|
||||
|
||||
## What you're actually allowed to do — the token's scopes are the source of truth
|
||||
|
||||
The shared `AGENT_TOKEN` was granted **read and write** on the `issue`,
|
||||
The shared `SELF_TOKEN` was granted **read and write** on the `issue`,
|
||||
`repository`, `organization`, and `misc` scope groups, **cross-repo** (any repo the
|
||||
token's account can see). That covers:
|
||||
- issues, PRs, comments, labels, milestones, reviewers (read + write)
|
||||
@@ -64,9 +58,9 @@ in `agent.yml` exists to enforce.
|
||||
|
||||
## Never echo the token
|
||||
|
||||
**Never print, log, or exfiltrate `AGENT_TOKEN`.** Do not pass it to `echo`, do not
|
||||
**Never print, log, or exfiltrate `SELF_TOKEN`.** Do not pass it to `echo`, do not
|
||||
include it in a comment, do not write it to a file. If you need to show a curl command,
|
||||
redact the header as `Authorization: token $AGENT_TOKEN`.
|
||||
redact the header as `Authorization: token $SELF_TOKEN`.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -77,9 +71,9 @@ All examples assume `API="${GITHUB_SERVER_URL}/api/v1"`.
|
||||
```bash
|
||||
API="${GITHUB_SERVER_URL}/api/v1"
|
||||
# Get issue/PR #12 on repo owner/repo (a PR if the number is a pull; issues/PRs share one number space)
|
||||
curl -sS -H "Authorization: token $AGENT_TOKEN" "$API/repos/owner/repo/issues/12" | jq '{title,state,body,user:.user.login}'
|
||||
curl -sS -H "Authorization: token $SELF_TOKEN" "$API/repos/owner/repo/issues/12" | jq '{title,state,body,user:.user.login}'
|
||||
# Its comment thread
|
||||
curl -sS -H "Authorization: token $AGENT_TOKEN" "$API/repos/owner/repo/issues/12/comments?limit=100" \
|
||||
curl -sS -H "Authorization: token $SELF_TOKEN" "$API/repos/owner/repo/issues/12/comments?limit=100" \
|
||||
| jq -r '.[] | "### @\(.user.login):\n\(.body)\n"'
|
||||
```
|
||||
|
||||
@@ -91,27 +85,27 @@ find the owner/repo for a `#N` in *this* repo, just use `${GITHUB_REPOSITORY}`.
|
||||
```bash
|
||||
API="${GITHUB_SERVER_URL}/api/v1"
|
||||
# Recent runs on a repo
|
||||
curl -sS -H "Authorization: token $AGENT_TOKEN" "$API/repos/owner/repo/actions/runs?limit=10" | jq '.[] | {id,status,conclusion,head_branch,event}'
|
||||
curl -sS -H "Authorization: token $SELF_TOKEN" "$API/repos/owner/repo/actions/runs?limit=10" | jq '.[] | {id,status,conclusion,head_branch,event}'
|
||||
# Jobs for a run
|
||||
curl -sS -H "Authorization: token $AGENT_TOKEN" "$API/repos/owner/repo/actions/runs/$RUN_ID/jobs" | jq '.[] | {name,status,conclusion}'
|
||||
curl -sS -H "Authorization: token $SELF_TOKEN" "$API/repos/owner/repo/actions/runs/$RUN_ID/jobs" | jq '.[] | {name,status,conclusion}'
|
||||
# Logs for a job (returns a text/plain stream)
|
||||
curl -sS -H "Authorization: token $AGENT_TOKEN" "$API/repos/owner/repo/actions/jobs/$JOB_ID/logs"
|
||||
curl -sS -H "Authorization: token $SELF_TOKEN" "$API/repos/owner/repo/actions/jobs/$JOB_ID/logs"
|
||||
```
|
||||
|
||||
### List repos across an org
|
||||
|
||||
```bash
|
||||
curl -sS -H "Authorization: token $AGENT_TOKEN" "$API/orgs/$ORG/repos?limit=50" | jq '.[] | .full_name'
|
||||
curl -sS -H "Authorization: token $SELF_TOKEN" "$API/orgs/$ORG/repos?limit=50" | jq '.[] | .full_name'
|
||||
```
|
||||
|
||||
### Write: comment / label / close on another repo's issue (only when your task requires it)
|
||||
|
||||
```bash
|
||||
curl -sS -X POST -H "Authorization: token $AGENT_TOKEN" -H "Content-Type: application/json" \
|
||||
curl -sS -X POST -H "Authorization: token $SELF_TOKEN" -H "Content-Type: application/json" \
|
||||
"$API/repos/owner/repo/issues/12/comments" -d '{"body":"related to #N"}'
|
||||
curl -sS -X POST -H "Authorization: token $AGENT_TOKEN" -H "Content-Type: application/json" \
|
||||
curl -sS -X POST -H "Authorization: token $SELF_TOKEN" -H "Content-Type: application/json" \
|
||||
"$API/repos/owner/repo/issues/12/labels" -d '{"labels":["related"]}'
|
||||
curl -sS -X PATCH -H "Authorization: token $AGENT_TOKEN" -H "Content-Type: application/json" \
|
||||
curl -sS -X PATCH -H "Authorization: token $SELF_TOKEN" -H "Content-Type: application/json" \
|
||||
"$API/repos/owner/repo/issues/12" -d '{"state":"closed"}'
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user