Authenticate git drives to private remotes (global + per-principal)#101
Merged
Conversation
…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>
6897a01 to
a68a70f
Compare
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
omnyshell node git-credential add/list/remove(secrets masked) — configures credentials on the node host that performs the clone/push.GitClichokepoint;GIT_TERMINAL_PROMPT=0makes 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.Storage & safety
Stored in
~/.omnyshell/git-credentials.json(mode600) 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.NodeDriveServicewas already resolver-shaped; the per-principal logic lives in a newNodeGitCredentialswrapper that reuses omnydrive's host-keyedGitCredentialStoreper scope.Temporarily builds against the omnydrive branch via a git
dependency_overrides(OmnyGrid/omnydrive#14). Before merge: merge/publish omnydrive 1.10.0, switch toomnydrive: ^1.10.0, and drop the override block inpubspec.yaml.Test plan
dart analyze— clean.dart test— 658 unit tests pass, incl. newtest/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.list, removal pruning emptied scopes, mode 600 — all verified.🤖 Generated with Claude Code