Skip to content

Commit 9c1449f

Browse files
committed
feat: add check for hidden commits
1 parent 1fd86ac commit 9c1449f

File tree

4 files changed

+105
-7
lines changed

4 files changed

+105
-7
lines changed

src/proxy/chain.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ const pushActionChain: ((req: any, action: Action) => Promise<Action>)[] = [
99
proc.push.checkCommitMessages,
1010
proc.push.checkAuthorEmails,
1111
proc.push.checkUserPushPermission,
12-
proc.push.checkIfWaitingAuth,
1312
proc.push.pullRemote,
1413
proc.push.writePack,
14+
proc.push.checkHiddenCommits,
15+
proc.push.checkIfWaitingAuth,
1516
proc.push.getMissingData,
1617
proc.push.preReceive,
1718
proc.push.getDiff,
@@ -20,7 +21,9 @@ const pushActionChain: ((req: any, action: Action) => Promise<Action>)[] = [
2021
proc.push.blockForAuth,
2122
];
2223

23-
const pullActionChain: ((req: any, action: Action) => Promise<Action>)[] = [proc.push.checkRepoInAuthorisedList];
24+
const pullActionChain: ((req: any, action: Action) => Promise<Action>)[] = [
25+
proc.push.checkRepoInAuthorisedList,
26+
];
2427

2528
let pluginsInserted = false;
2629

@@ -58,7 +61,9 @@ export const executeChain = async (req: any, res: any): Promise<Action> => {
5861
*/
5962
let chainPluginLoader: PluginLoader;
6063

61-
const getChain = async (action: Action): Promise<((req: any, action: Action) => Promise<Action>)[]> => {
64+
const getChain = async (
65+
action: Action,
66+
): Promise<((req: any, action: Action) => Promise<Action>)[]> => {
6267
if (chainPluginLoader === undefined) {
6368
console.error(
6469
'Plugin loader was not initialized! This is an application error. Please report it to the GitProxy maintainers. Skipping plugins...',
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import path from 'path';
2+
import { Action, Step } from '../../actions';
3+
import { spawnSync } from 'child_process';
4+
5+
const exec = async (req: any, action: Action): Promise<Action> => {
6+
const step = new Step('checkHiddenCommits');
7+
8+
try {
9+
const repoPath = `${action.proxyGitPath}/${action.repoName}`;
10+
console.log(`repoPath: ${repoPath}`);
11+
12+
const introducedCommits = new Set<string>();
13+
14+
action.updatedRefs?.forEach(({ ref, oldOid, newOid }) => {
15+
const revRange =
16+
oldOid === '0000000000000000000000000000000000000000' ? newOid : `${oldOid}..${newOid}`;
17+
18+
const result = spawnSync('git', ['rev-list', revRange], {
19+
cwd: repoPath,
20+
encoding: 'utf-8',
21+
});
22+
23+
result.stdout
24+
.trim()
25+
.split('\n')
26+
.forEach((c) => {
27+
if (c) introducedCommits.add(c);
28+
});
29+
});
30+
31+
step.log(`Total introduced commits: ${introducedCommits.size}`);
32+
step.log(`Introduced commits: ${[...introducedCommits].join(', ')}`);
33+
34+
const packPath = path.join('.git', 'objects', 'pack');
35+
36+
const packCommits = new Set<string>();
37+
38+
(action.newIdxFiles || []).forEach((idxFile) => {
39+
const idxPath = path.join(packPath, idxFile);
40+
const out = spawnSync('git', ['verify-pack', '-v', idxPath], {
41+
cwd: repoPath,
42+
encoding: 'utf-8',
43+
}).stdout;
44+
45+
out
46+
.trim()
47+
.split('\n')
48+
.forEach((line) => {
49+
const [sha, type] = line.split(/\s+/);
50+
if (type === 'commit') packCommits.add(sha);
51+
});
52+
});
53+
step.log(`Commits nel pack: ${packCommits.size}`);
54+
console.log('Pack commits:', packCommits);
55+
console.log('Introduced commits:', introducedCommits);
56+
57+
const referenced: string[] = [];
58+
const unreferenced: string[] = [];
59+
[...packCommits].forEach((sha) => {
60+
if (introducedCommits.has(sha)) referenced.push(sha);
61+
else unreferenced.push(sha);
62+
});
63+
64+
step.log(`✅ Referenced commits: ${referenced.length}`);
65+
step.log(`❌ Unreferenced commits: ${unreferenced.length}`);
66+
67+
if (unreferenced.length > 0) {
68+
step.setError(
69+
`Unreferenced commits in pack (${unreferenced.length}): ${unreferenced.join(', ')}`,
70+
);
71+
action.error = true;
72+
}
73+
step.setContent(`Referenced: ${referenced.length}, Unreferenced: ${unreferenced.length}`);
74+
} catch (e: any) {
75+
step.setError(e.message);
76+
throw e;
77+
} finally {
78+
action.addStep(step);
79+
}
80+
81+
return action;
82+
};
83+
84+
exec.displayName = 'checkHiddenCommits.exec';
85+
export { exec };

src/proxy/processors/push-action/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { exec as audit } from './audit';
55
import { exec as pullRemote } from './pullRemote';
66
import { exec as writePack } from './writePack';
77
import { exec as getDiff } from './getDiff';
8+
import { exec as checkHiddenCommits } from './checkHiddenCommits';
89
import { exec as scanDiff } from './scanDiff';
910
import { exec as blockForAuth } from './blockForAuth';
1011
import { exec as checkIfWaitingAuth } from './checkIfWaitingAuth';
@@ -22,6 +23,7 @@ export {
2223
pullRemote,
2324
writePack,
2425
getDiff,
26+
checkHiddenCommits,
2527
scanDiff,
2628
blockForAuth,
2729
checkIfWaitingAuth,

src/proxy/processors/push-action/parsePush.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,17 @@ async function exec(req: any, action: Action): Promise<Action> {
3131
return action;
3232
}
3333

34-
const parts = refUpdates[0].split(' ');
35-
const [oldCommit, newCommit, ref] = parts;
34+
const cleanedUpdates = refUpdates.map((line) => {
35+
const [oldOid, newOid, refWithNull] = line.split(' ');
36+
const ref = refWithNull.replace(/\0.*/, '').trim();
37+
return { oldOid, newOid, ref };
38+
});
3639

37-
action.branch = ref.replace(/\0.*/, '').trim();
38-
action.setCommit(oldCommit, newCommit);
40+
action.updatedRefs = cleanedUpdates;
41+
42+
const { oldOid, newOid, ref } = cleanedUpdates[0];
43+
action.branch = ref;
44+
action.setCommit(oldOid, newOid);
3945

4046
// Check if the offset is valid and if there's data after it
4147
if (packDataOffset >= req.body.length) {

0 commit comments

Comments
 (0)