Fix user git access#4253
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates libgit2 initialization for Hugging Face git-clone based model pulls to avoid repository access failures when model directories are owned by a different OS user.
Changes:
- Disables libgit2 owner validation for repositories opened by OVMS.
- Clears selected libgit2 git config search paths to avoid reading host/user git configuration.
- Disables pack
.keepfile checks to reduce stat calls during repository operations.
| // Redirect all git config search paths to an empty string so libgit2 never reads | ||
| // host-level git configuration (~/.gitconfig, /etc/gitconfig, etc.). Without this, | ||
| // a host gitconfig that sets credential.helper, http.proxy, lfs.*, or safe.directory | ||
| // can silently override OVMS's intended proxy/token settings and cause spurious | ||
| // failures or credential leaks in multi-tenant environments. | ||
| // On Windows, GIT_CONFIG_LEVEL_PROGRAMDATA covers %PROGRAMDATA%\Git\config which is | ||
| // a machine-wide config that libgit2 reads before SYSTEM; it must be cleared as well. | ||
| this->status = git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, ""); | ||
| IF_ERROR_SET_MSG_AND_RETURN(); | ||
| this->status = git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, ""); | ||
| IF_ERROR_SET_MSG_AND_RETURN(); | ||
| this->status = git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, ""); | ||
| IF_ERROR_SET_MSG_AND_RETURN(); |
There was a problem hiding this comment.
Shouldn't this be limited only to container environments? Even then(in container) one could want to override some git settings used by OVMS.
There was a problem hiding this comment.
The settings may affect the resume and download logic. We do not want to risk this kind of situation.
| candidates.hasWipMarker = libgit2::hasLfsWipMarker(downloadPath); | ||
| candidates.hasLfsErrorFile = libgit2::hasLfsErrorFile(downloadPath); | ||
|
|
||
| ResumeCandidates buildResumeCandidates(git_repository* repo, const std::string& downloadPath, ResumeCandidates candidates) { |
There was a problem hiding this comment.
Minor but we create a copy of resume candidates. Couldn't we return ptr then?
| // The user has copied model files in by hand; skip the pull and let model loading proceed | ||
| // against whatever files are already on disk. Use --overwrite_models to replace it with a | ||
| // fresh download. | ||
| bool resumeCheckSecondCondition(const std::string& downloadPath, const ResumeCandidates& candidates) { |
There was a problem hiding this comment.
First/Second -> whats the meaning of First/Second? Be more descriptive in naming. eg resumeCheckDotGitExistence
| return StatusCode::OK; | ||
| } | ||
|
|
||
| Status handleExistingRepositoryWithoutOverwrite(const std::string& downloadPath, |
| } | ||
|
|
||
| auto candidates = buildResumeCandidates(repoGuard.get(), downloadPath); | ||
| candidates = buildResumeCandidates(repoGuard.get(), downloadPath, std::move(candidates)); |
There was a problem hiding this comment.
Just pass candidates as reference?
|
|
||
| class Libgt2InitGuardTest : public ::testing::Test { | ||
| protected: | ||
| TempDir td; |
| // container vs. a non-root serving user). | ||
| this->status = git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 0); | ||
| IF_ERROR_SET_MSG_AND_RETURN(); | ||
| const char* enableSearchPathEnv = std::getenv("GIT_OPT_SET_ENABLE_SEARCH_PATHS"); |
| envGuard.set("GIT_OPT_SET_ENABLE_SEARCH_PATHS", "1"); | ||
|
|
||
| std::array<std::string, 3> baselinePaths; | ||
| ASSERT_EQ(git_libgit2_init(), 1); | ||
| { | ||
| git_buf systemBuf = GIT_BUF_INIT; | ||
| ASSERT_EQ(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, &systemBuf), 0); | ||
| baselinePaths[0] = (systemBuf.ptr != nullptr) ? systemBuf.ptr : ""; | ||
| git_buf_dispose(&systemBuf); | ||
|
|
||
| git_buf xdgBuf = GIT_BUF_INIT; | ||
| ASSERT_EQ(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, &xdgBuf), 0); | ||
| baselinePaths[1] = (xdgBuf.ptr != nullptr) ? xdgBuf.ptr : ""; | ||
| git_buf_dispose(&xdgBuf); | ||
|
|
||
| git_buf globalBuf = GIT_BUF_INIT; | ||
| ASSERT_EQ(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &globalBuf), 0); | ||
| baselinePaths[2] = (globalBuf.ptr != nullptr) ? globalBuf.ptr : ""; | ||
| git_buf_dispose(&globalBuf); | ||
| } | ||
| git_libgit2_shutdown(); | ||
|
|
||
| ovms::Libgt2InitGuard guard(defaultOpts); | ||
| ASSERT_GE(guard.status, 0); | ||
|
|
||
| git_buf systemBuf = GIT_BUF_INIT; | ||
| ASSERT_EQ(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, &systemBuf), 0); | ||
| EXPECT_EQ((systemBuf.ptr != nullptr) ? systemBuf.ptr : "", baselinePaths[0]); | ||
| git_buf_dispose(&systemBuf); | ||
|
|
||
| git_buf xdgBuf = GIT_BUF_INIT; | ||
| ASSERT_EQ(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, &xdgBuf), 0); | ||
| EXPECT_EQ((xdgBuf.ptr != nullptr) ? xdgBuf.ptr : "", baselinePaths[1]); | ||
| git_buf_dispose(&xdgBuf); | ||
|
|
||
| git_buf globalBuf = GIT_BUF_INIT; | ||
| ASSERT_EQ(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &globalBuf), 0); | ||
| EXPECT_EQ((globalBuf.ptr != nullptr) ? globalBuf.ptr : "", baselinePaths[2]); | ||
| git_buf_dispose(&globalBuf); | ||
| } |
There was a problem hiding this comment.
Create utility that will check expected variable values with boolean parameter (useGlobal)
Then we need either 1 test or 3 tests when we check
checkifUsingGlobalConfig( boolean expectToUseGlobal)
3 cases:
- Undefined env GIT_OPT_SET_ENABLE_SEARCH_PATHS
- defined set to 0
- defined set to 1

🛠 Summary
JIRA CVS-187604
Disables libgit2 owner validation for repositories opened by OVMS.
Clears selected libgit2 git config search paths to avoid reading host/user git configuration.
Disables pack .keep file checks to reduce stat calls during repository operations.
🧪 Checklist
``