Skip to content
Open
Changes from 1 commit
Commits
Show all changes
1045 commits
Select commit Hold shift + click to select a range
a1bab38
Merge branch 'feat/e2e-dashboard-tests' of https://github.com/fabiovi…
fabiovincenzi Feb 20, 2026
28b570b
chore: improve error messages in push actions
jescalada Feb 20, 2026
143a9eb
chore: don't throw error on writePack, update tests
jescalada Feb 20, 2026
1ed9bd5
chore: push, don't overwrite history so browser works
andypols Feb 20, 2026
e6cec75
chore: fix push sort order to be latest-first
andypols Feb 20, 2026
960bad5
feat: add ErrorBoundary component to handle errors in Dashboard layout
dcoric Feb 20, 2026
5af1982
Merge remote-tracking branch 'finos/main' into denis-coric/fix-1392-l…
dcoric Feb 21, 2026
a2d3ffd
feat: add validateAttestation function to check attestation questions…
jescalada Feb 21, 2026
f2c0c60
feat: add CompletedAttestation, AttestationAnswer types and fix type …
jescalada Feb 21, 2026
8016d83
fix: failing e2e test due to boolean/string casting in validateAttest…
jescalada Feb 21, 2026
bae44da
refactor: src/services/routes/repo.ts into function, remove unnecessa…
jescalada Feb 21, 2026
8dd60cb
fix: RepoDetails classes and aria-label, PushRequests/PushesTable err…
jescalada Feb 21, 2026
e1a6008
Merge branch 'main' into tab1-update-website
jescalada Feb 23, 2026
692531b
Merge pull request #1286 from tabathad/tab1-update-website
jescalada Feb 23, 2026
c970f67
test: revert test removal due to type errors and use unknown casting …
jescalada Feb 23, 2026
78778ca
chore: add @andypols to list of maintainers
jescalada Feb 23, 2026
5316a81
Merge branch 'main' into add-reject-reason
andypols Feb 23, 2026
14ce0b6
Merge branch 'main' into feat/e2e-dashboard-tests
fabiovincenzi Feb 23, 2026
7ac5912
fix: integration test
andypols Feb 23, 2026
fa6c123
fix: improve error handling and logging in ErrorBoundary and auth ser…
dcoric Feb 23, 2026
67b85b2
Merge remote-tracking branch 'finos/main' into denis-coric/fix-1392-l…
dcoric Feb 23, 2026
5c4329c
Merge pull request #1396 from qube-rt/add-reject-reason
jescalada Feb 23, 2026
473c982
Merge branch 'main' into website-add-andy-to-maintainers
kriswest Feb 23, 2026
5f81021
docs: restructure contributing docs and improve E2E test infrastructure
coopernetes Feb 9, 2026
3974e2d
docs: move usage to quickstart
tabathad Feb 23, 2026
2472f39
Merge branch 'main' into docs/deployment-guide
tabathad Feb 23, 2026
e174392
docs(fix): remove duplicate usage in sidebar
tabathad Feb 23, 2026
0908706
docs: update path to installation page
tabathad Feb 23, 2026
dfa1d88
fix: rm duplicate supertest dependency
andypols Feb 24, 2026
7ee282c
Merge remote-tracking branch 'finos/main' into denis-coric/fix-1392-l…
dcoric Feb 24, 2026
28aac41
Apply suggestion from @kriswest
kriswest Feb 24, 2026
6713757
Merge pull request #1413 from finos/website-add-andy-to-maintainers
kriswest Feb 24, 2026
0bc60bf
Merge branch 'main' into update-quickstart
tabathad Feb 24, 2026
850ea55
Merge branch 'main' into rm-dup-supertest
jescalada Feb 25, 2026
2c2b093
Merge branch 'main' into denis-coric/fix-1392-linked
jescalada Feb 25, 2026
b937878
Merge pull request #1406 from dcoric/denis-coric/fix-1392-linked
jescalada Feb 25, 2026
48614fb
refactor(ui): replace async/await and promise chaining mixing with co…
fabiovincenzi Feb 25, 2026
ad24af3
fix(ssh): use authenticated user identity from transport layer in par…
fabiovincenzi Feb 25, 2026
a56700f
Merge remote-tracking branch 'upstream/main' into ssh-agent-on-pr987
fabiovincenzi Feb 25, 2026
be7759a
fix(pullRemote): restore concurrent request check and directory clean…
fabiovincenzi Feb 25, 2026
c4f36b7
fix(ssh): add proper TypeScript types to SSH key route params
fabiovincenzi Feb 25, 2026
79b6f7c
fix(ssh): use path.join in test assertions for cross-platform path co…
fabiovincenzi Feb 25, 2026
021e901
Merge branch 'main' into rm-dup-supertest
andypols Feb 25, 2026
bc8eedc
Merge pull request #1419 from andypols/rm-dup-supertest
jescalada Feb 25, 2026
977158b
Update website/docs/quickstart/usage.mdx
tabathad Feb 25, 2026
0c1b077
Merge branch 'main' into update-quickstart
tabathad Feb 25, 2026
a28ce83
Merge branch 'main' into 1174-remove-any-and-as-ts-wrapup
jescalada Feb 25, 2026
e828482
fix: rejection contents and type in autoActions.ts
jescalada Feb 25, 2026
d559cab
chore: ignore experimental packages in renovate.json (#1401)
jescalada Feb 26, 2026
a08379a
docs: move installation.mdx into quickstart directory
jescalada Feb 26, 2026
a1e62d3
docs: update sidebars.js
jescalada Feb 26, 2026
3392dd0
chore(deps): update github-actions - workflows - .github/workflows/do…
renovate[bot] Feb 26, 2026
097d2ff
Merge branch 'main' into update-quickstart
kriswest Feb 26, 2026
cd14cec
Merge pull request #1417 from tabathad/update-quickstart
kriswest Feb 26, 2026
f885211
Merge branch 'main' into docs/contrib-fixup
coopernetes Feb 26, 2026
7fb692e
Merge pull request #1398 from RBC/docs/contrib-fixup
coopernetes Feb 26, 2026
ea19387
chore(deps): update httpd:2.4 docker digest to 96b1e8f - localgit - l…
renovate[bot] Feb 26, 2026
9bb8059
Merge pull request #1425 from finos/renovate/localgit-manager
jescalada Feb 27, 2026
a685438
chore(deps): update actions/download-artifact action to v8 - workflow…
renovate[bot] Feb 27, 2026
730b5d1
Merge branch 'main' into move-sort-to-db
andypols Mar 2, 2026
363e3e1
chore: merge upstream main
fabiovincenzi Mar 2, 2026
ec728a0
fix: type error
andypols Mar 2, 2026
186c984
Merge branch 'main' into fix-dashboard-navigation
andypols Mar 2, 2026
fb025a0
Merge branch 'main' into 1174-remove-any-and-as-ts-wrapup
jescalada Mar 2, 2026
9e0ceec
test: fix confusing helper test
jescalada Mar 2, 2026
2105335
Merge pull request #1429 from finos/renovate/workflows-major-8-github…
jescalada Mar 3, 2026
dd291b0
chore(deps): update github-actions - workflows - .github/workflows/e2…
renovate[bot] Mar 3, 2026
96d1dd3
Merge pull request #1426 from finos/renovate/workflows-manager
jescalada Mar 3, 2026
bd82eaa
fix(deps): update dependency axios to ^1.13.6 - git-proxy-cli - packa…
renovate[bot] Mar 3, 2026
f938c42
Merge pull request #1427 from finos/renovate/git-proxy-cli-manager
jescalada Mar 3, 2026
23b69c8
chore(deps): update dependency @eslint/json to v1 - - package.json
renovate[bot] Mar 3, 2026
25277e3
Merge pull request #1434 from finos/renovate/major-1-npm
jescalada Mar 3, 2026
54293b7
Merge branch 'main' into fix-dashboard-navigation
andypols Mar 3, 2026
5b992bd
Merge branch 'main' into move-sort-to-db
andypols Mar 3, 2026
019c8a6
Merge pull request #1431 from qube-rt/move-sort-to-db
kriswest Mar 3, 2026
a177b01
chore(deps): update github-actions to v5 - workflows - .github/workfl…
renovate[bot] Mar 3, 2026
3872b14
Merge pull request #1437 from finos/renovate/workflows-major-5-github…
jescalada Mar 3, 2026
0a25231
Merge branch 'main' into fix-dashboard-navigation
andypols Mar 3, 2026
0448190
Merge pull request #1433 from qube-rt/fix-dashboard-navigation
jescalada Mar 3, 2026
28b337c
chore(deps): update github-actions to v6 - workflows - .github/workfl…
renovate[bot] Mar 3, 2026
53c9353
Merge pull request #1438 from finos/renovate/workflows-major-6-github…
jescalada Mar 3, 2026
f0478ac
chore(deps): update github-actions to v7 - workflows - .github/workfl…
renovate[bot] Mar 3, 2026
1bda10c
Merge pull request #1439 from finos/renovate/workflows-major-7-github…
jescalada Mar 3, 2026
bfa0e72
Merge branch 'main' into improve-test-coverage
jescalada Mar 3, 2026
2d0a092
fix: failing push test due to renamed field
jescalada Mar 3, 2026
b9b684a
Merge branch 'main' into improve-test-coverage
jescalada Mar 3, 2026
887a669
test: fix failing push test due to missing sort entry
jescalada Mar 3, 2026
f3b9e4e
Merge branch 'main' into ssh-agent-on-pr987
fabiovincenzi Mar 4, 2026
cd90d1b
chore: merge upstream main
fabiovincenzi Mar 4, 2026
8606a21
refactor(ui): replace promise chaining with async/await in repo service
fabiovincenzi Mar 4, 2026
5445793
chore: merge upstream main
fabiovincenzi Mar 4, 2026
2949e9e
test(e2e): add repo cleanup commands and fix delete using _id
fabiovincenzi Mar 4, 2026
95d2a8d
fix(e2e): use correct test-owner/test-repo in Cypress commands
fabiovincenzi Mar 4, 2026
0c76acd
fix(e2e): logout after cleaning
fabiovincenzi Mar 4, 2026
5a58db5
Merge pull request #1421 from fabiovincenzi/fix/async-await-consistency
jescalada Mar 4, 2026
1e272b4
chore(deps): update github-actions to v4 - workflows - .github/workfl…
renovate[bot] Mar 4, 2026
2f654fb
test: consolidate duplicate afterAll in testPush
jescalada Mar 4, 2026
bd985e2
Merge branch 'main' into improve-test-coverage
jescalada Mar 4, 2026
a3b612d
test: add cases for 401 and 404 checks in push routes
jescalada Mar 4, 2026
9b8bfed
Merge branch 'improve-test-coverage' of https://github.com/jescalada/…
jescalada Mar 4, 2026
c880780
test: add tests for fetch by ID and filtering
jescalada Mar 4, 2026
d33b3ab
test: add edge case checks for 400, 401, 403
jescalada Mar 4, 2026
6d26ccf
Merge pull request #1441 from finos/renovate/workflows-major-4-github…
jescalada Mar 4, 2026
2afedcc
chore(deps): update github-actions - workflows - .github/workflows/un…
renovate[bot] Mar 4, 2026
39fe246
test: add missing 404 edge case test for approval
jescalada Mar 4, 2026
3c43652
Merge pull request #1440 from finos/renovate/workflows-manager
jescalada Mar 4, 2026
698e39f
Merge branch 'main' into improve-test-coverage
jescalada Mar 4, 2026
fd151da
chore: add CustomTabs to show different push data
andypols Mar 4, 2026
7b504f5
chore: add StepsTimeline to show results from each push action
andypols Mar 4, 2026
6706274
chore: add optional numeric badge
andypols Mar 4, 2026
8f95c5c
chore: make header the primary colour to match dashboard
andypols Mar 4, 2026
ac353de
Merge pull request #1356 from jescalada/improve-test-coverage
jescalada Mar 5, 2026
9fa39cf
Update src/config/validators.ts
jescalada Mar 5, 2026
3fcbc58
Merge branch 'main' into 1174-remove-any-and-as-ts-wrapup
jescalada Mar 5, 2026
da95d85
Merge branch 'main' into 1174-remove-any-and-as-ts-wrapup
jescalada Mar 5, 2026
5f77ec5
refactor: flatten repo test endpoints and fix failing tests
jescalada Mar 5, 2026
0d378ec
fix: remove any types, improve error handler functions
jescalada Mar 5, 2026
5e9adf1
chore: add eslint license header plugin to devDependencies
jescalada Mar 6, 2026
ca6114c
chore: add license header plugin to eslint config, add licenseHeader.js
jescalada Mar 6, 2026
24d1a59
chore: add license headers
jescalada Mar 6, 2026
c6a578e
fix: relative path bug for license header file
jescalada Mar 6, 2026
9e287a1
Merge branch 'main' into display-git-push-actions
andypols Mar 6, 2026
308d747
Merge branch 'main' into feat/e2e-dashboard-tests
fabiovincenzi Mar 6, 2026
492ce79
refactor: remove or replace unnecessary console.log with step.log
jescalada Mar 6, 2026
dbd797b
chore: remove unnecessary ellipses on logs
jescalada Mar 6, 2026
3c68dd9
test: fix logging-reliant tests, remove log stubs/spies
jescalada Mar 8, 2026
90df884
Merge pull request #1447 from jescalada/1002-eslint-plugin-license-he…
jescalada Mar 8, 2026
adf28a1
Merge branch 'main' into 1281-improve-processors-logging
jescalada Mar 8, 2026
6a2cefe
Merge branch 'main' into 1174-remove-any-and-as-ts-wrapup
jescalada Mar 8, 2026
b2126db
chore: npm run lint:fix
jescalada Mar 8, 2026
bab1881
fix: error message check in cypress test
jescalada Mar 8, 2026
6f2d840
Merge branch 'main' into display-git-push-actions
andypols Mar 9, 2026
cdd9335
chore: add missing license headers
andypols Mar 9, 2026
ccef965
Merge branch 'main' into feat/e2e-dashboard-tests
jescalada Mar 9, 2026
1c4ba16
chore: add missing header
fabiovincenzi Mar 9, 2026
2dfb917
Merge branch 'main' into docs/deployment-guide
tabathad Mar 9, 2026
93c5bb6
Update src/proxy/processors/push-action/preReceive.ts
jescalada Mar 10, 2026
c37cbab
Update src/proxy/chain.ts
jescalada Mar 10, 2026
7486aaa
fix: parsePush error handling
jescalada Mar 10, 2026
833543e
chore: fix duplicate apache headers
jescalada Mar 10, 2026
4b7d295
Merge branch '1174-remove-any-and-as-ts-wrapup' of https://github.com…
jescalada Mar 10, 2026
2ee4f68
chore: merge upstream main
fabiovincenzi Mar 11, 2026
c3bd14e
Merge branch 'ssh-agent-on-pr987' of https://github.com/fabiovincenzi…
fabiovincenzi Mar 11, 2026
5e2d0a9
fix: do not overwrite publicKeys on updateUser
fabiovincenzi Mar 11, 2026
a4f12d4
refactor: remove logs for chunks/changes in scanDiff
jescalada Mar 11, 2026
c9a8bb3
chore: ensure Timeline gets steps
andypols Mar 11, 2026
a94864a
chore: ensure errorCount does not fail in steps undefined
andypols Mar 11, 2026
17dc7f2
chore: open first error step
andypols Mar 11, 2026
1c6c541
Merge pull request #1323 from jescalada/1174-remove-any-and-as-ts-wrapup
kriswest Mar 11, 2026
35adcb6
Merge branch 'main' into 1281-improve-processors-logging
jescalada Mar 14, 2026
93286e8
refactor: rename error handling functions, add step error logger
jescalada Mar 14, 2026
b744a20
Merge branch 'main' into feat/e2e-dashboard-tests
jescalada Mar 15, 2026
9f148a4
Merge pull request #1403 from fabiovincenzi/feat/e2e-dashboard-tests
jescalada Mar 15, 2026
7a1ca00
fix: use CompletedAttestation.answers in AttestationView
fabiovincenzi Mar 16, 2026
d65c9b8
Merge pull request #1459 from fabiovincenzi/fix/attestation-view-answ…
jescalada Mar 16, 2026
cd42eeb
chore: remove parsePush logging
jescalada Mar 16, 2026
c6c703e
Merge branch 'main' into 1281-improve-processors-logging
jescalada Mar 16, 2026
864559e
Merge pull request #1448 from jescalada/1281-improve-processors-logging
jescalada Mar 16, 2026
f52760d
chore: bump git-proxy version to 2.0.0-rc.5
jescalada Mar 16, 2026
cc5e5f3
Merge pull request #1461 from finos/rc5-bump
jescalada Mar 16, 2026
264223d
chore: drop node 20 support, replace with 22
jescalada Mar 16, 2026
072563b
chore: run `npm audit fix`
jescalada Mar 16, 2026
142223e
chore: add Artistic-2.0 to allowed licenses
jescalada Mar 16, 2026
e75310d
docs: explain Node deprecation in CONTRIBUTING.md
jescalada Mar 16, 2026
6459080
fix: broken link to usage.mdx
jescalada Mar 17, 2026
a13f35c
Merge branch 'main' into docs/deployment-guide
jescalada Mar 17, 2026
758b2db
Merge pull request #1385 from tabathad/docs/deployment-guide
jescalada Mar 17, 2026
ec1a77d
Merge branch 'main' into display-git-push-actions
andypols Mar 18, 2026
f957ef8
Merge branch 'main' into 1456-drop-node-20-support
jescalada Mar 19, 2026
868652d
chore: remove node 20 from deployment guide, run `npm audit fix`
jescalada Mar 19, 2026
4fa50d3
chore: remove obsolete CI comment
jescalada Mar 19, 2026
00b6a06
chore: show message when no commit data
andypols Mar 19, 2026
ec0a993
Merge pull request #1462 from finos/1456-drop-node-20-support
jescalada Mar 22, 2026
244686a
chore(deps): update github-actions - workflows - .github/workflows/ci…
renovate[bot] Mar 22, 2026
7bbce24
Merge pull request #1465 from finos/renovate/workflows-manager
jescalada Mar 22, 2026
a635ae4
chore(deps): update httpd:2.4 docker digest to 331548c - localgit - l…
renovate[bot] Mar 22, 2026
68bf3db
Merge pull request #1466 from finos/renovate/localgit-manager
jescalada Mar 22, 2026
6ed9a5e
chore(deps): update dependency node to v24 - workflows - .github/work…
renovate[bot] Mar 22, 2026
6f9a16d
Merge branch 'main' into display-git-push-actions
andypols Mar 23, 2026
06bbe90
Merge pull request #1436 from finos/renovate/workflows-major-24-githu…
coopernetes Mar 23, 2026
fca94af
chore(deps): update node.js to v24 - - dockerfile
renovate[bot] Mar 23, 2026
c0ba816
Merge pull request #1445 from finos/renovate/major-24-dockerfile
coopernetes Mar 23, 2026
2cdd607
Update meeting_minutes.md issue tempalte
kriswest Mar 23, 2026
f097a06
Merge pull request #1473 from finos/kriswest-patch-meeting-minutes-te…
jescalada Mar 24, 2026
7d61115
chore(deps): update actions/upload-artifact action to v6 - workflows …
renovate[bot] Mar 24, 2026
212ab9d
Merge pull request #1468 from finos/renovate/workflows-major-6-github…
jescalada Mar 24, 2026
0cf32c2
chore(deps): update github/codeql-action digest to 72c0b0e - workflow…
renovate[bot] Mar 24, 2026
aecfa3d
Merge pull request #1469 from finos/renovate/workflows-manager
jescalada Mar 24, 2026
d48e3e0
chore(deps): update docker/setup-buildx-action action to v4 - workflo…
renovate[bot] Mar 24, 2026
8eb40f1
Merge pull request #1475 from finos/renovate/workflows-major-4-github…
jescalada Mar 24, 2026
e2bfd5f
chore(deps): update github-actions to v7 - workflows - .github/workfl…
renovate[bot] Mar 24, 2026
50f88d7
Merge pull request #1476 from finos/renovate/workflows-major-7-github…
jescalada Mar 24, 2026
8089983
fix(plugins): update sample plugin imports to use package subpath exp…
coopernetes Mar 26, 2026
0332a30
Merge branch 'main' into display-git-push-actions
andypols Mar 26, 2026
232980a
fix: release drafter permission error (#1482)
jescalada Mar 26, 2026
42e5131
Apply suggestion from @coopernetes
coopernetes Mar 26, 2026
01c544f
Merge branch 'main' into display-git-push-actions
andypols Mar 26, 2026
4e2eea8
Merge pull request #1446 from qube-rt/display-git-push-actions
andypols Mar 26, 2026
6529fc3
fix: broken plugin exports
jescalada Mar 25, 2026
e788ab7
Merge pull request #1489 from finos/1474-fix-broken-subpath-exports
jescalada Mar 31, 2026
579345b
ci: split e2e into parallel vitest and cypress jobs
fabiovincenzi Apr 1, 2026
1c57272
ci: add Docker BuildKit cache to e2e workflow
fabiovincenzi Apr 1, 2026
6ecdfc0
ci: add e2e result job to satisfy branch protection check
fabiovincenzi Apr 1, 2026
4b47144
docs: fix link to installation page
gep13 Apr 1, 2026
5e81660
Merge branch 'main' into fix/plugin-sample-exports
coopernetes Apr 1, 2026
3328267
ci: remove redundant artifact upload/download in CI
fabiovincenzi Apr 2, 2026
1d41221
ci: skip redundant npm ci in cypress-io/github-action
fabiovincenzi Apr 2, 2026
084a77a
ci: use --no-fund flag for npm ci
fabiovincenzi Apr 2, 2026
95110da
Update badge link: stages → maturity in README.md
TheJuanAndOnly99 Apr 2, 2026
a7936c6
chore: fix formatting
jescalada Apr 3, 2026
fc085d4
Merge pull request #1491 from gep13/patch-1
jescalada Apr 3, 2026
1c45104
Merge branch 'main' into ci/e2e-optimization
jescalada Apr 3, 2026
6900045
Merge pull request #1490 from fabiovincenzi/ci/e2e-optimization
jescalada Apr 3, 2026
330a12a
Merge branch 'main' into ci/optimize-ci
jescalada Apr 3, 2026
c0b4a8d
Merge pull request #1492 from fabiovincenzi/ci/optimize-ci
jescalada Apr 3, 2026
d4a2c38
Merge branch 'main' into update-badge
jescalada Apr 8, 2026
848746e
Merge branch 'main' into fix/plugin-sample-exports
jescalada Apr 8, 2026
fda6e3c
fix: add missing utils/errors subpath export
fabiovincenzi Apr 9, 2026
8b606df
fix: restrict tsconfig types to node
fabiovincenzi Apr 9, 2026
064a955
fix: update stale imports in CLI test utils
fabiovincenzi Apr 9, 2026
b9bf5c2
fix: handle 403 and unhandled status codes in CLI
fabiovincenzi Apr 9, 2026
0e42bd4
fix: correct test config path and invalidate cache
fabiovincenzi Apr 9, 2026
1b3e695
fix: add attestationConfig to test proxy config
fabiovincenzi Apr 9, 2026
e389ced
ci: add c8 for CLI subprocess coverage
fabiovincenzi Apr 10, 2026
f2a6118
ci: add CLI test coverage script and source maps
fabiovincenzi Apr 10, 2026
103b4f1
ci: add CLI build step to CI workflow
fabiovincenzi Apr 10, 2026
488b22b
ci: add c8 to depcheck ignores
fabiovincenzi Apr 10, 2026
5783c6c
ci: separate CLI coverage output and upload both reports
fabiovincenzi Apr 10, 2026
5696ebf
ci: fix Windows quoting and increase test timeout for CLI
fabiovincenzi Apr 10, 2026
4d337c4
chore: add coverage-cli to gitignore
fabiovincenzi Apr 10, 2026
ba4f08e
Merge pull request #1499 from fabiovincenzi/fix/cli-restore
jescalada Apr 13, 2026
0821c36
Merge branch 'main' into ci/cli-test-coverage
fabiovincenzi Apr 13, 2026
25d1239
Merge pull request #1500 from fabiovincenzi/ci/cli-test-coverage
jescalada Apr 13, 2026
ab44342
Merge branch 'main' into fix/plugin-sample-exports
kriswest Apr 13, 2026
70d42d5
Merge pull request #1484 from finos/fix/plugin-sample-exports
jescalada Apr 13, 2026
b8f0d0b
chore: bump git-proxy to v2.0.0-rc.6
jescalada Apr 14, 2026
a827aa3
chore: npm run audit
jescalada Apr 15, 2026
2019faf
Merge pull request #1502 from finos/bump-to-rc.6
jescalada Apr 16, 2026
53c9fc3
chore: improve docker-publish.yml flow
jescalada Apr 19, 2026
bec60df
Merge branch 'main' into update-badge
kriswest Apr 20, 2026
1dbb249
Merge branch 'main' into improve-docker-publish-flow
kriswest Apr 20, 2026
e4715f2
Merge pull request #1505 from jescalada/improve-docker-publish-flow
kriswest Apr 20, 2026
4469ed7
Merge branch 'main' into update-badge
06kellyjac Apr 20, 2026
6981427
Merge pull request #1493 from finos/update-badge
kriswest Apr 20, 2026
53a3f3a
Merge remote-tracking branch 'upstream/main' into ssh-agent-on-pr987
fabiovincenzi Apr 22, 2026
6056c34
fix(security): validate req.body is a Buffer before parsing pkt-lines
fabiovincenzi Apr 22, 2026
fac846d
fix(security): add typeof/isArray guards to satisfy CodeQL type-confu…
fabiovincenzi Apr 22, 2026
2452a1e
fix(security): prevent shell injection in ssh-keyscan host verification
fabiovincenzi Apr 22, 2026
ccf8b63
refactor(ssh): centralize ssh2 internal API access with version guards
fabiovincenzi Apr 22, 2026
d9fffe3
chore: run format
fabiovincenzi Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
305 changes: 305 additions & 0 deletions src/proxy/ssh/GitProtocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
/**
* Git Protocol Handling for SSH
*
* This module handles the git pack protocol communication with remote Git servers (such as GitHub).
* It manages:
* - Fetching capabilities and refs from remote
* - Forwarding pack data for push operations
* - Setting up bidirectional streams for pull operations
*/

import * as ssh2 from 'ssh2';
import { ClientWithUser } from './types';
import { validateSSHPrerequisites, createSSHConnectionOptions } from './sshHelpers';

/**
* Parser for Git pkt-line protocol
* Git uses pkt-line format: [4 byte hex length][payload]
* Special packet "0000" (flush packet) indicates end of section
*/
class PktLineParser {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: rename to PacketLineParser for searchability/consistency

private buffer: Buffer = Buffer.alloc(0);

/**
* Append data to internal buffer
*/
append(data: Buffer): void {
this.buffer = Buffer.concat([this.buffer, data]);
}

/**
* Check if we've received a flush packet (0000) indicating end of capabilities
* The flush packet appears after the capabilities/refs section
*/
hasFlushPacket(): boolean {
const bufStr = this.buffer.toString('utf8');
return bufStr.includes('0000');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like this is too rudimentary, take the Linux kernel repo:

$ git log 0000
error: short object ID 0000 is ambiguous
hint: The candidates are:
hint:   000006155029 commit 2025-06-30 - arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
[about 26 more omitted]

and that's just prefixes, in this case a 0000 anywhere in a head's commit ID would collide. There's not a security problem here I don't think, just breaks the protocol, but we implemented a better parser before (38915e7) so it would be good to use it (move it somewhere common?).

(https://github.com/not-an-aardvark/lucky-commit could be useful to test this, if needed.)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Moved the proper pkt-line parser from parsePush.ts to a shared module (src/proxy/processors/pktLineParser.ts)

}

/**
* Get the complete buffer
*/
getBuffer(): Buffer {
return this.buffer;
}
}

/**
* Fetch capabilities and refs from GitHub without sending any data
* This allows us to validate data BEFORE sending to GitHub
*/
export async function fetchGitHubCapabilities(
command: string,
client: ClientWithUser,
): Promise<Buffer> {
validateSSHPrerequisites(client);
const connectionOptions = createSSHConnectionOptions(client);

return new Promise((resolve, reject) => {
const remoteGitSsh = new ssh2.Client();
const parser = new PktLineParser();

// Safety timeout (should never be reached)
const timeout = setTimeout(() => {
console.error(`[fetchCapabilities] Timeout waiting for capabilities`);
remoteGitSsh.end();
reject(new Error('Timeout waiting for capabilities from remote'));
}, 30000); // 30 seconds

remoteGitSsh.on('ready', () => {
console.log(`[fetchCapabilities] Connected to GitHub`);

remoteGitSsh.exec(command, (err: Error | undefined, remoteStream: ssh2.ClientChannel) => {
if (err) {
console.error(`[fetchCapabilities] Error executing command:`, err);
clearTimeout(timeout);
remoteGitSsh.end();
reject(err);
return;
}

console.log(`[fetchCapabilities] Command executed, waiting for capabilities`);

// Single data handler that checks for flush packet
remoteStream.on('data', (data: Buffer) => {
parser.append(data);
console.log(`[fetchCapabilities] Received ${data.length} bytes`);

if (parser.hasFlushPacket()) {
console.log(`[fetchCapabilities] Flush packet detected, capabilities complete`);
clearTimeout(timeout);
remoteStream.end();
remoteGitSsh.end();
resolve(parser.getBuffer());
}
});

remoteStream.on('error', (err: Error) => {
console.error(`[fetchCapabilities] Stream error:`, err);
clearTimeout(timeout);
remoteGitSsh.end();
reject(err);
});
});
});

remoteGitSsh.on('error', (err: Error) => {
console.error(`[fetchCapabilities] Connection error:`, err);
clearTimeout(timeout);
reject(err);
});

remoteGitSsh.connect(connectionOptions);
});
}

/**
* Base function for executing Git commands on remote server
* Handles all common SSH connection logic, error handling, and cleanup
* Delegates stream-specific behavior to the provided callback
*
* @param command - The Git command to execute
* @param clientStream - The SSH stream to the client
* @param client - The authenticated client connection
* @param onRemoteStreamReady - Callback invoked when remote stream is ready
*/
async function executeGitCommandOnRemote(
command: string,
clientStream: ssh2.ServerChannel,
client: ClientWithUser,
onRemoteStreamReady: (remoteStream: ssh2.ClientChannel) => void,
): Promise<void> {
validateSSHPrerequisites(client);

const userName = client.authenticatedUser?.username || 'unknown';
const connectionOptions = createSSHConnectionOptions(client, { debug: true, keepalive: true });

return new Promise((resolve, reject) => {
const remoteGitSsh = new ssh2.Client();

const connectTimeout = setTimeout(() => {
console.error(`[SSH] Connection timeout to remote for user ${userName}`);
remoteGitSsh.end();
clientStream.stderr.write('Connection timeout to remote server\n');
clientStream.exit(1);
clientStream.end();
reject(new Error('Connection timeout'));
}, 30000);

remoteGitSsh.on('ready', () => {
clearTimeout(connectTimeout);
console.log(`[SSH] Connected to remote Git server for user: ${userName}`);

remoteGitSsh.exec(command, (err: Error | undefined, remoteStream: ssh2.ClientChannel) => {
if (err) {
console.error(`[SSH] Error executing command on remote for user ${userName}:`, err);
clientStream.stderr.write(`Remote execution error: ${err.message}\n`);
clientStream.exit(1);
clientStream.end();
remoteGitSsh.end();
reject(err);
return;
}

console.log(`[SSH] Command executed on remote for user ${userName}`);

remoteStream.on('close', () => {
console.log(`[SSH] Remote stream closed for user: ${userName}`);
clientStream.end();
remoteGitSsh.end();
console.log(`[SSH] Remote connection closed for user: ${userName}`);
resolve();
});

remoteStream.on('exit', (code: number, signal?: string) => {
console.log(
`[SSH] Remote command exited for user ${userName} with code: ${code}, signal: ${signal || 'none'}`,
);
clientStream.exit(code || 0);
resolve();
});

remoteStream.on('error', (err: Error) => {
console.error(`[SSH] Remote stream error for user ${userName}:`, err);
clientStream.stderr.write(`Stream error: ${err.message}\n`);
clientStream.exit(1);
clientStream.end();
remoteGitSsh.end();
reject(err);
});

try {
onRemoteStreamReady(remoteStream);
} catch (callbackError) {
console.error(`[SSH] Error in stream callback for user ${userName}:`, callbackError);
clientStream.stderr.write(`Internal error: ${callbackError}\n`);
clientStream.exit(1);
clientStream.end();
remoteGitSsh.end();
reject(callbackError);
}
});
});

remoteGitSsh.on('error', (err: Error) => {
console.error(`[SSH] Remote connection error for user ${userName}:`, err);
clearTimeout(connectTimeout);
clientStream.stderr.write(`Connection error: ${err.message}\n`);
clientStream.exit(1);
clientStream.end();
reject(err);
});

remoteGitSsh.connect(connectionOptions);
});
}

/**
* Forward pack data to remote Git server (used for push operations)
* This connects to GitHub, sends the validated pack data, and forwards responses
*/
export async function forwardPackDataToRemote(
command: string,
stream: ssh2.ServerChannel,
client: ClientWithUser,
packData: Buffer | null,
capabilitiesSize?: number,
): Promise<void> {
const userName = client.authenticatedUser?.username || 'unknown';

await executeGitCommandOnRemote(command, stream, client, (remoteStream) => {
console.log(`[SSH] Forwarding pack data for user ${userName}`);

// Send pack data to GitHub
if (packData && packData.length > 0) {
console.log(`[SSH] Writing ${packData.length} bytes of pack data to remote`);
remoteStream.write(packData);
}
remoteStream.end();

// Skip duplicate capabilities that we already sent to client
let bytesSkipped = 0;
const CAPABILITY_BYTES_TO_SKIP = capabilitiesSize || 0;

remoteStream.on('data', (data: Buffer) => {
if (CAPABILITY_BYTES_TO_SKIP > 0 && bytesSkipped < CAPABILITY_BYTES_TO_SKIP) {
const remainingToSkip = CAPABILITY_BYTES_TO_SKIP - bytesSkipped;

if (data.length <= remainingToSkip) {
bytesSkipped += data.length;
console.log(
`[SSH] Skipping ${data.length} bytes of capabilities (${bytesSkipped}/${CAPABILITY_BYTES_TO_SKIP})`,
);
return;
} else {
const actualResponse = data.slice(remainingToSkip);
bytesSkipped = CAPABILITY_BYTES_TO_SKIP;
console.log(
`[SSH] Capabilities skipped (${CAPABILITY_BYTES_TO_SKIP} bytes), forwarding response (${actualResponse.length} bytes)`,
);
stream.write(actualResponse);
return;
}
}
// Forward all data after capabilities
stream.write(data);
});
});
}

/**
* Connect to remote Git server and set up bidirectional stream (used for pull operations)
* This creates a simple pipe between client and remote for pull/clone operations
*/
export async function connectToRemoteGitServer(
command: string,
stream: ssh2.ServerChannel,
client: ClientWithUser,
): Promise<void> {
const userName = client.authenticatedUser?.username || 'unknown';

await executeGitCommandOnRemote(command, stream, client, (remoteStream) => {
console.log(`[SSH] Setting up bidirectional piping for user ${userName}`);

// Pipe client data to remote
stream.on('data', (data: Buffer) => {
remoteStream.write(data);
});

// Pipe remote data to client
remoteStream.on('data', (data: Buffer) => {
stream.write(data);
});

remoteStream.on('error', (err: Error) => {
if (err.message.includes('early EOF') || err.message.includes('unexpected disconnect')) {
console.log(
`[SSH] Detected early EOF for user ${userName}, this is usually harmless during Git operations`,
);
return;
}
// Re-throw other errors
throw err;
});
});
}