GitProxy is a Git HTTP proxy that intercepts Git operations (primarily git push) and enforces organizational policies before allowing changes to reach the actual Git host.
It acts as:
- A policy enforcement engine (via processors and plugins)
- A review/approval gate (manual or automated)
- A proxy server for Git operations
- A UI + API layer for reviewing, approving, and auditing pushes
The core design principle is a chain-of-processors architecture where each Git action flows through ordered processing steps.
# Build
npm run build
# Run unit tests
npm run test
# Run e2e tests
npm run test:e2e
# Lint check/fix
npm run lint
npm run lint:fix
# Format check/fix
npm run format:check
npm run format
Stack: TypeScript, Node >=22, Express 5, React 16, Vitest 3, NeDB / MongoDB
GitProxy consists of four main components:
Contributor (git push)
↓
HTTP Proxy (/src/proxy)
↓
Action Chain (Processors + Plugins)
↓
Service API (/src/service)
↓
Database (audit, users, repos, approvals)
↓
Web UI (/src/ui)
Express-based HTTP proxy that:
- Intercepts Git operations
- Parses requests into an
Action - Executes the appropriate Action Chain
- Blocks, rejects, or queues for approval
Core concepts:
- Action — Represents a Git operation (push/pull/default)
- Chain — Ordered list of processors
- Processor (Step) — A single policy enforcement unit
- Plugin — Custom processor injected externally
Express application responsible for:
- UI communication
- Authentication (Passport strategies)
- Database access
- Approval/rejection workflows
Default port: 8080
Authentication strategies supported:
- Local
- ActiveDirectory
- OpenID Connect
Loads and validates proxy.config.json.
Controls:
- Authentication methods
- Repository allowlist
- Commit message policies
- Database configuration
- Feature flags
Schema reference: https://git-proxy.finos.org/docs/configuration/reference/
React-based UI used to:
- View pending pushes
- Review diffs
- Approve/reject pushes
- Manage repositories/users (depending on role)
parseActionclassifies requestpushActionChainexecutes processors in strict order- If blocked → rejected
- If valid → queued for approval
- Approver reviews in UI
- If approved → user re-pushes to actual remote
parsePush
checkEmptyBranch
checkRepoInAuthorisedList
checkCommitMessages
checkAuthorEmails
checkUserPushPermission
pullRemote
writePack
checkHiddenCommits
checkIfWaitingAuth
preReceive
getDiff
gitleaks
scanDiff
blockForAuth
Order matters. Some processors depend on artifacts created by previous ones (e.g., cloned repo, computed diff).
checkRepoInAuthorisedList
checkRepoInAuthorisedList
When modifying or adding processors:
-
They must be idempotent
-
They must clearly define:
- Required inputs
- Side effects
- Failure mode (reject vs throw vs auto-approve)
-
They must not mutate shared state outside the
Action -
They must preserve audit traceability
If a processor requires data not available at the end of the chain, it must be inserted earlier.
Plugins:
- Extend push/pull chains
- Are externally defined processors
- Should not modify core system invariants
- Must respect chain ordering semantics
If logic needs access to internal chain data before plugins execute, implement a custom processor, not a plugin.
Authentication applies to:
- UI access
- Approval workflow
- User management
It does NOT authenticate Git pushes via the proxy itself — Git identity is derived from commit metadata (user.email).
Supported methods:
- Local (default)
- ActiveDirectory
- OpenID Connect
New strategies must:
- Extend
/src/service/passport - Provide a
configure()function - Match config
type - Be added to
authStrategiesinindex.ts
After chain execution:
auditstores:- Action metadata
- Processor results
- Approval state
If repository clone occurred:
clearBareClonemust clean up disk artifacts
Never introduce processor changes that bypass audit logging.
Audit integrity is critical.
The action chain is the core abstraction.
When implementing new functionality:
-
Decide whether it belongs in:
- Existing processor
- New processor
- Plugin
- Service layer
- UI
-
Do NOT insert logic randomly in the proxy request handler.
- Proxy handles Git interception + chain execution
- Service handles authentication + state
- Config handles validation and schema
- UI handles display + approval user flow
Do not mix responsibilities across modules.
Important rule:
A push must never reach the real Git remote unless explicitly approved or auto-approved by policy.
Changes must not bypass:
blockForAuth- Approval state checks
- Waiting authorization checks
When introducing new config options:
- Add schema validation
- Provide sensible defaults
- Ensure backward compatibility
- Document in schema reference
Never silently change default security behavior.
Add to existing processor (if cohesive).
Create a new processor.
Implement as plugin.
Ask:
- Does this require diff access?
- Does this require cloned repo?
- Does this require user database?
- Does this need to run before approval gating?
When modifying:
- Must test:
- Success path
- Rejection path
- Audit logging (
step.error,step.log)
- Must test:
- Invalid values
- Default values
- Breaking processor order dependencies
- Mixing UI and service logic
- Introducing security regressions in approval flow
- Mutating global/shared state outside
Action
All source files must include the Apache 2.0 license header (see any existing file).
This file is the canonical project guide. Tool-specific entry points:
- Claude Code:
CLAUDE.md(bridge) +.claude/skills/ - GitHub Copilot:
.github/copilot-instructions.md - OpenCode:
.opencode/commands/ - Gemini CLI:
GEMINI.md(bridge) - Cursor:
.cursor/rules/00-core.mdc+.cursor/commands/ - Codex:
AGENTS.mdprimary — (Codex does not have a dedicated convention file)
The main agent must act as an orchestrator. Never do work inline that can be delegated to a subagent.
- Delegate everything: Use the Task tool with specialized subagents for all research, code exploration, code writing, testing, and analysis. The main agent should plan, coordinate, and summarize — not do the work itself.
- Maximize parallelism: Launch multiple subagents concurrently whenever their tasks are independent. For example, when exploring code patterns AND analyzing tests AND checking dependencies, spawn all three agents in a single message rather than sequentially. Always send independent Task calls in a single message with multiple tool-use blocks.
GitProxy is:
- A deterministic policy pipeline
- Wrapped in a Git HTTP proxy
- With an approval gate
- Backed by a service API
- Audited end-to-end
All changes must respect that flow.