/ opencodehub / scripts / clean-corrupted-s3-repos.ts
swadhinbiswas feat: OpenCodeHub v1.1.0 - Enterprise Features & Storage Adapters · 2/15/2026
719a1cb
106 lines · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { getStorage } from '../src/lib/storage';

/**
 * This script identifies and optionally deletes corrupted repository structures in S3.
 * 
 * Corrupted repos have the pattern: repos/swadhinbiswas/test.git/reposswadhinbiswas/...
 * instead of: repos/swadhinbiswas/test.git/HEAD, refs/, objects/, etc.
 * 
 * Usage:
 *   npx ts-node scripts/clean-corrupted-s3-repos.ts [--delete]
 */

async function main() {
    const shouldDelete = process.argv.includes('--delete');

    console.log('Scanning S3 for corrupted repository structures...\n');

    const storage = await getStorage();

    // List all repos
    const result = await storage.list({ prefix: 'repos/' });

    const corruptedRepos: string[] = [];
    const seenRepos = new Set<string>();

    // Check each prefix/object
    if (result.prefixes) {
        for (const prefix of result.prefixes) {
            // Expected pattern: repos/owner/repo.git/
            const parts = prefix.split('/');

            if (parts.length === 4 && parts[2].endsWith('.git')) {
                const repoPath = parts.slice(0, 3).join('/'); // repos/owner/repo.git

                if (seenRepos.has(repoPath)) continue;
                seenRepos.add(repoPath);

                // Check what's inside this repo
                const repoContents = await storage.list({ prefix: repoPath + '/' });

                // Check if it has the corrupted nested structure
                if (repoContents.prefixes) {
                    for (const subPrefix of repoContents.prefixes) {
                        const subParts = subPrefix.split('/');
                        const lastPart = subParts[subParts.length - 2]; // Get directory name

                        // If it starts with "repos" it's corrupted
                        if (lastPart && lastPart.startsWith('repos')) {
                            console.log(`❌ CORRUPTED: ${repoPath}/`);
                            console.log(`   Found invalid directory: ${lastPart}`);
                            corruptedRepos.push(repoPath);
                            break;
                        }
                    }
                }

                // Also check if it has proper Git structure
                const hasValidStructure = repoContents.objects?.some(obj =>
                    obj.key.endsWith('/HEAD') ||
                    obj.key.includes('/refs/') ||
                    obj.key.includes('/objects/')
                );

                if (!hasValidStructure && !corruptedRepos.includes(repoPath)) {
                    console.log(`⚠️  EMPTY or INCOMPLETE: ${repoPath}/`);
                } else if (!corruptedRepos.includes(repoPath)) {
                    console.log(`✅ VALID: ${repoPath}/`);
                }
            }
        }
    }

    console.log(`\n\nSummary:`);
    console.log(`Found ${corruptedRepos.length} corrupted repositories`);

    if (corruptedRepos.length > 0) {
        console.log('\nCorrupted repositories:');
        corruptedRepos.forEach(repo => console.log(`  - ${repo}`));

        if (shouldDelete) {
            console.log('\n🗑️  Deleting corrupted repositories...');

            for (const repoPath of corruptedRepos) {
                console.log(`Deleting ${repoPath}...`);

                // List ALL objects under this path
                const toDelete = await storage.list({ prefix: repoPath + '/' });

                if (toDelete.objects) {
                    for (const obj of toDelete.objects) {
                        await storage.delete(obj.key);
                        console.log(`  Deleted: ${obj.key}`);
                    }
                }
            }

            console.log('\n✅ Cleanup complete!');
        } else {
            console.log('\nTo delete these repositories, run:');
            console.log('  npx ts-node scripts/clean-corrupted-s3-repos.ts --delete');
        }
    }
}

main().catch(console.error);