Menu

#163 improve: provision_vcs_auth credential file isolation and provider coverage

closed
nobody
None
2026-04-28
2026-04-21
Anonymous
No

Originally created by: kumaakh

Background

`provision_vcs_auth` deploys git credentials to fleet members so they can perform HTTPS git operations autonomously. The architecture differs significantly by provider — and GitHub's path is the right model.


What GitHub App mode does well

When `github_mode: github-app` is used, `provision_vcs_auth` mints a short-lived installation token from the configured GitHub App rather than storing a personal credential:

  • Token is scoped to specific repositories and permissions (read / push / admin / issues / full)
  • Token expires in ~1 hour — not stored permanently
  • Token is non-personal: it represents the App installation, not any individual's account
  • When the token expires, `provision_vcs_auth` re-mints — no human credential ever leaves the PM

This is the right model. The plaintext credential file on the member machine is a real trade-off, but with a 1-hour TTL the blast radius of any exposure is narrow.


Bug: Credential identity collision (current design is fundamentally single-identity)

The current implementation always writes to a single hardcoded file:

  • Windows: `~/.fleet-git-credential.bat`
  • Linux: `~/.fleet-git-credential`

And registers it at host scope in `.gitconfig`:

[credential "https://github.com"]
    helper = ~/.fleet-git-credential.bat

This fails in any multi-identity scenario:

Scenario Problem
Work GitHub + Personal GitHub Second provision_vcs_auth overwrites the file — first identity gone
GitHub + Bitbucket Same file serves both hosts — file contains one provider's token
Two Bitbucket workspaces with different logins No way to differentiate at all
Any credential rotation Overwrites any other active credential for that host

Git's actual capability

Git credential helpers support URL-prefix scoping, not just host scoping:

[credential "https://github.com/work-org"]
    helper = ~/.fleet-git-credential-work.bat

[credential "https://github.com/personal"]
    helper = ~/.fleet-git-credential-personal.bat

The most specific URL prefix wins. This means per-identity, per-org, or per-repo-set credentials are all representable — if the implementation uses it.


Proposed fix

Add a label parameter to provision_vcs_auth

A short slug that uniquely identifies this credential registration on the member (e.g. work-github, bitbucket-main, personal-gh). Defaults to the provider name for backwards compatibility.

Add a scope_url parameter (optional)

The URL prefix to register in `.gitconfig`. Defaults to https://<host> (current behaviour). For org-scoped access: https://github.com/my-org.

Per-label credential files

~/.fleet-git-credential-<label>.bat   (Windows)
~/.fleet-git-credential-<label>       (Linux)

Each provision_vcs_auth call writes its own file and registers its own gitconfig entry. Multiple identities coexist without collision.

Revocation

revoke_vcs_auth removes the file and the gitconfig entry for the given label.


What NOT to do

Do not replace the credential file with a shim that calls back to apra-fleet (`apra-fleet git-credential --host github.com`). Any process running as the same OS user could call that shim and extract any stored credential without authentication — making apra-fleet a local unauthenticated secrets API.


Provider minting capabilities

Provider Minting TTL Notes
GitHub ✅ GitHub App installation tokens ~1 hour Current implementation — the right model
Azure DevOps ✅ Entra ID service principal tokens ~1 hour, auto-rotating Uses bearer token in HTTP header or git URL; non-personal, supports managed identities
Bitbucket ⚠️ Workspace access tokens Days–365 days (admin-configurable) Scoped to repos/permissions but not short-lived; no sub-hour minting. App passwords deprecated June 2026

Azure DevOps has a viable minting path (service principal → Entra ID token) that should be wired up. Bitbucket workspace tokens are an improvement over personal API tokens but lack auto-rotation — plaintext file is the only current option.


Path encoding bug (Windows + bash/WSL)

Windows backslashes written to `.gitconfig` are stripped by bash. The helper call fails silently and git falls back to `credential.helper=store`.

Fix: Use forward slashes in the gitconfig value when writing from bash contexts.


Acceptance criteria

  • [ ] provision_vcs_auth accepts label (slug, default: provider name) and optional scope_url (default: https://<host>)
  • [ ] Credential file is named ~/.fleet-git-credential-<label>.bat / ~/.fleet-git-credential-<label>
  • [ ] gitconfig entry uses scope_url as the credential URL key
  • [ ] Multiple calls with different labels coexist without collision
  • [ ] revoke_vcs_auth removes by label (file + gitconfig entry)
  • [ ] Path written to .gitconfig uses forward slashes (bash/WSL compatible)
  • [ ] Cleanup: on provision_vcs_auth, remove legacy ~/.fleet-git-credential.bat / ~/.fleet-git-credential if present
  • [ ] Azure DevOps: add service principal / Entra ID token minting path alongside PAT (future sprint)
  • [ ] Bitbucket workspace token support documented; PAT path updated to use workspace tokens (replaces deprecated app passwords)

Related

Tickets: #76

Discussion

  • Anonymous

    Anonymous - 2026-04-23

    Originally posted by: kumaakh

    Technical direction: This is a well-scoped design issue. Recommended implementation order:

    1. Add label param to provision_vcs_auth (src/tools/provision-vcs-auth.ts) — slug, defaults to provider name for backward compat. Use it to name the credential file: ~/.fleet-git-credential-<label>.bat / ~/.fleet-git-credential-<label>.</label></label>
    2. Add scope_url param (optional, defaults to https://<host>) — pass directly as the gitconfig credential URL key.</host>
    3. Update gitCredentialHelperWrite in src/services/credential-cleanup.ts (or the helper used by provisionVcsAuth) to write forward-slash paths in the gitconfig value — fixes the bash/WSL path-stripping bug.
    4. Update
      evoke_vcs_auth
      to accept label and remove only the matching file + gitconfig entry.
    5. Migration: on any provision_vcs_auth call, detect and remove legacy ~/.fleet-git-credential.bat / ~/.fleet-git-credential if present.
    6. credential_store_list — add llowed_members display (prerequisite for [#157] too).

    Azure DevOps Entra ID minting and Bitbucket workspace token support can be a follow-up sprint — the label/scope_url isolation fix is the blocking part and can ship independently.

     

    Related

    Tickets: #157

  • Anonymous

    Anonymous - 2026-04-28

    Originally posted by: kumaakh

    Addressed in PR [#183] (sprint/session-lifecycle-oob-fix → main).

    Changes shipped: provision_vcs_auth now writes per-label isolated credential files instead of a single shared file.

    PR is open for testing — will be merged once testing is complete.

     

    Related

    Tickets: #183

  • Anonymous

    Anonymous - 2026-04-28

    Ticket changed by: kumaakh

    • status: open --> closed
     

Log in to post a comment.

MongoDB Logo MongoDB