Skip to content

git: host-held credentials for model-driven clone, fetch, pull and push #218

Open

Description

@mattzcarey

The model-facing git entry points, which are the worker-shell git command and ws:git (cli, clone), have no way to authenticate. Host code can pass onAuth or headers on each GitClient call. A model running git push or git clone against a private repo can't, unless it puts a token on the command line, and then the token sits in the transcript.

@cloudflare/shell in cloudflare/agents had gitTools(ws, { token }) / { auth: { username, password } }. The host held the credential and added it to clone, fetch, pull, and push, so the model never saw it. We're deprecating Shell for Computer and need the same thing.

Proposal

Add a host-side auth resolver to the git client factory:

createGitClient({
  auth: (url) =>
    new URL(url).host === "github.com"
      ? { username: "x-access-token", password: env.GITHUB_TOKEN }
      : undefined,
});
  • clone, fetch, pull, push, and ls-remote call the resolver for every network request. That covers the typed client, git.cli, the worker-shell git command, and ws:git.
  • Auth passed explicitly on a call still wins over the resolver.
  • The credential never shows up in command output, error messages, .git/config, or remote URLs written to the repo.
  • The resolver takes the URL, so one workspace can hold different credentials for different hosts.

Activity

  1. github-actions commented on Oct 8, 2026

    @github-actions
    Contributor

    Thanks. This is a feature request: git.cli, the worker-shell git command and ws:git can't authenticate without a token on the command line. The CLI doesn't surface onAuth or headers. The proposal is a host-side auth resolver on createGitClient() that covers clone, fetch, pull, push and ls-remote. The likely area is packages/computer/src/git/ (client factory and cli.ts) plus the worker-shell git command. See docs/13_git_interface.md. I found no duplicate open issues.

  2. aron-cf commented on Oct 9, 2026

    @aron-cf
    Collaborator

    This is needed. Agents SDK also needs some sort of secret storage for this purpose too.

    @gardener-cf can you take a look at this and propose an interface, with usage examples, on this issue that works for both private repositories on GitHub & GitLab as well as the Cloudflare Artifacts registry.

  3. github-actions commented on Oct 9, 2026

    @github-actions
    Contributor

    @aron-cf I propose host-only auth(url,{operation}): Promise<GitAuth|undefined> on createGitClient; SDK supplies tenant-scoped encrypted secrets.get, inaccessible to models. Illustrative proposed usage, not shipped:

    const a = await artifacts.get("cache");
    const repos = {
      "https://github.com/acme/private.git": ["x-access-token", "github"],
      "https://gitlab.com/acme/private.git": ["oauth2", "gitlab"],
    };
    const git = createGitClient({
      auth: async (url, {operation}) => {
        if (url === a.remote) {
          const t = await artifacts.createToken("cache", operation === "push" ? "write" : "read", 300);
          return {username: "x", password: t.plaintext.split("?expires=")[0]};
        }
        const r = repos[url];
        return r ? {username: r[0], password: await secrets.get(r[1])} : undefined;
      },
    });
    const ws = new Workspace({storage: ctx.storage, git});
    for (const url of [...Object.keys(repos), a.remote])
      await ws.git.clone({url}); // independently, into separate directories

    Resolve every request across typed/CLI/shell/ws:git; explicit auth wins. Require HTTPS, redirect reauthorization, expiry refresh, clean config/URLs, and redacted errors. Artifacts’ current token-printing/credentialed-remote CLI needs a secret-free mode. ls-remote needs adding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions