macos-notarized-application.spec.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. /** Verify application qualification commands without invoking Apple tools. */
  2. import { spawnSync } from 'node:child_process'
  3. import { afterEach, describe, expect, it, vi } from 'vitest'
  4. import { verifyMacOSNotarizedApplication } from '../scripts/verify-macos-signature.mjs'
  5. vi.mock('node:child_process', async importOriginal => ({
  6. ...await importOriginal<typeof import('node:child_process')>(),
  7. spawnSync: vi.fn(),
  8. }))
  9. const expected = { signingIdentity: 'Example Company (TEAMID1234)', teamId: 'TEAMID1234' }
  10. const appPath = '/private build/DeepSeek Harness.app'
  11. const commands = [
  12. ['/usr/bin/codesign', ['--verify', '--deep', '--strict', '--verbose=2', appPath]],
  13. ['/usr/bin/codesign', ['--display', '--verbose=4', appPath]],
  14. ['/usr/bin/xcrun', ['stapler', 'validate', appPath]],
  15. ['/usr/sbin/spctl', ['--assess', '--type', 'execute', '--verbose=4', appPath]],
  16. ] as const
  17. afterEach(() => { vi.resetAllMocks() })
  18. describe('notarized application qualification', () => {
  19. it.each([undefined, 0, 1, 2, 3])('stops at failed command %s or verifies every qualification', (failedCommand) => {
  20. let index = 0
  21. vi.mocked(spawnSync).mockImplementation(() => ({
  22. pid: 1,
  23. output: [],
  24. stdout: '',
  25. stderr: `Authority=Developer ID Application: ${expected.signingIdentity}\nTeamIdentifier=${expected.teamId}\n`,
  26. status: index++ === failedCommand ? 1 : 0,
  27. signal: null,
  28. }))
  29. if (failedCommand === undefined) {
  30. expect(() => { verifyMacOSNotarizedApplication(appPath, expected) }).not.toThrow()
  31. } else {
  32. expect(() => { verifyMacOSNotarizedApplication(appPath, expected) }).toThrow('exited with 1')
  33. }
  34. const calledCommands = commands.slice(0, failedCommand === undefined ? commands.length : failedCommand + 1)
  35. expect(spawnSync).toHaveBeenCalledTimes(calledCommands.length)
  36. for (const [index, [command, args]] of calledCommands.entries()) {
  37. expect(spawnSync).toHaveBeenNthCalledWith(index + 1, command, args, { encoding: 'utf8' })
  38. }
  39. })
  40. })