build-state.mjs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import { hasNotarizeCredentials, prepareNotarizeEnv } from '../hooks/notarize-options.mjs'
  2. import { getFirstConfiguredEnv, hasValue, isEnvFlagEnabled } from './build-env.mjs'
  3. function hasSigningIdentityEnv(env = process.env) {
  4. return hasValue(env.IDENTITY)
  5. }
  6. function describeNotarizationSetup(env = process.env) {
  7. if (hasValue(env.APPLE_KEYCHAIN_PROFILE)) {
  8. return 'APPLE_KEYCHAIN_PROFILE'
  9. }
  10. if (hasValue(env.APPLE_API_KEY) || hasValue(env.APPLE_API_KEY_ID) || hasValue(env.APPLE_API_ISSUER)) {
  11. return 'APPLE_API_KEY + APPLE_API_KEY_ID + APPLE_API_ISSUER'
  12. }
  13. if (
  14. hasValue(env.APPLE_ID) ||
  15. hasValue(env.APPLE_APP_SPECIFIC_PASSWORD) ||
  16. hasValue(env.APPLE_TEAM_ID) ||
  17. hasValue(env.TEAM_ID)
  18. ) {
  19. return 'APPLE_ID + APPLE_APP_SPECIFIC_PASSWORD + APPLE_TEAM_ID'
  20. }
  21. return null
  22. }
  23. export async function resolveMacBuildState(plan, env = process.env) {
  24. const includesMac = plan.some(({ platform }) => platform === 'mac')
  25. const notarizationForcedOff = env.MAKE_FOR === 'dev' || isEnvFlagEnabled(env.SKIP_NOTARIZATION)
  26. const state = {
  27. includesMac,
  28. sign: false,
  29. notarize: false,
  30. logLevel: 'step',
  31. message: 'macOS signing configuration check skipped',
  32. }
  33. if (!includesMac) {
  34. state.message = 'skipping macOS signing configuration check'
  35. return state
  36. }
  37. await prepareNotarizeEnv(env)
  38. const hasIdentity = hasSigningIdentityEnv(env)
  39. const hasNotary = hasNotarizeCredentials(env)
  40. const configuredNotarySetup = describeNotarizationSetup(env)
  41. if (notarizationForcedOff) {
  42. if (hasIdentity) {
  43. state.sign = true
  44. state.logLevel = 'success'
  45. state.message = `macOS code signing enabled via IDENTITY; notarization disabled by ${
  46. env.MAKE_FOR === 'dev' ? 'MAKE_FOR=dev' : 'SKIP_NOTARIZATION'
  47. }`
  48. } else {
  49. state.logLevel = 'warning'
  50. state.message =
  51. 'IDENTITY is not configured; falling back to unsigned macOS artifacts because notarization is disabled.'
  52. }
  53. return state
  54. }
  55. if (hasIdentity && hasNotary) {
  56. state.sign = true
  57. state.notarize = true
  58. state.logLevel = 'success'
  59. state.message = `macOS signing and notarization enabled via IDENTITY + ${configuredNotarySetup}`
  60. return state
  61. }
  62. const missing = []
  63. if (!hasIdentity) {
  64. missing.push('IDENTITY')
  65. }
  66. if (!hasNotary) {
  67. missing.push(
  68. 'APPLE_KEYCHAIN_PROFILE or APPLE_API_KEY/APPLE_API_KEY_ID/APPLE_API_ISSUER or APPLE_ID/APPLE_APP_SPECIFIC_PASSWORD/APPLE_TEAM_ID',
  69. )
  70. }
  71. state.logLevel = 'warning'
  72. state.message =
  73. `macOS signing/notarization config is missing or incomplete (${missing.join(', ')}). ` +
  74. 'Falling back to unsigned and unnotarized macOS artifacts.'
  75. return state
  76. }
  77. export function resolveWindowsBuildState(plan, env = process.env) {
  78. const includesWin = plan.some(({ platform }) => platform === 'win')
  79. const certificateSubjectName = getFirstConfiguredEnv(env, [
  80. 'WIN_CERTIFICATE_SUBJECT_NAME',
  81. 'WINDOWS_CERTIFICATE_SUBJECT_NAME',
  82. 'WIN_CERT_SUBJECT_NAME',
  83. ])
  84. const configuredPublisherName = getFirstConfiguredEnv(env, ['WIN_PUBLISHER_NAME', 'WINDOWS_PUBLISHER_NAME'])
  85. const publisherName = configuredPublisherName || certificateSubjectName
  86. const state = {
  87. includesWin,
  88. sign: false,
  89. logLevel: 'step',
  90. message: 'skipping Windows signing configuration check',
  91. publisherName,
  92. certificateSubjectName,
  93. }
  94. if (!includesWin) {
  95. state.message = 'skipping Windows signing configuration check'
  96. return state
  97. }
  98. if (certificateSubjectName) {
  99. state.sign = true
  100. state.logLevel = 'success'
  101. state.message =
  102. configuredPublisherName
  103. ? 'Windows code signing enabled via WIN_CERTIFICATE_SUBJECT_NAME and WIN_PUBLISHER_NAME.'
  104. : 'Windows code signing enabled via WIN_CERTIFICATE_SUBJECT_NAME; publisherName defaults to the certificate subject name.'
  105. return state
  106. }
  107. if (configuredPublisherName) {
  108. state.logLevel = 'warning'
  109. state.message =
  110. 'Windows signing config is incomplete (missing WIN_CERTIFICATE_SUBJECT_NAME or WINDOWS_CERTIFICATE_SUBJECT_NAME or WIN_CERT_SUBJECT_NAME). ' +
  111. 'Skipping Windows code signing for this build.'
  112. return state
  113. }
  114. state.message =
  115. 'Windows code signing disabled by default. Set WIN_CERTIFICATE_SUBJECT_NAME to enable it; WIN_PUBLISHER_NAME is optional.'
  116. return state
  117. }