fix: harden Xcode release provenance
This commit is contained in:
parent
7619036c6f
commit
fdc1bd3c0a
2 changed files with 27 additions and 7 deletions
|
|
@ -120,8 +120,9 @@ export function materializeUpdaterPrivateKey(env, readText = (file) => fs.readFi
|
|||
readText(privateKeyPath),
|
||||
'HOLOLAKE_RELEASE_PIPELINE_UPDATER_PRIVATE_KEY_EMPTY',
|
||||
)
|
||||
const { TAURI_SIGNING_PRIVATE_KEY_PATH: _privateKeyPath, ...childEnvironment } = env
|
||||
return {
|
||||
...env,
|
||||
...childEnvironment,
|
||||
TAURI_SIGNING_PRIVATE_KEY: privateKey,
|
||||
}
|
||||
}
|
||||
|
|
@ -234,6 +235,18 @@ function localDateDirectory() {
|
|||
return `${date.getFullYear()}-${part(date.getMonth() + 1)}-${part(date.getDate())}`
|
||||
}
|
||||
|
||||
function unsignedExecutableSha256(executable) {
|
||||
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), 'hololake-unsigned-executable-'))
|
||||
const copy = path.join(temporary, path.basename(executable))
|
||||
try {
|
||||
fs.copyFileSync(executable, copy)
|
||||
run('/usr/bin/codesign', ['--remove-signature', copy])
|
||||
return sha256File(copy)
|
||||
} finally {
|
||||
fs.rmSync(temporary, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
|
||||
export function formatPlistDate(date) {
|
||||
const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
||||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
|
|
@ -260,7 +273,9 @@ function createXcodeArchive(application, input) {
|
|||
add('Name', 'string', `HoloLake ${input.version} ${input.sourceCommit.slice(0, 12)}`)
|
||||
add('SchemeName', 'string', 'HoloLake')
|
||||
add('HoloLakeSourceCommit', 'string', input.sourceCommit)
|
||||
add('HoloLakeExecutableSha256', 'string', sha256File(path.join(application, 'Contents/MacOS/hololake-native-desktop')))
|
||||
const executable = path.join(application, 'Contents/MacOS/hololake-native-desktop')
|
||||
add('HoloLakePreNotarizationExecutableSha256', 'string', sha256File(executable))
|
||||
add('HoloLakeUnsignedExecutableSha256', 'string', unsignedExecutableSha256(executable))
|
||||
add('ApplicationProperties', 'dict', '')
|
||||
add('ApplicationProperties:ApplicationPath', 'string', 'Applications/HoloLake.app')
|
||||
add('ApplicationProperties:ArchiveVersion', 'integer', '2')
|
||||
|
|
@ -298,11 +313,13 @@ function resolveNotarizedApplication(argument, input) {
|
|||
fail('HOLOLAKE_RELEASE_PIPELINE_NOTARIZED_APP_IDENTITY_MISMATCH')
|
||||
}
|
||||
const archive = findPreparedXcodeArchive(input)
|
||||
const expectedExecutableSha256 = run('/usr/libexec/PlistBuddy', [
|
||||
'-c', 'Print :HoloLakeExecutableSha256', path.join(archive, 'Info.plist'),
|
||||
const expectedUnsignedExecutableSha256 = run('/usr/libexec/PlistBuddy', [
|
||||
'-c', 'Print :HoloLakeUnsignedExecutableSha256', path.join(archive, 'Info.plist'),
|
||||
], { capture: true }).trim()
|
||||
const actualExecutableSha256 = sha256File(path.join(application, 'Contents/MacOS/hololake-native-desktop'))
|
||||
if (actualExecutableSha256 !== expectedExecutableSha256) {
|
||||
const actualUnsignedExecutableSha256 = unsignedExecutableSha256(
|
||||
path.join(application, 'Contents/MacOS/hololake-native-desktop'),
|
||||
)
|
||||
if (actualUnsignedExecutableSha256 !== expectedUnsignedExecutableSha256) {
|
||||
fail('HOLOLAKE_RELEASE_PIPELINE_NOTARIZED_APP_SOURCE_BINARY_MISMATCH')
|
||||
}
|
||||
return application
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ test('release pipeline materializes a protected updater key path only inside the
|
|||
return 'encrypted-private-key-material'
|
||||
})
|
||||
assert.equal(hydrated.TAURI_SIGNING_PRIVATE_KEY, 'encrypted-private-key-material')
|
||||
assert.equal(hydrated.TAURI_SIGNING_PRIVATE_KEY_PATH, undefined)
|
||||
assert.equal(source.TAURI_SIGNING_PRIVATE_KEY, undefined)
|
||||
})
|
||||
|
||||
|
|
@ -109,7 +110,9 @@ test('release pipeline verifies the updater signature against embedded product t
|
|||
const source = readFileSync(new URL('./release-pipeline.mjs', import.meta.url), 'utf8')
|
||||
assert.match(source, /--example',\s*'verify_updater_signature'/)
|
||||
assert.match(source, /src-tauri\/release-trust\.json/)
|
||||
assert.match(source, /HoloLakeExecutableSha256/)
|
||||
assert.match(source, /HoloLakePreNotarizationExecutableSha256/)
|
||||
assert.match(source, /HoloLakeUnsignedExecutableSha256/)
|
||||
assert.match(source, /--remove-signature/)
|
||||
assert.match(source, /NOTARIZED_APP_SOURCE_BINARY_MISMATCH/)
|
||||
assert.match(source, /APPLE_APP_NOTARIZATION_ACCEPTED_AND_STAPLED_DMG_CONTAINS_NOTARIZED_APP/)
|
||||
assert.match(source, /path\.resolve\(appExecutable, '\.\.\/\.\.\/\.\.'\)/)
|
||||
|
|
|
|||
Loading…
Reference in a new issue