Grant GitHub Push Access to a Sandboxed Agent

View as Markdown

This tutorial shows how provider access and sandbox policy work together. You attach a GitHub provider that contributes read-only GitHub access, observe a denied push, and add a user policy that permits writes to one repository.

The built-in default policy does not grant network access. Imported provider profiles contribute the endpoints and executable paths needed by their providers.

Prerequisites

You need:

  • A working OpenShell installation and active gateway.
  • An OCI image you built with Claude Code, git, and the GitHub CLI installed.
  • An Anthropic API key.
  • A GitHub fine-grained personal access token with read and write access to the target repository’s contents.
  • A scratch GitHub repository that you can push to.

Use two host terminals. Terminal 1 runs the agent. Terminal 2 inspects denials and updates policy.

1

Import the Provider Profiles

Review the Claude Code profile and GitHub profile. Confirm that their binaries paths match the executables in your image, then import them directly. If a path or endpoint grant needs to change, edit a local copy and import it with -f instead.

openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/claude-code.yaml --global
openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/github.yaml --global

The gateway contains no built-in profiles. Import each profile once per gateway at the scope where users need it.

2

Create the Providers

Create provider instances from credentials in your host environment. Passing a credential on the same command line exports it only to that command:

ANTHROPIC_API_KEY=<your-anthropic-key> \
openshell provider create --name my-claude --type claude-code --from-existing
GITHUB_TOKEN=<your-github-token> \
openshell provider create --name my-github --type github --from-existing

OpenShell stores the credentials through the configured credential driver. The agent receives opaque placeholders; the sandbox proxy resolves them only for endpoints allowed by the corresponding profile.

3

Start the Agent

In terminal 1, start Claude Code from your image and attach both providers:

openshell sandbox create \
--name github-demo \
--from registry.example.com/your-org/claude-agent:latest \
--provider my-claude \
--provider my-github \
-- claude

To use an existing sandbox, attach the providers from a host terminal, then start a new agent process so it receives the provider environment variables:

openshell sandbox provider attach <sandbox-name> my-claude
openshell sandbox provider attach <sandbox-name> my-github
openshell sandbox connect <sandbox-name>
4

Attempt a Push

Ask the agent to create a file and push it to your scratch repository. Replace <org> and <repo> with the repository owner and name:

Prompt
Create `hello_world.py`, commit it, and push it to
`https://github.com/<org>/<repo>.git`. Use the GitHub credentials already
available in the environment. Do not ask me to paste a token.

The push fails. The GitHub profile permits clone and fetch operations but does not permit git-receive-pack, the Git Smart HTTP operation used for a push. The credential remains attached and endpoint-scoped; changing the token would not grant the missing network authority.

5

Inspect the Denial

In terminal 2, inspect recent sandbox logs:

openshell logs github-demo --since 5m --source sandbox

You should see a denial for a request resembling this one:

[1775014140.412] [sandbox] [OCSF ] [ocsf] HTTP:POST [MED] DENIED POST http://github.com:443/<org>/<repo>.git/git-receive-pack [policy:_provider_my_github engine:l7] [reason:L7_REQUEST deny POST github.com:443/<org>/<repo>.git/git-receive-pack reason=POST /<org>/<repo>.git/git-receive-pack not permitted by policy]

_provider_my_github is the rule that OpenShell composes from the attached my-github provider. Policy events are INFO-level log records, so do not filter them out with --level warn.

You can also run openshell term to inspect policy decisions in the terminal dashboard.

6

Create a Repository-Scoped Policy

policy set replaces the complete base policy, so start from the sandbox’s current one. In terminal 2, print it:

openshell policy get github-demo --base

The command prints revision details followed by the policy. Save only the policy YAML as github-push.yaml. Keep its filesystem, Landlock, and process settings unchanged, because OpenShell rejects removed filesystem paths and changed Landlock or process settings on a running sandbox.

Add these entries under network_policies, creating the section if it is missing. Replace <org> and <repo>, and adjust binaries to match your image:

network_policies:
github_repository_push:
name: github-repository-push
endpoints:
- host: github.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow:
method: GET
path: "/<org>/<repo>.git/info/refs*"
- allow:
method: POST
path: "/<org>/<repo>.git/git-upload-pack"
- allow:
method: POST
path: "/<org>/<repo>.git/git-receive-pack"
binaries:
- path: /usr/bin/git
- path: /usr/local/bin/git
github_repository_api:
name: github-repository-api
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow:
method: "*"
path: "/repos/<org>/<repo>/**"
binaries:
- path: /usr/bin/gh
- path: /usr/local/bin/gh

The first entry grants Git Smart HTTP operations only for the selected repository. The second lets gh use REST operations scoped to the same repository. The attached GitHub provider continues to supply credential placement and its broader read-only rules.

7

Apply the Policy

Apply the policy and wait for the new revision to load:

openshell policy set github-demo --policy github-push.yaml --wait

Network policy changes hot-reload without recreating the sandbox. Provider rules are composed with this user-authored base policy.

8

Retry and Verify

Ask the agent to retry the push. Then confirm that the proxy allowed the scoped request:

openshell logs github-demo --since 5m
openshell policy get github-demo --full

The push succeeds for the selected repository. Requests to push to another repository remain denied.

9

Clean Up

Delete the sandbox when you are finished:

openshell sandbox delete github-demo

Next Steps