Skip to content

Add Git credential helper support for proxied HTTPS remotes#175

Open
freemanconsulting wants to merge 2 commits into
Infisical:mainfrom
freemanconsulting:feature/git-credential-broker
Open

Add Git credential helper support for proxied HTTPS remotes#175
freemanconsulting wants to merge 2 commits into
Infisical:mainfrom
freemanconsulting:feature/git-credential-broker

Conversation

@freemanconsulting
Copy link
Copy Markdown

@freemanconsulting freemanconsulting commented May 14, 2026

Summary

Adds first-class Git-over-HTTPS credential brokering for Agent Vault-wrapped processes.

Git asks credential helpers for username/password before it sends HTTPS traffic, which breaks non-interactive agent runtimes when system helpers such as macOS Keychain require UI access. This PR adds a Git credential helper plus agent-vault run --git so Git can proceed with sentinel credentials while Agent Vault remains the authority for the real upstream credential and injects it through the existing MITM proxy path.

User flow:

agent-vault vault credential set AZURE_DEVOPS_USER=your-azure-devops-username
agent-vault vault credential set AZURE_DEVOPS_PASSWORD
agent-vault vault service add \
  --name azure-devops-git \
  --host dev.azure.com \
  --auth-type basic \
  --username-key AZURE_DEVOPS_USER \
  --password-key AZURE_DEVOPS_PASSWORD

agent-vault run --git -- git ls-remote https://dev.azure.com/org/project/_git/repo

Technical overview:

  • Adds agent-vault git-credential <get|store|erase>, implementing Git's credential helper protocol.
  • get returns only non-secret sentinel credentials for supported HTTPS hosts.
  • store and erase are safe no-ops.
  • Adds agent-vault run --git, which injects process-local Git config through GIT_CONFIG_* env vars:
    • resets inherited/global credential.helper entries first
    • credential.helper=!<agent-vault> git-credential
    • credential.useHttpPath=true
    • http.sslCAInfo=<Agent Vault MITM CA>
    • http.proxySSLCAInfo=<Agent Vault MITM CA>
    • GIT_TERMINAL_PROMPT=0
  • Updates README and CLI reference docs.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation
  • CI / build

Test plan

  • Existing tests pass (make test)
  • Added/updated tests for new behavior
  • Manual testing (describe below)

Automated/local verification:

  • make test passed
  • go test ./... passed
  • go vet ./... passed
  • cd web && npm run build passed
  • cd web && npm test || true checked; no npm test script exists
  • make lint attempted; local environment does not have golangci-lint installed
  • git diff --check origin/main...HEAD passed
  • GitGuardian check is passing on this PR

Manual smoke coverage:

  • Public GitHub HTTPS git ls-remote through agent-vault run --git: PASS
  • Azure DevOps HTTPS git ls-remote with short-lived Code Read credential stored in Agent Vault: PASS
  • Azure DevOps HTTPS clone/fetch path through agent-vault run --git: PASS
  • Azure DevOps HTTPS push of an empty commit to a disposable scratch branch with a short-lived Code Read/Write credential stored in Agent Vault: PASS
  • Remote scratch branch deletion through agent-vault run --git: PASS
  • Request logs show matched service and credential key names only, not credential values: PASS

Smoke transcripts are attached in PR comments:

Security checklist

  • No secrets or credentials in code
  • No new unauthenticated endpoints
  • Input validation on new API surfaces
  • Checked for OWASP top 10 (injection, XSS, etc.)

Security notes:

  • The helper never returns vault credential values.
  • Real upstream credentials are not written into Git remote URLs, Git config, command-line arguments, helper stdout/stderr, request logs, or PR text.
  • --git uses process-local Git config only; it does not mutate global Git config.
  • The helper rejects unsupported protocols and invalid/local/internal hosts.
  • Existing strict-deny and service matching behavior remains in the proxy layer.
  • The manual Azure DevOps credentials used for smoke testing were short-lived, loaded into Agent Vault, and the local plaintext handoff files were deleted after ingestion.

@gitguardian
Copy link
Copy Markdown

gitguardian Bot commented May 14, 2026

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@freemanconsulting freemanconsulting force-pushed the feature/git-credential-broker branch from da9c8c4 to 8950f7e Compare May 14, 2026 23:00
@freemanconsulting
Copy link
Copy Markdown
Author

freemanconsulting commented May 14, 2026

Latest smoke/update on 4de349a:

  • Reworked the PR to avoid secret-scanner false positives in examples/tests while keeping the helper behavior intact.
  • Fixed run --git to reset inherited/global Git credential helpers before installing the Agent Vault helper. This prevents non-interactive macOS runs from still invoking helpers such as osxkeychain during Git's store phase.
  • Verified public GitHub HTTPS Git through Agent Vault succeeds with run --git and no keychain error:
AGENT_VAULT_ADDR=http://127.0.0.1:14321 ./agent-vault run --vault default --git -- \
  /opt/homebrew/bin/git ls-remote --heads https://github.com/Infisical/agent-vault.git
  • Ran Azure DevOps read smoke against the configured dev.azure.com Basic service. Result is still 401, but request logs confirm Agent Vault matched azure-devops-basic and resolved only credential key names in logs:
host=dev.azure.com:443
path=/dtetrac/eTracIntegrations/_git/etrac-as2-router/info/refs
matched_service=azure-devops-basic
credential_keys=[AZURE_DEVOPS_USER AZURE_DEVOPS_PASSWORD]
status=401

This means the helper/config path works and the proxy injection path is being exercised. Remaining blocker for marking ready is a valid scoped Azure DevOps credential pairing for a live 200 Git read, then a scratch-branch write smoke.

Automated verification:

  • go test ./... passed
  • cd web && npm test || true shows no npm test script exists
  • cd web && npm run build passed

@freemanconsulting freemanconsulting force-pushed the feature/git-credential-broker branch from 8950f7e to 4de349a Compare May 14, 2026 23:26
@freemanconsulting
Copy link
Copy Markdown
Author

Azure DevOps read smoke is now verified with a short-lived Code Read credential stored in Agent Vault.

Command shape:

AGENT_VAULT_ADDR=http://127.0.0.1:14321 ./agent-vault run --vault default --git -- \
  /opt/homebrew/bin/git ls-remote --heads \
  https://dev.azure.com/dtetrac/eTracIntegrations/_git/etrac-as2-router

Result:

0690be9e2c266564a7a425e5b103120d7e661487 refs/heads/feature/vltrader-inbound-mailbox-delivery
569bb72d9549d1ba6ef57b7e01b0d2a580a8fbec refs/heads/main
AZDO_GIT_EXIT=0
AZDO_GIT_READ_RESULT=PASS

Request log verification:

{"method":"GET","host":"dev.azure.com:443","path":"/dtetrac/eTracIntegrations/_git/etrac-as2-router/info/refs","matched_service":"azure-devops-basic","credential_keys":["AZURE_DEVOPS_USER","AZURE_DEVOPS_PASSWORD"],"status":200,"error_code":""}

Security notes from the smoke:

  • The child Git process used agent-vault run --git; no upstream credential was placed in the remote URL or Git config.
  • Agent Vault request logs show only credential key names, not values.
  • The local plaintext smoke credential file was deleted after loading the credential into Agent Vault.

Remaining blocker before ready-for-review: write smoke with a short-lived Code Read/Write credential against a scratch branch, then delete the scratch branch.

@freemanconsulting
Copy link
Copy Markdown
Author

Azure DevOps write smoke is now verified with a short-lived Code Read/Write credential stored in Agent Vault.

Test shape:

  • Cloned dtetrac/eTracIntegrations/_git/etrac-as2-router through agent-vault run --git
  • Created an empty commit on a disposable scratch branch
  • Pushed the scratch branch through agent-vault run --git
  • Verified the remote branch existed
  • Deleted the remote scratch branch through agent-vault run --git
  • Verified the remote branch was gone

Scratch branch:

agent-vault-smoke/git-credential-broker-20260515-093315

Push result:

To https://dev.azure.com/dtetrac/eTracIntegrations/_git/etrac-as2-router
 * [new branch]      HEAD -> agent-vault-smoke/git-credential-broker-20260515-093315

Delete result:

To https://dev.azure.com/dtetrac/eTracIntegrations/_git/etrac-as2-router
 - [deleted]         agent-vault-smoke/git-credential-broker-20260515-093315

Request log verification includes successful Git write traffic and only credential key names:

{"method":"POST","host":"dev.azure.com:443","path":"/dtetrac/eTracIntegrations/_git/etrac-as2-router/git-receive-pack","matched_service":"azure-devops-basic","credential_keys":["AZURE_DEVOPS_USER","AZURE_DEVOPS_PASSWORD"],"status":200,"error_code":""}

Cleanup completed:

  • Deleted the local temporary clone.
  • Deleted the local plaintext smoke credential file after loading the credential into Agent Vault.
  • Deleted the remote scratch branch.

With this, the required real Git operations are verified:

  • git ls-remote read: PASS
  • git clone/fetch path: PASS
  • git push write to scratch branch: PASS
  • scratch branch deletion: PASS
  • request logs show key names only: PASS

@freemanconsulting freemanconsulting force-pushed the feature/git-credential-broker branch from 4de349a to f0058be Compare May 15, 2026 09:42
@freemanconsulting freemanconsulting marked this pull request as ready for review May 15, 2026 09:43
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant