Repository navigation
refactor(git)!: stop injecting FERRFLOW_TOKEN into remote URL + gix foundation - #486
Merged
Merged
Conversation
…otocol The previous auth path baked the FERRFLOW_TOKEN into the remote URL (authenticated_remote_url -> https://x-access-token:TOKEN@github.com/...). That leaks the token into git's process argv and into any subprocess error message, and bypasses the standard credential helper protocol. This change removes authenticated_remote_url entirely. The libgit2 callback path (push, fetch, ls-refs) keeps relying on credentials_callback which already handles FERRFLOW_TOKEN -> Cred::userpass_plaintext, with fallback to Cred::credential_helper for users with a configured helper. The shell-out path (git ls-remote, git push for tags) now uses an inline -c credential.helper=... config that emits username/password on stdin, so the token never appears in argv or in the URL. Also wires gix 0.83 into the cli feature with the sha1 + max-performance-safe features (required for gix-hash to compile on rustc 1.94), and migrates collect_all_tags to gix as the first read-path migration. The remaining git paths still use libgit2 - to be migrated incrementally. Pulls in gix-date 0.15.3, resolving RUSTSEC-2025-0140.
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: 40af923 | Previous: 0b5fe57 | Ratio |
|---|---|---|---|
version_files/toml_read |
7977 ns/iter (± 91) |
8489 ns/iter (± 791) |
0.94 |
version_files/toml_write |
180493 ns/iter (± 30183) |
132036 ns/iter (± 10286) |
1.37 |
version_files/json_read |
5445 ns/iter (± 73) |
5314 ns/iter (± 69) |
1.02 |
version_files/json_write |
171106 ns/iter (± 24211) |
130851 ns/iter (± 8755) |
1.31 |
version_files/xml_read |
5101 ns/iter (± 41) |
5140 ns/iter (± 16) |
0.99 |
version_files/xml_write |
131818 ns/iter (± 13632) |
138826 ns/iter (± 18123) |
0.95 |
version_files/gradle_read |
4935 ns/iter (± 27) |
4981 ns/iter (± 37) |
0.99 |
version_files/gradle_write |
131888 ns/iter (± 10377) |
128857 ns/iter (± 12186) |
1.02 |
This comment was automatically generated by workflow using github-action-benchmark.
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.
| Benchmark suite | Current: 40af923 | Previous: 0b5fe57 | Ratio |
|---|---|---|---|
version_files/toml_write |
180493 ns/iter (± 30183) |
132036 ns/iter (± 10286) |
1.37 |
version_files/json_write |
171106 ns/iter (± 24211) |
130851 ns/iter (± 8755) |
1.31 |
This comment was automatically generated by workflow using github-action-benchmark.
BryanFRD
added a commit
that referenced
this pull request
May 21, 2026
Removes the git2 dependency entirely. The cli feature now uses gix for all local repository operations (tag enumeration, commit walks, tree diffs, object lookups) and shells out to the user's installed git CLI for network operations (push, fetch, ls-remote) and write operations (commit, tag, branch creation, checkout, reset). This is the same hybrid strategy cargo uses. Why shell out for network and writes: - gix-protocol exists but its API surface is genuinely complex and the blocking-network-client feature pulls reqwest + a large transport stack. We were already shelling out for push tags (#459) and the credential-helper path requires shell-out anyway. - Writes through gix (create_commit, create_tag, create_branch) require hand-rolling index manipulation, tree writing, and ref edits. git's porcelain handles all the edge cases for free. - Diff via gix needs the blob-diff feature which pulls in gix-diff, gix-filter, gix-traverse - heavy for our use case (just list paths that changed). git diff-tree / git ls-tree is a one-liner. What gix is used for (the perf-sensitive read paths): - collect_all_tags, find_last_tag, find_highest_semver_tag, TagIndex (the hot path for monorepo tag scanning) - get_commits_since_oid (revwalk) - open_repo, get_repo_root, resolve_current_branch - find_object, find_commit, find_tree for tag-to-commit resolution - repo.references().tags() for tag iteration Auth path: - For shell-out calls (git push/fetch/ls-remote): inline credential helper via -c credential.helper config (no token in argv, no token in URL). - FERRFLOW_TOKEN / GITHUB_TOKEN / GITLAB_TOKEN env vars unchanged. Tests + benches: - Shell-out helpers in lib.rs::test_utils and main.rs::test_utils (git init/add/commit/tag) replace the git2-based fixture functions. - benches/ferrflow_benchmarks.rs uses the same shell-out fixture pattern; bench measurements stay comparable. - The fetch_and_rebase and reset_branch_to_remote integration tests (which set up two repos + a bare remote) were rewritten with shell-out — same scenarios, same assertions. - 512 lib tests pass, 614 bin tests pass, cargo clippy -D warnings clean. Cargo.lock no longer contains git2, libgit2-sys, or openssl-src. Also fixes two long-standing Publish workflow failures: - ferrflow-wasm: wasm-pack's bundled wasm-opt fails on the new compiler output. Disable it via [package.metadata.wasm-pack.profile.release]. - npm scope rename: @ferrflow/* -> @ferrlabs/ferrflow-* (platforms), ferrflow -> @ferrlabs/ferrflow (wrapper), and @ferrflow/wasm -> @ferrlabs/ferrflow-wasm. The old @ferrflow user scope wasn't writable by the bot token; the @FerrLabs org scope is. The breaking-change marker (!) is dropped: v5.0.0 already shipped via #486 (the auth refactor) which is the SemVer-breaking piece of this work for downstream embedders of ferrflow::git::auth. This follow-up is a pure refactor with no public API change.
BryanFRD
added a commit
that referenced
this pull request
May 21, 2026
Removes the git2 dependency entirely. The cli feature now uses gix for all local repository operations (tag enumeration, commit walks, tree diffs, object lookups) and shells out to the user's installed git CLI for network operations (push, fetch, ls-remote) and write operations (commit, tag, branch creation, checkout, reset). This is the same hybrid strategy cargo uses. Why shell out for network and writes: - gix-protocol exists but its API surface is genuinely complex and the blocking-network-client feature pulls reqwest + a large transport stack. We were already shelling out for push tags (#459) and the credential-helper path requires shell-out anyway. - Writes through gix (create_commit, create_tag, create_branch) require hand-rolling index manipulation, tree writing, and ref edits. git's porcelain handles all the edge cases for free. - Diff via gix needs the blob-diff feature which pulls in gix-diff, gix-filter, gix-traverse - heavy for our use case (just list paths that changed). git diff-tree / git ls-tree is a one-liner. What gix is used for (the perf-sensitive read paths): - collect_all_tags, find_last_tag, find_highest_semver_tag, TagIndex (the hot path for monorepo tag scanning) - get_commits_since_oid (revwalk) - open_repo, get_repo_root, resolve_current_branch - find_object, find_commit, find_tree for tag-to-commit resolution - repo.references().tags() for tag iteration Auth path: - For shell-out calls (git push/fetch/ls-remote): inline credential helper via -c credential.helper config (no token in argv, no token in URL). - FERRFLOW_TOKEN / GITHUB_TOKEN / GITLAB_TOKEN env vars unchanged. Tests + benches: - Shell-out helpers in lib.rs::test_utils and main.rs::test_utils (git init/add/commit/tag) replace the git2-based fixture functions. - benches/ferrflow_benchmarks.rs uses the same shell-out fixture pattern; bench measurements stay comparable. - The fetch_and_rebase and reset_branch_to_remote integration tests (which set up two repos + a bare remote) were rewritten with shell-out — same scenarios, same assertions. - 512 lib tests pass, 614 bin tests pass, cargo clippy -D warnings clean. Cargo.lock no longer contains git2, libgit2-sys, or openssl-src. Also fixes two long-standing Publish workflow failures: - ferrflow-wasm: wasm-pack's bundled wasm-opt fails on the new compiler output. Disable it via [package.metadata.wasm-pack.profile.release]. - npm scope rename: @ferrflow/* -> @ferrlabs/ferrflow-* (platforms), ferrflow -> @ferrlabs/ferrflow (wrapper), and @ferrflow/wasm -> @ferrlabs/ferrflow-wasm. The old @ferrflow user scope wasn't writable by the bot token; the @FerrLabs org scope is. The breaking-change marker (!) is dropped: v5.0.0 already shipped via #486 (the auth refactor) which is the SemVer-breaking piece of this work for downstream embedders of ferrflow::git::auth. This follow-up is a pure refactor with no public API change.
BryanFRD
added a commit
that referenced
this pull request
May 21, 2026
Removes the git2 dependency entirely. The cli feature now uses gix for all local repository operations (tag enumeration, commit walks, tree diffs, object lookups) and shells out to the user's installed git CLI for network operations (push, fetch, ls-remote) and write operations (commit, tag, branch creation, checkout, reset). This is the same hybrid strategy cargo uses. Why shell out for network and writes: - gix-protocol exists but its API surface is genuinely complex and the blocking-network-client feature pulls reqwest + a large transport stack. We were already shelling out for push tags (#459) and the credential-helper path requires shell-out anyway. - Writes through gix (create_commit, create_tag, create_branch) require hand-rolling index manipulation, tree writing, and ref edits. git's porcelain handles all the edge cases for free. - Diff via gix needs the blob-diff feature which pulls in gix-diff, gix-filter, gix-traverse - heavy for our use case (just list paths that changed). git diff-tree / git ls-tree is a one-liner. What gix is used for (the perf-sensitive read paths): - collect_all_tags, find_last_tag, find_highest_semver_tag, TagIndex (the hot path for monorepo tag scanning) - get_commits_since_oid (revwalk) - open_repo, get_repo_root, resolve_current_branch - find_object, find_commit, find_tree for tag-to-commit resolution - repo.references().tags() for tag iteration Auth path: - For shell-out calls (git push/fetch/ls-remote): inline credential helper via -c credential.helper config (no token in argv, no token in URL). - FERRFLOW_TOKEN / GITHUB_TOKEN / GITLAB_TOKEN env vars unchanged. Tests + benches: - Shell-out helpers in lib.rs::test_utils and main.rs::test_utils (git init/add/commit/tag) replace the git2-based fixture functions. - benches/ferrflow_benchmarks.rs uses the same shell-out fixture pattern; bench measurements stay comparable. - The fetch_and_rebase and reset_branch_to_remote integration tests (which set up two repos + a bare remote) were rewritten with shell-out — same scenarios, same assertions. - 512 lib tests pass, 614 bin tests pass, cargo clippy -D warnings clean. Cargo.lock no longer contains git2, libgit2-sys, or openssl-src. Also fixes two long-standing Publish workflow failures: - ferrflow-wasm: wasm-pack's bundled wasm-opt fails on the new compiler output. Disable it via [package.metadata.wasm-pack.profile.release]. - npm scope rename: @ferrflow/* -> @ferrlabs/ferrflow-* (platforms), ferrflow -> @ferrlabs/ferrflow (wrapper), and @ferrflow/wasm -> @ferrlabs/ferrflow-wasm. The old @ferrflow user scope wasn't writable by the bot token; the @FerrLabs org scope is. The breaking-change marker (!) is dropped: v5.0.0 already shipped via #486 (the auth refactor) which is the SemVer-breaking piece of this work for downstream embedders of ferrflow::git::auth. This follow-up is a pure refactor with no public API change.
BryanFRD
added a commit
that referenced
this pull request
May 21, 2026
Removes the git2 dependency entirely. The cli feature now uses gix for all local repository operations (tag enumeration, commit walks, tree diffs, object lookups) and shells out to the user's installed git CLI for network operations (push, fetch, ls-remote) and write operations (commit, tag, branch creation, checkout, reset). This is the same hybrid strategy cargo uses. Why shell out for network and writes: - gix-protocol exists but its API surface is genuinely complex and the blocking-network-client feature pulls reqwest + a large transport stack. We were already shelling out for push tags (#459) and the credential-helper path requires shell-out anyway. - Writes through gix (create_commit, create_tag, create_branch) require hand-rolling index manipulation, tree writing, and ref edits. git's porcelain handles all the edge cases for free. - Diff via gix needs the blob-diff feature which pulls in gix-diff, gix-filter, gix-traverse - heavy for our use case (just list paths that changed). git diff-tree / git ls-tree is a one-liner. What gix is used for (the perf-sensitive read paths): - collect_all_tags, find_last_tag, find_highest_semver_tag, TagIndex (the hot path for monorepo tag scanning) - get_commits_since_oid (revwalk) - open_repo, get_repo_root, resolve_current_branch - find_object, find_commit, find_tree for tag-to-commit resolution - repo.references().tags() for tag iteration Auth path: - For shell-out calls (git push/fetch/ls-remote): inline credential helper via -c credential.helper config (no token in argv, no token in URL). - FERRFLOW_TOKEN / GITHUB_TOKEN / GITLAB_TOKEN env vars unchanged. Tests + benches: - Shell-out helpers in lib.rs::test_utils and main.rs::test_utils (git init/add/commit/tag) replace the git2-based fixture functions. - benches/ferrflow_benchmarks.rs uses the same shell-out fixture pattern; bench measurements stay comparable. - The fetch_and_rebase and reset_branch_to_remote integration tests (which set up two repos + a bare remote) were rewritten with shell-out — same scenarios, same assertions. - 512 lib tests pass, 614 bin tests pass, cargo clippy -D warnings clean. Cargo.lock no longer contains git2, libgit2-sys, or openssl-src. Also fixes two long-standing Publish workflow failures: - ferrflow-wasm: wasm-pack's bundled wasm-opt fails on the new compiler output. Disable it via [package.metadata.wasm-pack.profile.release]. - npm scope rename: @ferrflow/* -> @ferrlabs/ferrflow-* (platforms), ferrflow -> @ferrlabs/ferrflow (wrapper), and @ferrflow/wasm -> @ferrlabs/ferrflow-wasm. The old @ferrflow user scope wasn't writable by the bot token; the @FerrLabs org scope is. The breaking-change marker (!) is dropped: v5.0.0 already shipped via #486 (the auth refactor) which is the SemVer-breaking piece of this work for downstream embedders of ferrflow::git::auth. This follow-up is a pure refactor with no public API change.
BryanFRD
added a commit
that referenced
this pull request
May 21, 2026
Removes the git2 dependency entirely. The cli feature now uses gix for all local repository operations (tag enumeration, commit walks, tree diffs, object lookups) and shells out to the user's installed git CLI for network operations (push, fetch, ls-remote) and write operations (commit, tag, branch creation, checkout, reset). This is the same hybrid strategy cargo uses. Why shell out for network and writes: - gix-protocol exists but its API surface is genuinely complex and the blocking-network-client feature pulls reqwest + a large transport stack. We were already shelling out for push tags (#459) and the credential-helper path requires shell-out anyway. - Writes through gix (create_commit, create_tag, create_branch) require hand-rolling index manipulation, tree writing, and ref edits. git's porcelain handles all the edge cases for free. - Diff via gix needs the blob-diff feature which pulls in gix-diff, gix-filter, gix-traverse - heavy for our use case (just list paths that changed). git diff-tree / git ls-tree is a one-liner. What gix is used for (the perf-sensitive read paths): - collect_all_tags, find_last_tag, find_highest_semver_tag, TagIndex (the hot path for monorepo tag scanning) - get_commits_since_oid (revwalk) - open_repo, get_repo_root, resolve_current_branch - find_object, find_commit, find_tree for tag-to-commit resolution - repo.references().tags() for tag iteration Auth path: - For shell-out calls (git push/fetch/ls-remote): inline credential helper via -c credential.helper config (no token in argv, no token in URL). - FERRFLOW_TOKEN / GITHUB_TOKEN / GITLAB_TOKEN env vars unchanged. Tests + benches: - Shell-out helpers in lib.rs::test_utils and main.rs::test_utils (git init/add/commit/tag) replace the git2-based fixture functions. - benches/ferrflow_benchmarks.rs uses the same shell-out fixture pattern; bench measurements stay comparable. - The fetch_and_rebase and reset_branch_to_remote integration tests (which set up two repos + a bare remote) were rewritten with shell-out — same scenarios, same assertions. - 512 lib tests pass, 614 bin tests pass, cargo clippy -D warnings clean. Cargo.lock no longer contains git2, libgit2-sys, or openssl-src. Also fixes two long-standing Publish workflow failures: - ferrflow-wasm: wasm-pack's bundled wasm-opt fails on the new compiler output. Disable it via [package.metadata.wasm-pack.profile.release]. - npm scope rename: @ferrflow/* -> @ferrlabs/ferrflow-* (platforms), ferrflow -> @ferrlabs/ferrflow (wrapper), and @ferrflow/wasm -> @ferrlabs/ferrflow-wasm. The old @ferrflow user scope wasn't writable by the bot token; the @FerrLabs org scope is. The breaking-change marker (!) is dropped: v5.0.0 already shipped via #486 (the auth refactor) which is the SemVer-breaking piece of this work for downstream embedders of ferrflow::git::auth. This follow-up is a pure refactor with no public API change.
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.
Closes #485
Builds on #479 (full gix migration plan)
Summary
Why this is a breaking change
The internal auth helper API changed (`get_authenticated_remote` -> `get_remote`), but the user-facing env-var contract (`FERRFLOW_TOKEN`, `GITHUB_TOKEN`, `GITLAB_TOKEN`) is unchanged. Marked breaking because any downstream consumer importing `ferrflow::git::auth::*` will see renamed symbols.
Test plan