OpenClaw EnterpriseDOCSGitHub

Push-ref guardrail

Set pushRefAllowlist on a repository's Namespace policy in the credential registry to catch accidental branch pushes, such as pushing directly to main:

json
{  "namespaceId": "team",  "profiles": ["git-write", "git-full"],  "pushRefAllowlist": ["refs/heads/agent/*"]}

Use actual Namespace IDs. This example permits agent/feature but rejects main. The policy applies to every selected profile in that Namespace; it does not add token permissions or change GraphQL access.

Matching and delivery

The generated Git configuration selects image-owned hooks. Ordinary hooks in the repository's common Git directory still run, including for linked worktrees. Symlinks to the managed wrapper resolve from its installed location. A hook that links back to that wrapper is refused with recursive-repository-hook. Repository initialization works before the initial HEAD exists. Standalone sessions with this policy require the emitted client from pnpm credentials:build.

Enforce the ref policy at the gateway for a GitHub App

To give an Agent native Git read access and permission to push one review branch, set this policy on the repository in its Namespace's credential registry:

json
{  "namespaceId": "team",  "profiles": ["git-write"],  "transport": "git-only",  "pushRefAllowlist": ["refs/heads/review/example-123"]}

Select the github-prepared-git-registry backend for this policy. The Agent uses the ordinary git-write binding and a scoped gateway session. The prepared credential owner mints the repository-scoped GitHub App installation token in the background with metadata: read and contents: write. The gateway admits only Git discovery, fetch and push for this repository, and checks every proposed ref before sending any part of a push to GitHub. REST and GraphQL are unavailable through this session. The prepared backend requires exactly one branch ref; an omitted, empty, wildcard, or multi-ref allowlist is an error. Changing this transport or its ref changes the grant identity; close old sessions when narrowing access. See Prepared native Git for the credential lifecycle and deployment requirements.

The branch restriction is enforced by this gateway, not encoded in the provider token. The allowlist admits creation, updates, force pushes and deletion of the named branch, subject to the repository's own rules. Reading is repository-wide. Use a new disposable branch or a disposable repository with appropriate workflow and secret policies. This setting grants no Sandbox or network access on its own.

Gateway enforcement for the development token authority

With the development token authority, the same allowlist is also enforced by the gateway. It reads the receive-pack commands before any byte goes upstream and refuses the whole push with HTTP 400 when one ref fails, so --no-verify or a replaced core.hooksPath changes nothing. The client hook still gives the first, friendlier refusal. No admitted REST route writes refs, and GraphQL mutations are refused for this authority, so the allowlist bounds every ref write. The client hook alone is not a security boundary.

The gateway also limits one push to 256 refs and refuses a larger push with HTTP 413 push-ref-limit-exceeded, even when every ref is allowed. The client hook does not count refs, so this refusal comes from the gateway. Push the refs in batches of 256 or fewer.

Limits

The client hook is a convenience guardrail, not a security boundary. Native hook/config overrides, bypassing hooks, alternate clients, direct REST/GraphQL writes and merges are outside it. A custom core.hooksPath replaces the managed directory; custom hooks must explicitly chain the image dispatcher to retain the check. Use GitHub repository rules for server-side controls.

repository-push-ref-not-allowed means at least one destination is outside the allowlist. Choose an allowed branch. repository-pre-push-guard-failed means the guard could not safely check the push; a fixed reason code such as invalid-repository-material follows when one applies. Inspect the selected binding, session and hook configuration. Neither result forwards ref updates. Do not retry an uncertain remote mutation without inspecting its result. When a Pod's session material cannot be read, only pushes to plainly spelled HTTPS hosts other than every binding's gateway and canonical origin proceed; a single-session launcher refuses them all.

Other dispatcher failures print repository-hook-failed, the hook name and a reason code. Push-to-checkout refusals print Git's own reason, while the ref status reads push-to-checkout hook declined. A forwarded hook killed by a signal exits with 128 plus the signal number, as in Git, and the message names the hook instead of its path.

Search documentation