[PATCH 1/3] cgit: skip the notes system when the repository failed to open

Konstantin Ryabitsev konstantin at linuxfoundation.org
Tue Aug 25 18:05:14 UTC 2026


prepare_repo_env() calls setup_git_directory_gently() and then loads the
display notes unconditionally. When the setup fails, because repo.path is
not a valid git directory, the notes loader still resolves
refs/notes/commits, which reads the_repository->hash_algo. Git leaves that
pointer NULL outside a repository since v2.46, so cgit dereferences NULL
and dies before prepare_repo_cmd() gets a chance to report the failure.

The gap is easy to reach through scan-path, because cgit's own is_git_dir()
only stats objects/ and HEAD while git additionally requires refs/ and a
HEAD it can validate. A repository that is being created or replicated
therefore appears in the index and crashes every page that touches it.

Skip the notes system when the setup did not find a repository, and let
prepare_repo_cmd() print the config error page it already has. Cover the
three shapes a broken repo.path can take with a test.

Fixes: 8a92df0 ("Do not load user or system gitconfig and gitattributes")
Assisted-by: LLM [analysis, codegen, tests]
Signed-off-by: Konstantin Ryabitsev <konstantin at linuxfoundation.org>
---
 cgit.c                           |  7 ++++--
 tests/t0023-invalid-repo-path.sh | 51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/cgit.c b/cgit.c
index ca318e8..47471b0 100644
--- a/cgit.c
+++ b/cgit.c
@@ -587,9 +587,12 @@ static void prepare_repo_env(int *nongit)
 
 	/* Setup the git directory and initialize the notes system. Both of these
 	 * load local configuration from the git repository, so we do them both while
-	 * the HOME variables are unset. */
+	 * the HOME variables are unset. The notes system resolves a ref, which
+	 * needs a repository: skip it when the setup above failed, and let
+	 * prepare_repo_cmd() report the failure instead. */
 	setup_git_directory_gently(nongit);
-	load_display_notes(NULL);
+	if (!*nongit)
+		load_display_notes(NULL);
 }
 
 static int prepare_repo_cmd(int nongit)
diff --git a/tests/t0023-invalid-repo-path.sh b/tests/t0023-invalid-repo-path.sh
new file mode 100755
index 0000000..891c6c0
--- /dev/null
+++ b/tests/t0023-invalid-repo-path.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+test_description='Check handling of a repo.path that is not a git directory'
+. ./setup.sh
+
+# A repo.path can stop being a valid git directory at any time: the directory
+# is removed, a symlink goes dangling, or the repository format is one this
+# build refuses. cgit is supposed to answer with its "config error" page, so
+# every page has to survive the failed setup rather than dereference a
+# repository that was never opened.
+
+setup_broken_repos() {
+	rm -rf broken && mkdir -p broken/empty-dir &&
+	git init -q --bare broken/badformat &&
+	git -C broken/badformat config core.repositoryformatversion 1 &&
+	git -C broken/badformat config extensions.frobnicate true &&
+	cat >>cgitrc <<-EOF
+	repo.url=gone
+	repo.path=$PWD/broken/does-not-exist
+	repo.desc=vanished repo
+
+	repo.url=empty-dir
+	repo.path=$PWD/broken/empty-dir
+	repo.desc=not a git directory
+
+	repo.url=badformat
+	repo.path=$PWD/broken/badformat
+	repo.desc=unsupported repository format
+	EOF
+}
+
+test_expect_success 'setup' 'setup_broken_repos'
+
+for repo in gone empty-dir badformat
+do
+	for page in summary log tree commit diff refs
+	do
+		test_expect_success "$page of a $repo repo reports a config error" '
+			cgit_url "'"$repo"'/'"$page"'" >output &&
+			grep -q "config error" output &&
+			grep -q "Failed to open" output
+		'
+	done
+done
+
+test_expect_success 'a bogus repo does not crash with an object id either' '
+	cgit_url "gone/commit/&id=HEAD" >output &&
+	grep -q "config error" output
+'
+
+test_done

-- 
2.55.0



More information about the CGit mailing list