fix(skills): observe archive abort errors before reading (#26246)

This commit is contained in:
Neil
2026-10-07 09:20:57 -07:00
committed by GitHub
parent a576c0bc4e
commit 7d6d7ca6f8
2 changed files with 34 additions and 1 deletions
+32 -1
View File
@@ -1,5 +1,13 @@
import { describe, expect, it } from 'vitest'
import { parseSkillTarHeader, SKILL_TAR_BLOCK_BYTES } from './skill-package-tar'
import { mkdtemp, rm } from 'node:fs/promises'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import {
openSkillTarGzip,
parseSkillTarHeader,
SKILL_TAR_BLOCK_BYTES,
writeSkillTarGzip
} from './skill-package-tar'
function writeOctal(header: Buffer, offset: number, length: number, value: number): void {
header.write(`${value.toString(8).padStart(length - 1, '0')}\0`, offset, length, 'ascii')
@@ -62,3 +70,26 @@ describe('skill package tar envelope', () => {
}
})
})
describe('skill tar reader error ownership', () => {
it('observes an abort after the pipeline completes before the first reader request', async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-skill-tar-abort-'))
try {
const archivePath = join(root, 'archive.tar.gz')
await writeSkillTarGzip(archivePath, [
{ path: 'SKILL.md', size: 1, executable: false, bytes: Buffer.from('x') }
])
const archive = await openSkillTarGzip(archivePath)
await archive.archiveIdentity
const failure = Object.assign(new Error('staging directory already exists'), {
code: 'EEXIST'
})
archive.abort(failure)
// Observe destruction before lazily attaching the reader's error listener.
await new Promise<void>((resolve) => setImmediate(resolve))
await expect(archive.reader.readExact(SKILL_TAR_BLOCK_BYTES)).rejects.toBe(failure)
} finally {
await rm(root, { recursive: true, force: true })
}
})
})
+2
View File
@@ -262,6 +262,8 @@ export async function openSkillTarGzip(archivePath: string): Promise<{
}
})
const gunzip = createGunzip()
// Observe late aborts before the archive reader starts.
gunzip.on('error', () => undefined)
const completion = pipeline(source, verifier, gunzip)
const archiveIdentity = completion.then(() => ({
archiveSha256: archiveHash.digest('hex'),