Skip to content

Authenticate git drives to private remotes (global + per-principal)#101

Merged
gmpassos merged 5 commits into
masterfrom
feat/node-git-credentials
Jul 2, 2026
Merged

Authenticate git drives to private remotes (global + per-principal)#101
gmpassos merged 5 commits into
masterfrom
feat/node-git-credentials

Conversation

@gmpassos

@gmpassos gmpassos commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Adopts omnydrive 1.10.0's git-credential feature so a node can authenticate to private git remotes itself, instead of relying on the node host's ambient git config. Git clone/push runs on the node, so credentials are node-local state.

  • New CLI omnyshell node git-credential add/list/remove (secrets masked) — configures credentials on the node host that performs the clone/push.
  • Credentials are injected into the node's git clone/fetch/push via omnydrive's single GitCli chokepoint; GIT_TERMINAL_PROMPT=0 makes a missing/wrong credential fail fast instead of hanging.

Global + per-principal

Each credential is either global (node-wide) or scoped to a connecting principal via --principal <p>. At mount time the node resolves a host's credential principal-first, then global: the (hub-authenticated) connecting principal's credential wins, falling back to the node's global one — and one principal never sees another's.

omnyshell node git-credential add github.com --pat <token>               # global
omnyshell node git-credential add github.com --pat <alice> --principal alice
omnyshell node git-credential list                # grouped: [global] / [principal: …]
omnyshell node git-credential remove github.com --principal alice

Storage & safety

Stored in ~/.omnyshell/git-credentials.json (mode 600) as a single backward-compatible structured file — the legacy flat {credentials:{…}} loads as the global scope; principals are JSON keys so arbitrary identities need no sanitization. Credentials live only on the node: never sent to the hub/peers, never serialized onto a mount (mounts.json) or drive. The store is loaded fresh per drive session, so new credentials apply without a node restart.

NodeDriveService was already resolver-shaped; the per-principal logic lives in a new NodeGitCredentials wrapper that reuses omnydrive's host-keyed GitCredentialStore per scope.

⚠️ Blocked on omnydrive 1.10.0

Temporarily builds against the omnydrive branch via a git dependency_overrides (OmnyGrid/omnydrive#14). Before merge: merge/publish omnydrive 1.10.0, switch to omnydrive: ^1.10.0, and drop the override block in pubspec.yaml.

Test plan

  • dart analyze — clean.
  • dart test — 658 unit tests pass, incl. new test/unit/node/node_git_credentials_test.dart (principal-first/global-fallback, "B never sees A's", legacy-file compat, arbitrary principal keys, mode 600); drive integration (41) and version tests pass.
  • Manual CLI e2e: global + per-principal add, structured file, grouped/scoped list, removal pruning emptied scopes, mode 600 — all verified.

🤖 Generated with Claude Code

…1.50.0)

Adopt omnydrive 1.10.0's git-credential feature so a node can authenticate to
private git remotes itself, instead of relying on the node host's ambient git
config.

Git clone/push runs on the node, so credentials are node-local state managed by
a new `omnyshell node git-credential add/list/remove` command and injected into
the node's git operations (clone/fetch/push) at omnydrive's single GitCli
chokepoint. GIT_TERMINAL_PROMPT=0 means a missing/wrong credential fails fast.

Each credential is either global (node-wide) or scoped to a connecting principal
via --principal. At mount time the node resolves a host's credential
principal-first, then falls back to global: the hub-authenticated connecting
principal's credential wins, and one principal never sees another's.

Credentials live only on the node in ~/.omnyshell/git-credentials.json (mode
600) as a single backward-compatible structured file (a legacy flat file loads
as the global scope). They are never sent to the hub/peers or serialized onto a
mount/drive. The store is loaded fresh per drive session, so new credentials
apply without a node restart.

NOTE: temporarily depends on the omnydrive 1.10.0 branch via a git
dependency_override (OmnyGrid/omnydrive#14); switch to `omnydrive: ^1.10.0` and
drop the override once it is published to pub.dev.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gmpassos gmpassos force-pushed the feat/node-git-credentials branch from 6897a01 to a68a70f Compare July 2, 2026 00:18
gmpassos and others added 4 commits July 1, 2026 21:39
omnydrive 1.10.0 is now on pub.dev, so resolve it from the hosted registry and
remove the temporary git dependency_override.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prove that a single resolver picks per host: one host resolves to the
connecting principal's credential while another falls back to the node's
global credential.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clone a private remote end-to-end through the real node path
(NodeGitCredentials -> resolverFor(principal) -> omnydrive GitProvider). The
remote is a local smart-HTTP git server (git http-backend) behind HTTP Basic
auth, so a clone only succeeds when the credential is injected and accepted.

Covers the principal way (a principal-scoped credential authenticates; a
different principal without one is rejected), the global way (a node-wide
credential serves any principal), per-host resolution, and a no-credential
case proving the remote truly requires auth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an integration case: a global credential covers the served host (host-x)
while principal A has a credential only for a different host (host-y). Cloning
host-x as A must resolve the GLOBAL credential — A's host-y credential must not
be consulted. Asserts both the resolved credential and a successful clone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gmpassos gmpassos merged commit fd1b3d2 into master Jul 2, 2026
5 checks passed
@gmpassos gmpassos deleted the feat/node-git-credentials branch July 2, 2026 01:14
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