Let gitea_api send only the query keys it needs, never sudo, and never approve a pull request

The confirmation review of 2026-10-09 measured GET /user?sudo=… answer the
operator's own account: the query went to the forge unjudged, and the tools'
token is the site administrator's, so any caller could act as any user.
gitea_api now sends only allow-listed query keys and refuses sudo in any case,
and a review that approves or requests changes is the operator's.
This commit is contained in:
jochen
2026-10-09 12:57:16 +02:00
parent ff648ad32b
commit ea772a9cce
3 changed files with 74 additions and 5 deletions
+3 -4
View File
@@ -14,7 +14,7 @@ import { GiteaClient, type BranchProtection } from "../client.js";
import { appendNote, deliveryStatus, run, viewBody, viewComment } from "../delivery.js";
import { containedFrom, isCommit, mergeableUnder, newestByContext } from "../checks.js";
import {
MERGE_METHODS, Refused, checkName, judgeApiCall, judgeContentsWrite, judgeDelete, judgeProtectionChange, routedPath,
MERGE_METHODS, Refused, checkName, judgeApiCall, judgeContentsWrite, judgeDelete, judgeProtectionChange, routedPath, sentQuery,
ruleCovers,
} from "../guard.js";
@@ -643,10 +643,9 @@ function allGiteaTools(gitea: GiteaClient): ToolDefinition[] {
await gitea.branchProtections(owner, repo));
if (refused) throw new Refused(refused);
}
// The path judged is the path sent: normalised, its query kept.
// The path judged is the path sent: normalised, with only the allow-listed query keys (guard.ts).
const raw = String(args.path ?? "");
const query = raw.includes("?") ? raw.slice(raw.indexOf("?")).split("#")[0] : "";
const result = await gitea.api(routedPath(raw) + query, {
const result = await gitea.api(routedPath(raw) + sentQuery(raw), {
method,
...(args.body ? { body: JSON.stringify(args.body) } : {}),
});