Stop agents from using the broker run token as a GitHub password (#212)
Agents kept configuring git with RAKAZO_GITHUB_BROKER_RUN_TOKEN as a password because the system prompt listed it among "managed credentials" to use in shell commands. GitHub rejects it, and the agent then asks the user for a personal access token. - List only the user's own agent secrets in that instruction; the broker variables stay in the environment for the git shim. - Make /usr/bin/git the shim as well, so git called by absolute path still goes through the broker; the real binary moves out of PATH. - Prompt no longer names the broker variable. Claude-Session: https://claude.ai/code/session_01Tgvrj34NMnaqvtgvruYQZZ Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d962e5e7f4
commit
f136451e22
@ -52,7 +52,11 @@ WORKDIR /home/rakazo
|
||||
# --chmod normalizes modes: a restrictive host umask (e.g. 077 on hardened hosts) would
|
||||
# otherwise leave these files unreadable to USER 1000 at runtime.
|
||||
COPY --chmod=755 bin/rakazo-git bin/rakazo-gh bin/rakazo-broker /usr/local/lib/rakazo/bin/
|
||||
RUN ln -sf /usr/local/lib/rakazo/bin/rakazo-git /usr/local/lib/rakazo/bin/git \
|
||||
# /usr/bin/git is the shim too, so calling git by absolute path still goes through the broker.
|
||||
RUN mkdir -p /usr/local/libexec/rakazo \
|
||||
&& mv /usr/bin/git /usr/local/libexec/rakazo/git \
|
||||
&& ln -sf /usr/local/lib/rakazo/bin/rakazo-git /usr/bin/git \
|
||||
&& ln -sf /usr/local/lib/rakazo/bin/rakazo-git /usr/local/lib/rakazo/bin/git \
|
||||
&& ln -sf /usr/local/lib/rakazo/bin/rakazo-gh /usr/local/lib/rakazo/bin/gh
|
||||
COPY --chmod=755 start.sh /usr/local/bin/rakazo-computer
|
||||
COPY --chmod=755 control.py /usr/local/bin/rakazo-computer-control
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
REAL_GIT=/usr/bin/git
|
||||
REAL_GIT=/usr/local/libexec/rakazo/git
|
||||
if [[ "${RAKAZO_GITHUB_BROKER_URL:-}" == "" || "${RAKAZO_GITHUB_BROKER_RUN_TOKEN:-}" == "" ]]; then
|
||||
exec "$REAL_GIT" "$@"
|
||||
fi
|
||||
|
||||
@ -10,3 +10,5 @@ done
|
||||
docker run --rm "$IMAGE" bash -c 'git --version | grep -q "^git version "'
|
||||
docker run --rm "$IMAGE" bash -c 'gh --version | grep -q "^gh version "'
|
||||
docker run --rm "$IMAGE" bash -c 'test "$(command -v git)" = "/usr/local/lib/rakazo/bin/git"'
|
||||
docker run --rm "$IMAGE" bash -c 'test "$(readlink /usr/bin/git)" = "/usr/local/lib/rakazo/bin/rakazo-git"'
|
||||
docker run --rm "$IMAGE" bash -c '/usr/bin/git --version | grep -q "^git version "'
|
||||
|
||||
@ -217,7 +217,7 @@ describe("formatConnectionsInstruction", () => {
|
||||
const line = formatGithubGitInstruction(["GitHub"]);
|
||||
expect(line).toMatch(/Clone private repositories with git/);
|
||||
expect(line).toMatch(/Never ask the user for a personal access token/);
|
||||
expect(line).toMatch(/RAKAZO_GITHUB_BROKER_RUN_TOKEN is not a GitHub token/);
|
||||
expect(line).toMatch(/never put a token into URLs, credential helpers, or git config/);
|
||||
});
|
||||
|
||||
it("says plainly when nothing is connected", () => {
|
||||
|
||||
@ -79,7 +79,7 @@ export const ROUTINE_RUN_INSTRUCTION =
|
||||
export function formatGithubGitInstruction(connectedApps: readonly string[]): string | undefined {
|
||||
const hasGithub = connectedApps.some((app) => app.trim().toLowerCase() === "github");
|
||||
if (!hasGithub) return undefined;
|
||||
return "GitHub is connected. Clone private repositories with git on your computer (authentication is brokered) or use the GitHub integration tools for issues, pull requests, and repository APIs. Plain `git clone https://github.com/owner/repo` works; RAKAZO_GITHUB_BROKER_RUN_TOKEN is not a GitHub token, so never put it or any token into URLs, credential helpers, or git config. Never ask the user for a personal access token, password, or SSH key for GitHub.";
|
||||
return "GitHub is connected. Clone private repositories with git on your computer (authentication is brokered) or use the GitHub integration tools for issues, pull requests, and repository APIs. Plain `git clone https://github.com/owner/repo` works as is; never put a token into URLs, credential helpers, or git config. Never ask the user for a personal access token, password, or SSH key for GitHub.";
|
||||
}
|
||||
|
||||
export function formatConnectionsInstruction(input: {
|
||||
|
||||
@ -1221,15 +1221,17 @@ export function createRunExecutor(deps: ExecutorDeps) {
|
||||
containerRoot: projectWorkspacePath ? "/home/rakazo/project" : "/home/rakazo",
|
||||
}).catch(() => undefined);
|
||||
}
|
||||
const agentSecrets = decryptAgentEnvironment(agentSecretRows, deps.secretStore);
|
||||
const agentEnvironment = {
|
||||
...decryptAgentEnvironment(agentSecretRows, deps.secretStore),
|
||||
...agentSecrets,
|
||||
...githubIntegrationEnvironmentForRun({
|
||||
runId,
|
||||
githubToken: githubIntegrationToken,
|
||||
}),
|
||||
};
|
||||
runSecrets.push(...Object.values(agentEnvironment));
|
||||
const agentEnvironmentInstruction = formatAgentEnvironmentInstruction(agentEnvironment);
|
||||
// The broker variables are plumbing for the git shim; naming them invites the model to use them as a GitHub token.
|
||||
const agentEnvironmentInstruction = formatAgentEnvironmentInstruction(agentSecrets);
|
||||
const hasModelOverride = Boolean(bot.modelProvider && bot.modelId);
|
||||
const overrideCredential =
|
||||
hasModelOverride && bot.modelProvider
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user