plans: row 199 design r5, the host derives each agent's fork from the upstream and its own Gitea user (webby-0011 N1), identity optional and required by publish (#1697)
This commit is contained in:
1 parent
12c85ada18
commit
34bfe4a53d
1 file changed
+25
-7
@@ -13,6 +13,14 @@ drops O2 (D10, A3, R2).
|
||||
r4 answers duckworth-0017 (REVIEW-r3.md at 4065ed59f): B3 in T3 and D9 step 5, B4 in D9 steps 1, 3 and 5, N6
|
||||
and N7 in D9a, N8 in D9 step 1.
|
||||
|
||||
r5 takes webby-0011 N1 (row 194 review, through honker-0009): the host checks at each push that the
|
||||
remote's owner is the agent's own Gitea user. r4 named one `remote` per project, which can't be a fork per
|
||||
agent (O1) once two agents publish the same project. So `projects.<p>.remote` now names the upstream
|
||||
repository, and the host builds each agent's fork URL from it (D9 step 2, D10, T3). It also fixes a conflict
|
||||
found while building: D8 made `identity` required for every agent whose definition declares `gitea`, while D9
|
||||
step 2 says today's files load unchanged. Coder declares `gitea`, so r5 makes `identity` optional and
|
||||
`publish` require it (D8).
|
||||
|
||||
## 0. Terms
|
||||
|
||||
- **Stack instance**: one Mosaic Stack deployment (row 190). It has one OS user, one config dir
|
||||
@@ -114,7 +122,8 @@ doesn't pick. A pi model credential also waits for P19 #383.
|
||||
## 5. Git identity and push (brief item 3)
|
||||
|
||||
D8. **Identity.** A new business-file key, `roles.<agent>.identity = {name, email, gitea: {url, user}}`. It is
|
||||
required when the role definition declares `gitea`. The sandbox sets `GIT_AUTHOR_*` and `GIT_COMMITTER_*` from
|
||||
optional, because today's business files with a `gitea` agent (coder) must load unchanged. `publish` (D9
|
||||
step 2) requires it, and requires that the definition declare `gitea`. The sandbox sets `GIT_AUTHOR_*` and `GIT_COMMITTER_*` from
|
||||
it in place of E7's invalid domain. The email is the one Jason gives the agent's Gitea user, so Gitea links the
|
||||
commits to that user. Agents without `gitea` keep E7.
|
||||
|
||||
@@ -146,9 +155,14 @@ The host checks, in order, and each refusal goes through `broker.refuse()`:
|
||||
reviewed commit adds it to both ROUTED lists and to coder's `withinRole`. From then on a coder publishes
|
||||
without a decision, and `decision` is optional for a within-role class only.
|
||||
2. The project is in the agent's grant, `roles.<agent>.publish: [project]`, and the business file names the
|
||||
project's remote, `projects.<project>.remote: "https://..."` (`remote-not-granted`). The remote's scheme is
|
||||
https and its host and port equal `identity.gitea.url`'s (`remote-host-mismatch`). The default https port
|
||||
counts as 443 on both sides. `remote` is a new key
|
||||
project's upstream repository, `projects.<project>.remote: "https://HOST/OWNER/REPO"`
|
||||
(`remote-not-granted`). Its scheme is https and its host and port equal `identity.gitea.url`'s
|
||||
(`remote-host-mismatch`). The default https port counts as 443 on both sides. The host never pushes to
|
||||
that URL. It builds the agent's fork, `https://HOST[:PORT]/<gitea.user>/REPO`, from the upstream's
|
||||
origin and repository name and the agent's own `gitea.user`, and pushes there. So the remote's owner is
|
||||
the agent's own Gitea user on every push, by construction, and the agent can't name it (webby-0011 N1).
|
||||
Gitea's refusal of a push to a repository the user doesn't own or collaborate on is the second layer.
|
||||
An upstream whose owner is the agent's own user refuses `remote-not-fork`, at load and at push. `remote` is a new key
|
||||
beside `root` and `repo` (`business.mjs:186`), and `identity` and `publish` are new keys on a role entry
|
||||
(`business.mjs:89`). All three are optional, so today's business files load unchanged.
|
||||
3. The source is one commit, `C = context.pushCommit`. It is checked three ways, so all three are equal:
|
||||
@@ -203,7 +217,8 @@ The op table gets no entry that returns a token.
|
||||
D10. **Which refs.** Our side: only `refs/heads/<gitea.user>/*`, set by the host (D9 step 3). The default
|
||||
branch and other agents' prefixes can't be named. Gitea side, two options (Q-M1):
|
||||
|
||||
- **O1. A fork per agent. Ruled by Mos (mos-1027).** The agent's Gitea user has read on the upstream repo and owns a fork.
|
||||
- **O1. A fork per agent. Ruled by Mos (mos-1027).** The agent's Gitea user has read on the upstream repo and owns a fork
|
||||
named like it. The host derives the fork's URL from the upstream and the agent's user (D9 step 2).
|
||||
Its token can write only repos the user owns or collaborates on, so Gitea itself stops any push to upstream
|
||||
or to another agent's fork. No branch rules are needed per agent, so none can drift. The cost: work reaches
|
||||
upstream as a pull request from the fork, opened by a human or a later API verb.
|
||||
@@ -327,7 +342,9 @@ All tests use scratch roots, fake tokens and a fake Gitea: `git http-backend` be
|
||||
and that no `roles/*.json` grants it. A force-push attempt is
|
||||
refused by git's non-fast-forward. A fake remote that answers 302 to a second 127.0.0.1 port: the push
|
||||
fails, and the second port receives no request with an Authorization header. A remote on the right host
|
||||
and a different port is refused at step 2. A first publish to an empty remote and to an unrelated remote
|
||||
and a different port is refused at step 2. Two agents granted one project each land on their own fork:
|
||||
agent A's push reaches `/<A's user>/REPO` only and B's reaches `/<B's user>/REPO` only, and the fake's
|
||||
upstream repository receives nothing. An upstream owned by the agent's own user refuses `remote-not-fork`. A first publish to an empty remote and to an unrelated remote
|
||||
each refuse `remote-unrelated`, and the fake remote receives no objects.
|
||||
- T4. Token handoff: the token never appears in argv, env, the remote URL, the working repo config,
|
||||
`changes.jsonl`, events or logs (scan every file under the scratch roots).
|
||||
@@ -342,7 +359,8 @@ check, allow a `{file}` reference into another agent's dir, make ENOENT on a `st
|
||||
ENOENT on a `{file}` path silent, a helper that answers any host, drop `http.followRedirects=false`, drop the
|
||||
`work-not-yours` check, drop the `remote-unrelated` check, add `git.push.remote` to ROUTED, skip the spent
|
||||
check on the decision, drop the `pushCommit` comparison in `#authorityFor`, push by ref name in place of the
|
||||
oid, skip the tip check under the lock, and pass a CA flag in production.
|
||||
oid, push to the upstream URL in place of the derived fork, take the fork's owner from anywhere but the agent's
|
||||
`gitea.user`, skip the tip check under the lock, and pass a CA flag in production.
|
||||
|
||||
## 12. Risks
|
||||
|
||||
|
||||
Reference in new issue
Block a user