Skip to content

Commit 463fa05

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix: reject missing Git blobs before consulting indexed facts
1 parent 008e6e1 commit 463fa05

4 files changed

Lines changed: 28 additions & 1 deletion

File tree

scripts/design-diff/git.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,11 @@ export class GitReader {
6262
const tab = record.indexOf('\t')
6363
const [mode, type, oid, size] = record.slice(0, tab).trim().split(/\s+/)
6464
if (type !== 'blob') continue
65+
const bytes = Number(size)
66+
// Git can exit successfully with size BAD for a missing blob. Cached facts must not hide it.
67+
if (!Number.isSafeInteger(bytes) || bytes < 0) throw new Error('Unreadable Git blob metadata')
6568
const path = record.slice(tab + 1)
66-
entries.set(path, { path, mode, oid, size: Number(size) })
69+
entries.set(path, { path, mode, oid, size: bytes })
6770
}
6871
return entries
6972
}

scripts/design-diff/tests/git.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,20 @@ it('fails explicitly for unreadable revisions and missing history', async () =>
7777
rmSync(shallow, { recursive: true, force: true })
7878
}
7979
})
80+
81+
it('rejects missing source blobs even when Git returns successful tree metadata', async () => {
82+
const repo = new FixtureRepo()
83+
try {
84+
const file = 'apps/sim/control.tsx'
85+
const base = repo.commit({ [file]: 'export const Control=()=> <button className="p-2"/>' })
86+
const head = repo.commit({ 'README.md': 'Nonvisual edit' })
87+
const blob = repo.git('rev-parse', `${base}:${file}`)
88+
rmSync(path.join(repo.cwd, '.git/objects', blob.slice(0, 2), blob.slice(2)))
89+
expect(() => new GitReader(repo.cwd).tree(base)).toThrow('Unreadable Git blob metadata')
90+
await expect(analyze(repo.cwd, base, head, config)).rejects.toThrow(
91+
'Unreadable Git blob metadata'
92+
)
93+
} finally {
94+
repo.close()
95+
}
96+
})

scripts/design-diff/tests/index-runtime.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@ try {
221221
)
222222
)
223223
assert.equal((await cached()).report, await fresh())
224+
} else if (mode === 'missing-source') {
225+
await cached()
226+
const blob = repo.git('rev-parse', `${base}:${file}`)
227+
rmSync(path.join(repo.cwd, '.git/objects', blob.slice(0, 2), blob.slice(2)))
228+
await assert.rejects(cached(), /Unreadable Git blob metadata/)
229+
await assert.rejects(fresh(), /Unreadable Git blob metadata/)
224230
} else if (mode === 'themes') {
225231
const theme = 'apps/sim/app/globals.css'
226232
const themedBase = repo.commit({

scripts/design-diff/tests/index.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ it.each([
1313
'themes',
1414
'sentinels',
1515
'restart',
16+
'missing-source',
1617
])(
1718
'maintains indexed correctness: %s',
1819
(mode) => {

0 commit comments

Comments
 (0)