Skip to content
Git proxy

Git proxy

Sandboxes clone, fetch and push only through the gateway’s Git smart-HTTP proxy. The proxy holds the forge credential, restricts what a run may push, checks every pushed commit and records every push.

    flowchart LR
  R["Runtime / git<br/>(sandbox)"] -- "https://gateway:8443/git/DF-12.git<br/>no credential" --> P["Git proxy"]
  P -- "source IP → run → task" --> P
  P -- "checks, push record" --> CP["Control plane"]
  P -- "forge credential" --> F["Forge"]
  

Endpoint and caller

The proxy serves https://<gateway>:8443/git/<TASK-KEY>.git with a certificate from the instance CA (fetch with protocol v2 and partial clone, and push). It identifies the run by the source pod IP; an unknown source, or a path naming another task than the run’s, gets 403. Until the gateway has its first policy snapshot it answers 503, which the runtime retries.

Credential injection

The proxy forwards to the project’s repository URL with the project’s forge credential. It drops any Authorization header from the client, and never returns the credential to the client or writes it to a log. The runtime’s Git configuration has no credential helper, so nothing in the sandbox could hold a credential either.

http:// repositories get no route unless the instance setting forge.allowPlainHttp is on; the sandbox always talks HTTPS to the gateway.

Allowed ref updates

A push is forwarded only if every ref update is:

RefAllowed update
refs/heads/factory/task/<KEY>create or fast-forward
refs/heads/factory/wip/<KEY>create, update or delete (the WIP snapshot)

Anything else (another branch, a tag, a force-push, another task’s branch) rejects the whole push before the forge is contacted. Git prints the reason, prefixed with df:.

Push checks

Before forwarding, the proxy checks the commits a push adds (commits already on the forge are not checked again):

CheckFindingConfigurable per project
Secret scandf:secret-scan: rule, path, line and a masked preview; the secret itself is never stored or loggedmode approval (default) or reject
Commit identitydf:identity: author and committer must be the instance’s commit identityno, always enforced
Protected pathsdf:protected-path: a change below a protected glob; .dark-factory/** is always protectedglobs (default CI workflow directories and CODEOWNERS) and mode
Blob sizedf:blob-too-large: a file larger than the limitlimit (default 5 MiB) and mode
Linear historydf:merge-commiton or off (default off)
Commit limitdf:push-too-large: more than 10,000 commitsno
Push sizedf:push-too-large (HTTP 413): a push body above the maximum (default 256 MiB)instance setting

Pushes to the WIP branch get only the secret scan and the size limit, always rejecting.

Approval mode. A task-branch push rejected only by approval-mode findings raises a push-check-exception request in the inbox, listing the findings. Approving it creates exceptions for exactly these findings, and the agent’s next push passes them; findings in reject mode stay rejected. The agent gets a message with the masked findings either way. Board members change the modes on the project’s Push checks tab.

Push records

Every push attempt is stored with the control plane before the client gets an answer: run, task, ref updates with old and new SHA, verdict, reasons, bytes and duration. A push is recorded as forwarding before anything reaches the forge. If the record cannot be stored within 5 seconds, the push is rejected (df:audit-unavailable).

Upstream failures

Proxy answerMeaning
503The forge is unreachable or timed out, or the gateway has no snapshot yet; the runtime retries
502The forge rejected the credential (401, 403) or answered with another error; not retried

Reference: Git hardening in the runtime.