Skip to content

Commit fee4b79

Browse files
Merge branch 'main' into brendan/cve-simple-git
2 parents 07eeeb2 + eb64ef0 commit fee4b79

26 files changed

Lines changed: 489 additions & 89 deletions

‎CHANGELOG.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Added `exclude.private` option to github connection config. [#1632](https://github.com/sourcebot-dev/sourcebot/pull/1632)
12+
1013
### Fixed
1114
- Silenced a false-positive `MaxListenersExceededWarning` logged on every request proxied through an external rewrite. [#1697](https://github.com/sourcebot-dev/sourcebot/pull/1697)
1215
- Upgraded `brace-expansion` to `^1.1.21`, `^2.1.7`, and `^5.0.12`. [#1700](https://github.com/sourcebot-dev/sourcebot/pull/1700)
@@ -17,6 +20,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1720
- Upgraded `next` to `^16.3.8`. [#1709](https://github.com/sourcebot-dev/sourcebot/pull/1709)
1821
- Upgraded `seroval` to `^1.6.8`, `proxy-addr` to `^2.0.8`, `shell-quote` to `^1.12.0`, and `@grpc/grpc-js` to `^1.14.6`. [#1713](https://github.com/sourcebot-dev/sourcebot/pull/1713)
1922
- Upgraded `simple-git` to `^4.0.2`. [#1715](https://github.com/sourcebot-dev/sourcebot/pull/1715)
23+
- Upgraded `katex` to `^0.18.2` and `postcss-selector-parser` to `^7.1.6`. [#1717](https://github.com/sourcebot-dev/sourcebot/pull/1717)
24+
- Upgraded `engine.io` to `^6.6.11`, `source-map-js` to `^1.2.2`, `smol-toml` to `^1.9.0`, `fast-copy` to `^3.1.0`, and `dompurify` to `^3.4.16`. [#1714](https://github.com/sourcebot-dev/sourcebot/pull/1714)
25+
- Upgraded `golang.org/x/crypto` to `v0.56.0` and OpenTelemetry-Go exporters and SDK to `v1.45.0` in Zoekt. [#1716](https://github.com/sourcebot-dev/sourcebot/pull/1716)
26+
- Upgraded `@modelcontextprotocol/sdk` to `^1.32.1`. [#1719](https://github.com/sourcebot-dev/sourcebot/pull/1719)
27+
- Decoded percent-encoded characters in repo names derived from direct generic git URLs. [#1666](https://github.com/sourcebot-dev/sourcebot/pull/1666)
28+
- Fixed `.gitattributes` `linguist-language` overrides being ignored for files in subdirectories. [#1692](https://github.com/sourcebot-dev/sourcebot/pull/1692)
29+
- Fixed selected language and repository filters disappearing when filtering the available options. [#1685](https://github.com/sourcebot-dev/sourcebot/pull/1685)
30+
- Fixed code highlights not covering every line of a multi-line range. [#1699](https://github.com/sourcebot-dev/sourcebot/pull/1699)
2031

2132
## [5.1.15] - 2026-09-29
2233

‎Dockerfile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ ARG NEXT_PUBLIC_SENTRY_BACKEND_DSN
1414
ARG NEXT_PUBLIC_BUILD_COMMIT_SHA
1515

1616
FROM node:24-alpine3.23 AS node-alpine
17-
FROM golang:1.25-alpine AS go-alpine
17+
FROM golang:1.26-alpine AS go-alpine
1818
# ----------------------------------
1919

2020
# ------ Build Zoekt ------

‎docs/snippets/schemas/v3/connection.schema.mdx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@
125125
"default": false,
126126
"description": "Exclude archived repositories from syncing."
127127
},
128+
"private": {
129+
"type": "boolean",
130+
"default": false,
131+
"description": "Exclude private repositories from syncing. Internal repositories are not affected."
132+
},
128133
"repos": {
129134
"type": "array",
130135
"items": {

‎docs/snippets/schemas/v3/github.schema.mdx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@
121121
"default": false,
122122
"description": "Exclude archived repositories from syncing."
123123
},
124+
"private": {
125+
"type": "boolean",
126+
"default": false,
127+
"description": "Exclude private repositories from syncing. Internal repositories are not affected."
128+
},
124129
"repos": {
125130
"type": "array",
126131
"items": {

‎docs/snippets/schemas/v3/index.schema.mdx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,11 @@
622622
"default": false,
623623
"description": "Exclude archived repositories from syncing."
624624
},
625+
"private": {
626+
"type": "boolean",
627+
"default": false,
628+
"description": "Exclude private repositories from syncing. Internal repositories are not affected."
629+
},
625630
"repos": {
626631
"type": "array",
627632
"items": {

‎package.json‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@
6666
"fast-uri@npm:^3.0.1": "^3.1.2",
6767
"shell-quote@npm:1.8.3": "^1.8.4",
6868
"ws@npm:~8.20.1": "^8.21.0",
69-
"postcss-selector-parser@npm:6.0.10": "^6.1.3"
69+
"postcss-selector-parser@npm:6.0.10": "^7.1.6",
70+
"postcss-selector-parser@npm:^6.1.1": "^7.1.6",
71+
"postcss-selector-parser@npm:^6.1.2": "^7.1.6",
72+
"postcss-selector-parser@npm:^6.1.3": "^7.1.6",
73+
"katex@npm:^0.16.45": "^0.18.2"
7074
}
7175
}

‎packages/backend/src/github.test.ts‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,40 @@ test('shouldExcludeRepo handles archived repos correctly', () => {
214214
expect(shouldExcludeRepo({ repo, exclude: { archived: false } })).toBe(false);
215215
});
216216

217+
test('shouldExcludeRepo handles private repos correctly', () => {
218+
const privateRepo = {
219+
full_name: 'test/private-repo',
220+
clone_url: 'https://github.com/test/private-repo.git',
221+
private: true,
222+
visibility: 'private',
223+
} as OctokitRepository;
224+
225+
expect(shouldExcludeRepo({ repo: privateRepo })).toBe(false);
226+
expect(shouldExcludeRepo({ repo: privateRepo, exclude: { private: true } })).toBe(true);
227+
expect(shouldExcludeRepo({ repo: privateRepo, exclude: { private: false } })).toBe(false);
228+
});
229+
230+
test('shouldExcludeRepo does not exclude internal repos when exclude.private is true', () => {
231+
const internalRepo = {
232+
full_name: 'test/internal-repo',
233+
clone_url: 'https://github.com/test/internal-repo.git',
234+
private: true,
235+
visibility: 'internal',
236+
} as OctokitRepository;
237+
238+
expect(shouldExcludeRepo({ repo: internalRepo, exclude: { private: true } })).toBe(false);
239+
});
240+
241+
test('shouldExcludeRepo excludes private repos with missing visibility when exclude.private is true', () => {
242+
const repo = {
243+
full_name: 'test/private-no-visibility',
244+
clone_url: 'https://github.com/test/private-no-visibility.git',
245+
private: true,
246+
} as OctokitRepository;
247+
248+
expect(shouldExcludeRepo({ repo, exclude: { private: true } })).toBe(true);
249+
});
250+
217251
test('shouldExcludeRepo handles include.topics correctly', () => {
218252
const repo = {
219253
full_name: 'test/repo',

‎packages/backend/src/github.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export type OctokitRepository = {
7777
full_name: string,
7878
fork: boolean,
7979
private: boolean,
80+
visibility?: string,
8081
html_url: string,
8182
clone_url?: string,
8283
stargazers_count?: number,
@@ -507,6 +508,11 @@ export const shouldExcludeRepo = ({
507508
return true;
508509
}
509510

511+
if (!!exclude?.private && repo.private && repo.visibility !== 'internal') {
512+
reason = `\`exclude.private\` is true`;
513+
return true;
514+
}
515+
510516
if (exclude?.repos) {
511517
if (micromatch.isMatch(repoName, exclude.repos)) {
512518
reason = `\`exclude.repos\` contains ${repoName}`;

‎packages/backend/src/repoCompileUtils.test.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,4 +334,24 @@ describe('compileGenericGitHostConfig_url', () => {
334334
const metadata = result[0].metadata as { gitConfig?: Record<string, string> };
335335
expect(metadata.gitConfig!['zoekt.name']).toBe('github.com/test/repo');
336336
});
337+
338+
test('should decode percent-encoded characters in the repo name', async () => {
339+
mockedIsUrlAValidGitRepo.mockResolvedValue(true);
340+
341+
const config = {
342+
type: 'git' as const,
343+
url: 'https://github.com/test/Project%20Name%20With%20Spaces.git',
344+
};
345+
346+
const result = await compileGenericGitHostConfig_url(config, 1);
347+
348+
expect(result).toHaveLength(1);
349+
// The repo name should have decoded spaces, not %20
350+
expect(result[0].name).toBe('github.com/test/Project Name With Spaces');
351+
expect(result[0].displayName).toBe('github.com/test/Project Name With Spaces');
352+
353+
const metadata = result[0].metadata as { gitConfig?: Record<string, string> };
354+
expect(metadata.gitConfig!['zoekt.name']).toBe('github.com/test/Project Name With Spaces');
355+
expect(metadata.gitConfig!['zoekt.display-name']).toBe('github.com/test/Project Name With Spaces');
356+
});
337357
});

‎packages/backend/src/repoCompileUtils.ts‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,28 @@ export const compileGenericGitHostConfig_url = async (
725725

726726
// @note: matches the naming here:
727727
// https://github.com/sourcebot-dev/zoekt/blob/main/gitindex/index.go#L293
728-
const repoName = path.join(remoteUrl.host, remoteUrl.pathname.replace(/\.git$/, ''));
728+
// Decode URL-encoded characters (e.g., %20 -> space) to ensure consistent repo names
729+
let decodedPathname: string;
730+
try {
731+
decodedPathname = decodeURIComponent(remoteUrl.pathname);
732+
} catch (e) {
733+
if (e instanceof URIError) {
734+
const warning = `Skipping ${remoteUrl.toString()} - malformed URL encoding.`;
735+
logger.warn(warning);
736+
reportRepositoryDiscoveryIssue({
737+
code: "INVALID_REPOSITORY_SOURCE",
738+
effect: "TARGET_SKIPPED",
739+
subject: {
740+
kind: "url",
741+
value: remoteUrl.toString(),
742+
},
743+
message: warning,
744+
});
745+
return [];
746+
}
747+
throw e;
748+
}
749+
const repoName = path.join(remoteUrl.host, decodedPathname.replace(/\.git$/, ''));
729750

730751
const repo: RepoData = {
731752
external_codeHostType: 'genericGitHost',

0 commit comments

Comments
 (0)