six-degrees 0.7.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +32 -4
  5. package/.next/standalone/.next/routes-manifest.json +6 -0
  6. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  12. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  14. package/.next/standalone/.next/server/app/_not-found.rsc +16 -16
  15. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
  16. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  17. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  18. package/.next/standalone/.next/server/app/api/admin-delete/route.js +1 -1
  19. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/api/admin-update/route.js +1 -1
  21. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/bridges/route.js +1 -1
  23. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/bulk-import/route.js +1 -1
  25. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/connections/route.js +1 -1
  29. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/data/backup/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/data/csv/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/data/restore/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/delete-cluster/route.js +1 -1
  39. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/ingest/route.js +1 -1
  41. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/network/route.js +1 -1
  43. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/notifications/route.js +1 -1
  45. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/outreach/route.js +3 -3
  47. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/queue/route.js +1 -1
  49. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/api/scraper/route.js +4 -4
  51. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/setup-profile/route.js +1 -1
  56. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/social/crm/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/social/messages/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/social/route.js +1 -1
  60. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/api/unlock/route.js +1 -1
  62. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/update-images/route.js +1 -1
  65. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/users/route.js +1 -1
  67. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/import.html +1 -1
  72. package/.next/standalone/.next/server/app/import.rsc +18 -18
  73. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +18 -18
  74. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
  75. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +16 -16
  76. package/.next/standalone/.next/server/app/index.html +1 -1
  77. package/.next/standalone/.next/server/app/index.rsc +19 -19
  78. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +16 -16
  79. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +19 -19
  80. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  81. package/.next/standalone/.next/server/app/insights/page/app-paths-manifest.json +3 -0
  82. package/.next/standalone/.next/server/app/insights/page/build-manifest.json +20 -0
  83. package/.next/standalone/.next/server/app/insights/page/next-font-manifest.json +11 -0
  84. package/.next/standalone/.next/server/app/insights/page/react-loadable-manifest.json +1 -0
  85. package/.next/standalone/.next/server/app/insights/page/server-reference-manifest.json +4 -0
  86. package/.next/standalone/.next/server/app/insights/page.js +13 -0
  87. package/.next/standalone/.next/server/app/insights/page.js.map +5 -0
  88. package/.next/standalone/.next/server/app/insights/page.js.nft.json +1 -0
  89. package/.next/standalone/.next/server/app/insights/page_client-reference-manifest.js +3 -0
  90. package/.next/standalone/.next/server/app/insights.html +1 -0
  91. package/.next/standalone/.next/server/app/insights.meta +26 -0
  92. package/.next/standalone/.next/server/app/insights.rsc +35 -0
  93. package/.next/standalone/.next/server/app/insights.segments/_full.segment.rsc +35 -0
  94. package/.next/standalone/.next/server/app/insights.segments/_tree.segment.rsc +4 -0
  95. package/.next/standalone/.next/server/app/insights.segments/insights/__PAGE__.segment.rsc +33 -0
  96. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  98. package/.next/standalone/.next/server/app/launch.html +2 -2
  99. package/.next/standalone/.next/server/app/launch.rsc +18 -18
  100. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +18 -18
  101. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
  102. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +16 -16
  103. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  105. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  107. package/.next/standalone/.next/server/app/paths.html +1 -1
  108. package/.next/standalone/.next/server/app/paths.rsc +19 -19
  109. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +19 -19
  110. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
  111. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +16 -16
  112. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  113. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  114. package/.next/standalone/.next/server/app/profile.html +1 -1
  115. package/.next/standalone/.next/server/app/profile.rsc +19 -19
  116. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +19 -19
  117. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
  118. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +16 -16
  119. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  121. package/.next/standalone/.next/server/app/queue.html +1 -1
  122. package/.next/standalone/.next/server/app/queue.rsc +19 -19
  123. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +19 -19
  124. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
  125. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +21 -20
  126. package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
  127. package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
  128. package/.next/standalone/.next/server/app/scores.html +1 -1
  129. package/.next/standalone/.next/server/app/scores.rsc +18 -18
  130. package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +18 -18
  131. package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
  132. package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +16 -16
  133. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  135. package/.next/standalone/.next/server/app/settings.html +1 -1
  136. package/.next/standalone/.next/server/app/settings.rsc +19 -19
  137. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +19 -19
  138. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  139. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +16 -16
  140. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  141. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  142. package/.next/standalone/.next/server/app/setup.html +1 -1
  143. package/.next/standalone/.next/server/app/setup.rsc +19 -19
  144. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +19 -19
  145. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  146. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +16 -16
  147. package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
  149. package/.next/standalone/.next/server/app/social.html +1 -1
  150. package/.next/standalone/.next/server/app/social.rsc +18 -18
  151. package/.next/standalone/.next/server/app/social.segments/_full.segment.rsc +18 -18
  152. package/.next/standalone/.next/server/app/social.segments/_tree.segment.rsc +2 -2
  153. package/.next/standalone/.next/server/app/social.segments/social/__PAGE__.segment.rsc +16 -16
  154. package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
  155. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__063s0x7._.js → [root-of-the-server]__0r-0t-9._.js} +1 -1
  156. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ra6xyg._.js +15 -0
  157. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__20rwfdw._.js → [root-of-the-server]__0rcpjad._.js} +5 -2
  158. package/.next/standalone/.next/server/chunks/_1_fynia._.js +7 -7
  159. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
  160. package/.next/standalone/.next/server/chunks/lib_02iz_9q._.js +2 -2
  161. package/.next/standalone/.next/server/chunks/lib_05agvk3._.js +2 -2
  162. package/.next/standalone/.next/server/chunks/lib_0v84u66._.js +2 -2
  163. package/.next/standalone/.next/server/chunks/lib_db-client_0_dch35.js +9 -9
  164. package/.next/standalone/.next/server/chunks/{lib_rpc_0jnfp2e.js → lib_rpc_00nndai.js} +1 -1
  165. package/.next/standalone/.next/server/chunks/{lib_rpc_0b17r6v.js → lib_rpc_03ibb-x.js} +1 -1
  166. package/.next/standalone/.next/server/chunks/{lib_rpc_0doq0t-.js → lib_rpc_03ri3ji.js} +1 -1
  167. package/.next/standalone/.next/server/chunks/{lib_rpc_0fd2rlw.js → lib_rpc_078ce48.js} +1 -1
  168. package/.next/standalone/.next/server/chunks/lib_rpc_0a69mgr.js +3 -0
  169. package/.next/standalone/.next/server/chunks/{lib_rpc_005abye.js → lib_rpc_0cej3t8.js} +1 -1
  170. package/.next/standalone/.next/server/chunks/lib_rpc_0cmh4g6.js +3 -0
  171. package/.next/standalone/.next/server/chunks/lib_rpc_0nx2_pc.js +3 -0
  172. package/.next/standalone/.next/server/chunks/lib_rpc_0r79-w1.js +3 -0
  173. package/.next/standalone/.next/server/chunks/lib_rpc_0yx8ynd.js +3 -0
  174. package/.next/standalone/.next/server/chunks/lib_rpc_12p-o9-.js +3 -0
  175. package/.next/standalone/.next/server/chunks/lib_rpc_1466dnb.js +3 -0
  176. package/.next/standalone/.next/server/chunks/{lib_rpc_0is4qoc.js → lib_rpc_1hjjjr4.js} +1 -1
  177. package/.next/standalone/.next/server/chunks/lib_rpc_1sryxv6.js +3 -0
  178. package/.next/standalone/.next/server/chunks/lib_rpc_1trn-x5.js +3 -0
  179. package/.next/standalone/.next/server/chunks/lib_rpc_1ygu_mv.js +3 -0
  180. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egamyq._.js +3 -0
  181. package/.next/standalone/.next/server/chunks/ssr/_04am_h8._.js +3 -0
  182. package/.next/standalone/.next/server/chunks/ssr/_07zb7lu._.js +1 -1
  183. package/.next/standalone/.next/server/chunks/ssr/_0_79idq._.js +1 -1
  184. package/.next/standalone/.next/server/chunks/ssr/_0gds903._.js +3 -0
  185. package/.next/standalone/.next/server/chunks/ssr/_0klqt9z._.js +3 -0
  186. package/.next/standalone/.next/server/chunks/ssr/{_1k9qfsk._.js → _14jak5s._.js} +6 -2
  187. package/.next/standalone/.next/server/chunks/ssr/_14nxd3q._.js +1 -1
  188. package/.next/standalone/.next/server/chunks/ssr/_1cj2yog._.js +3 -0
  189. package/.next/standalone/.next/server/chunks/ssr/_1fm1ih_._.js +1 -1
  190. package/.next/standalone/.next/server/chunks/ssr/_1hdqw0-._.js +7 -0
  191. package/.next/standalone/.next/server/chunks/ssr/_1k2nmbw._.js +1 -1
  192. package/.next/standalone/.next/server/chunks/ssr/{_0gy11ar._.js → _1r62six._.js} +6 -2
  193. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_insights_page_actions_0-0tf75.js +3 -0
  194. package/.next/standalone/.next/server/chunks/ssr/app_components_0uuff77._.js +2 -2
  195. package/.next/standalone/.next/server/chunks/ssr/app_components_1j3q-h5._.js +2 -2
  196. package/.next/standalone/.next/server/chunks/ssr/{_01o3i5y._.js → app_components_settings_SectorPicker_1c-29qw.js} +2 -6
  197. package/.next/standalone/.next/server/chunks/ssr/app_components_ui_0pdmz2z.js +3 -0
  198. package/.next/standalone/.next/server/chunks/ssr/app_insights_page_1d_chja.js +3 -0
  199. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +14 -14
  200. package/.next/standalone/.next/server/chunks/ssr/app_queue_page_0c6znd6.js +3 -3
  201. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_1f8mjj_.js +1 -1
  202. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +4 -4
  203. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  204. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  205. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  206. package/.next/standalone/.next/server/next-font-manifest.json +4 -0
  207. package/.next/standalone/.next/server/pages/404.html +1 -1
  208. package/.next/standalone/.next/server/pages/500.html +1 -1
  209. package/.next/standalone/.next/server/prefetch-hints.json +14 -0
  210. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  211. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  212. package/.next/standalone/.next/static/chunks/02wnf8dkxegxg.js +34 -0
  213. package/.next/standalone/.next/static/chunks/0hggugbh84m4t.js +21 -0
  214. package/.next/{static/chunks/2eo9pqq9gay3r.js → standalone/.next/static/chunks/0ka4prpk3w9wn.js} +4 -4
  215. package/.next/standalone/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
  216. package/.next/standalone/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
  217. package/.next/{static/chunks/44yn0tcd9dfk3.js → standalone/.next/static/chunks/1bkt_hhjzvbh8.js} +1 -1
  218. package/.next/standalone/.next/static/chunks/1cmphb3kh2ers.css +3 -0
  219. package/.next/{static/chunks/1qbjermbf68xj.js → standalone/.next/static/chunks/1d8yv3k_atka7.js} +1 -1
  220. package/.next/standalone/.next/static/chunks/1ods5h86raivz.js +1 -0
  221. package/.next/standalone/.next/static/chunks/23hc51oa4vkhc.js +5 -0
  222. package/.next/standalone/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
  223. package/.next/standalone/.next/static/chunks/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
  224. package/.next/{static/chunks/2zf4jmz9l3li2.js → standalone/.next/static/chunks/2w-y83mjlpnse.js} +1 -1
  225. package/.next/standalone/.next/static/chunks/2ws1xf293j-tm.js +5 -0
  226. package/.next/standalone/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
  227. package/.next/standalone/.next/static/chunks/3opgg1efrx8q6.js +1 -0
  228. package/.next/standalone/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
  229. package/.next/{static/chunks/0an_b6zi1r_qq.js → standalone/.next/static/chunks/3y40z6of3r9py.js} +1 -5
  230. package/.next/standalone/.next/static/chunks/403dpflln8ah5.js +1 -0
  231. package/.next/standalone/CHANGELOG.md +83 -0
  232. package/.next/standalone/README.md +40 -14
  233. package/.next/standalone/SECURITY.md +17 -4
  234. package/.next/standalone/app/api/outreach/route.js +13 -73
  235. package/.next/standalone/app/api/scraper/route.js +106 -5
  236. package/.next/standalone/app/components/AppHeader.js +22 -6
  237. package/.next/standalone/app/components/AppTabs.js +4 -0
  238. package/.next/standalone/app/components/AutoConnect.js +286 -0
  239. package/.next/standalone/app/components/ChainView.js +75 -2
  240. package/.next/standalone/app/components/FilterPanel.js +8 -1
  241. package/.next/standalone/app/components/LinkedInLimits.js +38 -13
  242. package/.next/standalone/app/components/OutlinkQuest.js +32 -11
  243. package/.next/standalone/app/components/ScanStatusBar.js +18 -3
  244. package/.next/standalone/app/components/ScanTrail.js +13 -3
  245. package/.next/standalone/app/components/SeparationView.js +6 -22
  246. package/.next/standalone/app/components/Sidebar.js +147 -38
  247. package/.next/standalone/app/components/insights/Boards.js +275 -0
  248. package/.next/standalone/app/components/insights/PeopleView.js +266 -0
  249. package/.next/standalone/app/components/insights/Rail.js +156 -0
  250. package/.next/standalone/app/components/insights/Report.js +382 -0
  251. package/.next/standalone/app/components/insights/parts.js +239 -0
  252. package/.next/standalone/app/components/settings/UsageSection.js +50 -3
  253. package/.next/standalone/app/globals.css +2 -3
  254. package/.next/standalone/app/insights/page.js +220 -0
  255. package/.next/standalone/app/page.js +1 -17
  256. package/.next/standalone/app/queue/page.js +30 -18
  257. package/.next/standalone/app/setup/page.js +71 -13
  258. package/.next/standalone/install.sh +7 -6
  259. package/.next/standalone/lib/auto-connect.js +145 -0
  260. package/.next/standalone/lib/companies.js +1 -1
  261. package/.next/standalone/lib/in-progress.js +46 -0
  262. package/.next/standalone/lib/insights-board.js +613 -0
  263. package/.next/standalone/lib/linkedin-limits.js +36 -11
  264. package/.next/standalone/lib/requests-client.js +10 -0
  265. package/.next/standalone/lib/requests.js +124 -0
  266. package/.next/standalone/lib/scan-state.js +1 -0
  267. package/.next/standalone/lib/scanner-setup.js +82 -3
  268. package/.next/standalone/lib/scraper-client.js +18 -5
  269. package/.next/standalone/lib/settings.js +6 -0
  270. package/.next/standalone/lib/usage.js +5 -0
  271. package/.next/standalone/package-lock.json +2 -2
  272. package/.next/standalone/package.json +1 -1
  273. package/.next/standalone/scripts/build-app.mjs +167 -11
  274. package/.next/standalone/scripts/build-desktop.mjs +3 -2
  275. package/.next/standalone/scripts/ci-mac-signing.sh +128 -0
  276. package/.next/standalone/scripts/entitlements/electron.plist +23 -0
  277. package/.next/standalone/scripts/entitlements/node.plist +27 -0
  278. package/.next/standalone/scripts/mac-sign.mjs +563 -0
  279. package/.next/standalone/scripts/make-dmg-background.mjs +2 -1
  280. package/.next/standalone/scripts/scrape.py +569 -9
  281. package/.next/standalone/scripts/set-signing-secrets.sh +96 -0
  282. package/.next/static/chunks/02wnf8dkxegxg.js +34 -0
  283. package/.next/static/chunks/0hggugbh84m4t.js +21 -0
  284. package/.next/{standalone/.next/static/chunks/2eo9pqq9gay3r.js → static/chunks/0ka4prpk3w9wn.js} +4 -4
  285. package/.next/static/chunks/0s_xxwp7z88vv.js +1 -0
  286. package/.next/static/chunks/1-nnl8amfm4yh.js +57 -0
  287. package/.next/{standalone/.next/static/chunks/44yn0tcd9dfk3.js → static/chunks/1bkt_hhjzvbh8.js} +1 -1
  288. package/.next/static/chunks/1cmphb3kh2ers.css +3 -0
  289. package/.next/{standalone/.next/static/chunks/1qbjermbf68xj.js → static/chunks/1d8yv3k_atka7.js} +1 -1
  290. package/.next/static/chunks/1ods5h86raivz.js +1 -0
  291. package/.next/static/chunks/23hc51oa4vkhc.js +5 -0
  292. package/.next/static/chunks/27n8k9wxlz5-7.js +1 -0
  293. package/.next/static/chunks/{0p3g5tfostsep.js → 2q9i7pcxcnph1.js} +2 -2
  294. package/.next/{standalone/.next/static/chunks/2zf4jmz9l3li2.js → static/chunks/2w-y83mjlpnse.js} +1 -1
  295. package/.next/static/chunks/2ws1xf293j-tm.js +5 -0
  296. package/.next/static/chunks/3cqn-r-y5rrw1.js +5 -0
  297. package/.next/static/chunks/3opgg1efrx8q6.js +1 -0
  298. package/.next/static/chunks/3p51fpxxi4d5y.js +34 -0
  299. package/.next/{standalone/.next/static/chunks/0an_b6zi1r_qq.js → static/chunks/3y40z6of3r9py.js} +1 -5
  300. package/.next/static/chunks/403dpflln8ah5.js +1 -0
  301. package/CHANGELOG.md +83 -0
  302. package/README.md +40 -14
  303. package/SECURITY.md +17 -4
  304. package/lib/auto-connect.js +145 -0
  305. package/lib/companies.js +1 -1
  306. package/lib/in-progress.js +46 -0
  307. package/lib/insights-board.js +613 -0
  308. package/lib/linkedin-limits.js +36 -11
  309. package/lib/requests-client.js +10 -0
  310. package/lib/requests.js +124 -0
  311. package/lib/scan-state.js +1 -0
  312. package/lib/scanner-setup.js +82 -3
  313. package/lib/scraper-client.js +18 -5
  314. package/lib/settings.js +6 -0
  315. package/lib/usage.js +5 -0
  316. package/package.json +1 -1
  317. package/scripts/scrape.py +569 -9
  318. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_4y8z7._.js +0 -8
  319. package/.next/standalone/.next/server/chunks/_02twlca._.js +0 -10
  320. package/.next/standalone/.next/server/chunks/lib_rpc_0nef_n7.js +0 -3
  321. package/.next/standalone/.next/server/chunks/lib_rpc_0plrzra.js +0 -3
  322. package/.next/standalone/.next/server/chunks/lib_rpc_13a4m0c.js +0 -3
  323. package/.next/standalone/.next/server/chunks/lib_rpc_1if17c-.js +0 -3
  324. package/.next/standalone/.next/server/chunks/lib_rpc_1j-zw7v.js +0 -3
  325. package/.next/standalone/.next/server/chunks/lib_rpc_1sngt-q.js +0 -3
  326. package/.next/standalone/.next/server/chunks/lib_rpc_1v2sgme.js +0 -3
  327. package/.next/standalone/.next/server/chunks/lib_rpc_1vh-tgx.js +0 -3
  328. package/.next/standalone/.next/server/chunks/lib_rpc_1zaubz7.js +0 -3
  329. package/.next/standalone/.next/server/chunks/ssr/_02sband._.js +0 -7
  330. package/.next/standalone/.next/server/chunks/ssr/_189g8lg._.js +0 -3
  331. package/.next/standalone/.next/server/chunks/ssr/_1f_n00p._.js +0 -3
  332. package/.next/standalone/.next/server/chunks/ssr/app_components_0t908t-._.js +0 -3
  333. package/.next/standalone/.next/static/chunks/0e3g0sil79cus.js +0 -21
  334. package/.next/standalone/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
  335. package/.next/standalone/.next/static/chunks/163b-20vwa06i.js +0 -34
  336. package/.next/standalone/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
  337. package/.next/standalone/.next/static/chunks/23_1z47al92nz.js +0 -57
  338. package/.next/standalone/.next/static/chunks/260bomtr214m8.js +0 -34
  339. package/.next/standalone/.next/static/chunks/2xk2ra4piiuod.js +0 -34
  340. package/.next/standalone/.next/static/chunks/3b0-14cxqsprt.js +0 -1
  341. package/.next/standalone/.next/static/chunks/3jarus1_38s2z.js +0 -1
  342. package/.next/standalone/.next/static/chunks/3ssu341hav_sq.css +0 -3
  343. package/.next/standalone/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
  344. package/.next/static/chunks/0e3g0sil79cus.js +0 -21
  345. package/.next/static/chunks/0zd0t7e60bn4z.js +0 -1
  346. package/.next/static/chunks/163b-20vwa06i.js +0 -34
  347. package/.next/static/chunks/1pa-2v1ajvrko.js +0 -1
  348. package/.next/static/chunks/23_1z47al92nz.js +0 -57
  349. package/.next/static/chunks/260bomtr214m8.js +0 -34
  350. package/.next/static/chunks/2xk2ra4piiuod.js +0 -34
  351. package/.next/static/chunks/3b0-14cxqsprt.js +0 -1
  352. package/.next/static/chunks/3jarus1_38s2z.js +0 -1
  353. package/.next/static/chunks/3ssu341hav_sq.css +0 -3
  354. package/.next/static/chunks/3v1qd3sqhqn0d.js +0 -1
  355. /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
  356. /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
  357. /package/.next/standalone/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
  358. /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_buildManifest.js +0 -0
  359. /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_clientMiddlewareManifest.js +0 -0
  360. /package/.next/static/{ZVpLBK-2vpllv2HxOFs2d → mwCGF3OV3CWV4SjUgg5T8}/_ssgManifest.js +0 -0
@@ -21,10 +21,15 @@
21
21
  // Chromium instead would make the scanner MORE detectable, not less, which
22
22
  // defeats the point of driving the user's real browser.
23
23
  //
24
- // Unsigned, because notarisation needs a paid Apple Developer account. macOS
25
- // will refuse the first launch; the user allows it once in System Settings.
26
- // An ad-hoc signature is applied anyway — it costs nothing and avoids the
27
- // separate "app is damaged" failure that unsigned arm64 binaries otherwise hit.
24
+ // Signing (DESKTOP.md D4, scripts/mac-sign.mjs). With a Developer ID identity
25
+ // in SIX_DEGREES_SIGN_IDENTITY, every program and library is signed inside out
26
+ // with the hardened runtime, and with SIX_DEGREES_NOTARY_KEY, _KEY_ID and
27
+ // _ISSUER the app and the disk image are notarized by Apple and stapled: it
28
+ // opens like any Mac app. Releases do this (release.yml). Without an identity
29
+ // (forks, pull requests, a local build) the app is signed ad hoc, exactly as
30
+ // before D4: it costs nothing and avoids the separate "app is damaged" failure
31
+ // that unsigned arm64 binaries otherwise hit, and a copy downloaded in a
32
+ // browser then needs one approval in System Settings.
28
33
 
29
34
  import { execFileSync } from 'node:child_process';
30
35
  import { createHash } from 'node:crypto';
@@ -38,6 +43,9 @@ import { fileURLToPath } from 'node:url';
38
43
  import {
39
44
  standaloneBuild, downloadVerified, machoSlices, machoSlice, megabytes, IMPORTS,
40
45
  } from '../lib/scanner-python.js';
46
+ import {
47
+ signingSetup, signDeveloperId, signatureInfo, signerName, signImage, notarize, staple, stapleValid, assess, SigningError,
48
+ } from './mac-sign.mjs';
41
49
 
42
50
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
43
51
  const pkg = JSON.parse(readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
@@ -53,6 +61,16 @@ if (!['classic', 'electron'].includes(SHELL)) {
53
61
  console.error(`\n ✗ --shell must be classic or electron, not ${SHELL}\n`);
54
62
  process.exit(1);
55
63
  }
64
+ // How this build is signed: ad hoc, or Developer ID (and notarized) when the
65
+ // environment names an identity (scripts/mac-sign.mjs). A setting that can't be
66
+ // right stops the build here, before anything is built.
67
+ const SIGNING = signingSetup(process.env, { exists: existsSync });
68
+ if (SIGNING.error) {
69
+ console.error(`\n ✗ ${SIGNING.error}\n`);
70
+ process.exit(1);
71
+ }
72
+ const DEVELOPER_ID = SIGNING.mode === 'developer-id';
73
+ const NOTARIZE = Boolean(DEVELOPER_ID && SIGNING.notary);
56
74
  const APP_NAME = 'Six Degrees';
57
75
  const OUT = path.join(ROOT, 'dist');
58
76
  const APP = path.join(OUT, `${APP_NAME}.app`);
@@ -115,6 +133,9 @@ function detach(mountPoint, device) {
115
133
  rmSync(OUT, { recursive: true, force: true });
116
134
 
117
135
  step('Building the app');
136
+ console.log(DEVELOPER_ID
137
+ ? ` it will be signed with Developer ID${NOTARIZE ? ' and notarized by Apple' : ', not notarized (no SIX_DEGREES_NOTARY_* settings)'}`
138
+ : ' it will be signed ad hoc (no SIX_DEGREES_SIGN_IDENTITY)');
118
139
  if (process.argv.includes('--fast') && existsSync(path.join(ROOT, '.next', 'standalone', 'server.js'))) {
119
140
  console.log(' --fast: reusing the existing build (make sure it is current)');
120
141
  } else {
@@ -290,7 +311,10 @@ writeFileSync(path.join(APP, 'Contents', 'Info.plist'), `<?xml version="1.0" enc
290
311
  </plist>
291
312
  `);
292
313
 
293
- // ---- 4. sign, ad-hoc -------------------------------------------------------
314
+ // ---- 4. sign ---------------------------------------------------------------
315
+ if (DEVELOPER_ID) {
316
+ signWithDeveloperId(APP);
317
+ } else {
294
318
  step('Signing (ad-hoc)');
295
319
  try {
296
320
  run('codesign', ['--force', '--deep', '--sign', '-', APP]);
@@ -298,6 +322,7 @@ try {
298
322
  } catch {
299
323
  console.log(' codesign failed; the app will still run after the one-time approval');
300
324
  }
325
+ }
301
326
  } // end of the classic shell
302
327
 
303
328
  // ---- the Electron shell (--shell=electron) -----------------------------------
@@ -348,6 +373,10 @@ async function buildElectronShell() {
348
373
  // and nothing copies them again (TRAPS §37).
349
374
  await bundlePython(path.join(APP, 'Contents', 'Resources'));
350
375
 
376
+ if (DEVELOPER_ID) {
377
+ signWithDeveloperId(APP);
378
+ return;
379
+ }
351
380
  step('Signing (ad-hoc)');
352
381
  // Electron's framework and helpers must all carry the same kind of signature,
353
382
  // or macOS refuses to load them; re-signing the whole bundle ad hoc does that.
@@ -359,6 +388,96 @@ async function buildElectronShell() {
359
388
  console.log(' signed ad-hoc and verified — no Apple account needed, still unnotarised');
360
389
  }
361
390
 
391
+ // ---- Developer ID and notarization (DESKTOP.md D4) ----------------------------
392
+ // Inside out with the hardened runtime (scripts/mac-sign.mjs signDeveloperId:
393
+ // every loose program and library, then the helper apps and frameworks deepest
394
+ // first, then the app), then the signed programs are run once to prove their
395
+ // entitlements are enough. With the notary settings, the app goes to Apple and
396
+ // comes back with its ticket stapled to it, and only then is the disk image made
397
+ // from it: the app people drag to Applications carries its own ticket, and so
398
+ // does the copy install.sh and the in-app updater put in place with ditto.
399
+ function signWithDeveloperId(app) {
400
+ step('Signing with Developer ID (inside out, hardened runtime, timestamped)');
401
+ const { info } = guard(() => signDeveloperId(app, SIGNING));
402
+ checkSignedRuntime(app, info);
403
+ if (!NOTARIZE) return;
404
+ step('Notarizing the app (Apple; usually a few minutes)');
405
+ const zip = path.join(OUT, 'notarize-app.zip');
406
+ run('ditto', ['-c', '-k', '--sequesterRsrc', '--keepParent', app, zip]);
407
+ guard(() => notarize(zip, SIGNING.notary, { what: 'the app' }));
408
+ rmSync(zip, { force: true });
409
+ guard(() => staple(app));
410
+ const verdict = assess(app, 'exec');
411
+ if (!verdict.ok && !verdict.disabled) fail(`Gatekeeper doesn't accept the stapled app as notarized: ${oneLine(verdict.text)}`);
412
+ console.log(verdict.ok ? ` stapled; Gatekeeper says: ${verdict.source}` : gatekeeperOff());
413
+ }
414
+
415
+ // The signed programs, run as the app runs them: the server's Node (and sharp,
416
+ // the one native module it loads), the scanner's Python with its packages, and
417
+ // Playwright's driver. A missing entitlement or a library that fails library
418
+ // validation stops the build here, minutes before notarization would, and long
419
+ // before a user's scan. Nothing here writes into the app (no bytecode: -B and
420
+ // PYTHONDONTWRITEBYTECODE), which the image check would catch anyway.
421
+ function checkSignedRuntime(app, info) {
422
+ step('Running the signed programs under the hardened runtime');
423
+ if (!info.team) {
424
+ // A self-signed test identity has no Team ID, and library validation then
425
+ // refuses even the app's own libraries. A Developer ID always has one.
426
+ console.log(' skipped: this identity has no Team ID (a test identity, not a Developer ID)');
427
+ return;
428
+ }
429
+ const res = path.join(app, 'Contents', 'Resources');
430
+ const env = {
431
+ HOME: os.homedir(), TMPDIR: os.tmpdir(), PATH: '/usr/bin:/bin:/usr/sbin:/sbin', LANG: 'en_US.UTF-8',
432
+ PYTHONNOUSERSITE: '1', PYTHONDONTWRITEBYTECODE: '1',
433
+ };
434
+ const server = [path.join(res, 'server'), path.join(res, 'app')].find((d) => existsSync(path.join(d, 'server.js')));
435
+ const sharp = server && existsSync(path.join(server, 'node_modules', 'sharp')) ? path.join(server, 'node_modules', 'sharp') : null;
436
+ console.log(` the server's Node: ${mustRun(path.join(res, 'node'), ['-e',
437
+ `require('node:sqlite');${sharp ? ` require(${JSON.stringify(sharp)});` : ''} console.log(process.version${sharp ? ", '· sharp loads'" : ''})`],
438
+ env, 'The app\'s Node doesn\'t run once signed (its entitlements: scripts/entitlements/node.plist)')}`);
439
+ const py = path.join(res, 'python');
440
+ if (!existsSync(path.join(py, 'bin', 'python3'))) return;
441
+ console.log(` the scanner's Python: ${mustRun(path.join(py, 'bin', 'python3'), ['-E', '-s', '-B', '-c',
442
+ `${IMPORTS}; import sys; print(sys.version.split()[0], "· its packages load")`],
443
+ env, 'The scanner\'s Python doesn\'t run once signed')}`);
444
+ const xy = readdirSync(path.join(py, 'lib')).find((n) => /^python3\.\d+$/.test(n));
445
+ const driver = path.join(py, 'lib', xy || 'python3', 'site-packages', 'playwright', 'driver');
446
+ if (existsSync(path.join(driver, 'node'))) {
447
+ console.log(` Playwright's driver: ${mustRun(path.join(driver, 'node'), [path.join(driver, 'package', 'cli.js'), '--version'],
448
+ env, 'Playwright\'s driver doesn\'t start once signed')}`);
449
+ }
450
+ }
451
+
452
+ // A step of the signing that failed: its reason, never a credential (mac-sign.mjs
453
+ // never puts one in a message), and the build stops.
454
+ function guard(fn) {
455
+ try {
456
+ return fn();
457
+ } catch (err) {
458
+ fail(err instanceof SigningError ? err.message : `Signing failed: ${String(err.message || err).split('\n')[0]}`);
459
+ }
460
+ return undefined;
461
+ }
462
+
463
+ function fail(message) {
464
+ console.error(`\n ✗ ${message}\n`);
465
+ process.exit(1);
466
+ }
467
+
468
+ // When this machine has Gatekeeper's assessments turned off, spctl accepts
469
+ // anything and can't confirm notarization; Apple's "Accepted" and the stapled
470
+ // tickets (validated) are what's left, and the log says so.
471
+ function gatekeeperOff() {
472
+ return ' stapled; Gatekeeper\'s assessments are turned off on this machine, so it can\'t be asked: '
473
+ + 'the stapled tickets and Apple\'s Accepted are the check';
474
+ }
475
+
476
+ // (Function declarations, not consts: the shells call these before this line runs.)
477
+ function oneLine(text) {
478
+ return String(text || '').trim().split('\n').join(' | ');
479
+ }
480
+
362
481
  // ---- the scanner's Python (Electron app only; DESKTOP.md D2) ------------------
363
482
  // A standalone CPython from python-build-standalone, with the scanner's packages
364
483
  // installed, at Contents/Resources/python. desktop/main.mjs names it to the
@@ -602,9 +721,11 @@ mkdirSync(staging, { recursive: true });
602
721
  // on the build machine: anywhere else those paths do not exist (TRAPS §37).
603
722
  run('ditto', [APP, path.join(staging, `${APP_NAME}.app`)]);
604
723
 
605
- // The picture behind the window says what to do: drag across, then the one-time
606
- // Open Anyway step, since the app is unsigned. It replaces the READ ME text file
607
- // this image used to carry. Made by scripts/make-dmg-background.mjs from
724
+ // The picture behind the window says what to do: drag across, and that the app
725
+ // is signed and notarized, so it opens like any Mac app (it said Open Anyway
726
+ // until D4). It replaces the READ ME text file this image used to carry. A build
727
+ // signed ad hoc gets the same picture: it never left this Mac, so macOS doesn't
728
+ // ask about it either. Made by scripts/make-dmg-background.mjs from
608
729
  // scripts/dmg/background.html; its geometry and the positions below are one
609
730
  // layout, so change them together.
610
731
  const BACKGROUND = path.join(ROOT, 'scripts', 'dmg', 'background.tiff');
@@ -742,6 +863,21 @@ detach(mount, device);
742
863
  run('hdiutil', ['convert', rw, '-format', 'UDZO', '-imagekey', 'zlib-level=9', '-o', dmg, '-ov']);
743
864
  rmSync(rw, { force: true });
744
865
  rmSync(staging, { recursive: true, force: true });
866
+
867
+ // The image gets its own signature and ticket (DESKTOP.md D4): Gatekeeper judges
868
+ // a downloaded .dmg by them before it looks at the app inside. Made from the
869
+ // stapled app, so the app keeps its own ticket once it is copied out.
870
+ if (DEVELOPER_ID) {
871
+ step('Signing the disk image');
872
+ guard(() => signImage(dmg, SIGNING));
873
+ console.log(' signed and verified');
874
+ if (NOTARIZE) {
875
+ step('Notarizing the disk image (Apple; usually a few minutes)');
876
+ guard(() => notarize(dmg, SIGNING.notary, { what: 'the disk image' }));
877
+ guard(() => staple(dmg));
878
+ console.log(' stapled');
879
+ }
880
+ }
745
881
  checkImage(dmg);
746
882
 
747
883
  // Check the app as people will get it: inside the finished image, not the copy
@@ -763,6 +899,12 @@ function checkImage(image) {
763
899
  } catch (err) {
764
900
  problem = `its signature does not verify: ${(err.stderr || '').toString().trim().split('\n').slice(0, 2).join(' ')}`;
765
901
  }
902
+ // Notarized: the app inside carries its ticket, and Gatekeeper accepts it.
903
+ if (NOTARIZE && !problem) {
904
+ const verdict = assess(inside, 'exec');
905
+ if (!stapleValid(inside)) problem = 'it has no valid stapled notarization ticket';
906
+ else if (!verdict.ok && !verdict.disabled) problem = `Gatekeeper doesn't accept it as notarized (${oneLine(verdict.text)})`;
907
+ }
766
908
  const escaping = execFileSync('find', [inside, '-type', 'l'])
767
909
  .toString().split('\n').filter(Boolean)
768
910
  .filter((link) => {
@@ -778,10 +920,24 @@ function checkImage(image) {
778
920
  console.error(`\n ✗ The app inside ${path.basename(image)} is broken: ${problem}\n`);
779
921
  process.exit(1);
780
922
  }
781
- console.log(' signature verifies, and every link stays inside the app');
923
+ // And the image itself, as Gatekeeper judges a downloaded one: by its own
924
+ // signature (context:primary-signature) and its own ticket.
925
+ if (NOTARIZE) {
926
+ const verdict = assess(image, 'open');
927
+ if (!stapleValid(image)) fail(`${path.basename(image)} has no valid stapled notarization ticket.`);
928
+ if (!verdict.ok && !verdict.disabled) fail(`Gatekeeper doesn't accept ${path.basename(image)} as notarized: ${oneLine(verdict.text)}`);
929
+ if (verdict.disabled) console.log(gatekeeperOff());
930
+ }
931
+ console.log(` signature verifies, and every link stays inside the app${NOTARIZE ? '; the app and the image are notarized and stapled, and Gatekeeper accepts both' : ''}`);
782
932
  }
783
933
 
784
934
  const size = execFileSync('du', ['-h', dmg]).toString().split('\t')[0];
785
935
  console.log(`\n✓ ${dmg} (${size})\n`);
786
- console.log(' Unsigned by design: notarisation needs a paid Apple account.');
787
- console.log(' First launch needs one approval in System Settings > Privacy & Security.\n');
936
+ if (DEVELOPER_ID) {
937
+ const who = signerName(signatureInfo(APP).authority) || 'this Developer ID';
938
+ if (NOTARIZE) console.log(` Signed by ${who} and notarized by Apple: it opens like any Mac app.\n`);
939
+ else console.log(` Signed by ${who}, not notarized: a copy downloaded in a browser still needs one approval\n in System Settings > Privacy & Security.\n`);
940
+ } else {
941
+ console.log(' Signed ad hoc (no Developer ID here: SIX_DEGREES_SIGN_IDENTITY). A copy downloaded in a browser');
942
+ console.log(' needs one approval in System Settings > Privacy & Security.\n');
943
+ }
@@ -14,8 +14,9 @@
14
14
  // Menu and Desktop shortcuts. No admin rights asked for.
15
15
  // Linux @electron/packager, then a .deb (chrome-sandbox setuid root, which
16
16
  // Electron needs on Ubuntu 24.04 and later) and a plain .tar.gz.
17
- // Unsigned, like the Mac app until D4: Windows shows SmartScreen's "More info →
18
- // Run anyway" the first time.
17
+ // Unsigned (the Mac app is signed and notarized since D4; Windows signing is
18
+ // D4's other half): Windows shows SmartScreen's "More info → Run anyway" the
19
+ // first time.
19
20
  //
20
21
  // Built on the platform it is for (release.yml has a job each): pip installs
21
22
  // the Python's packages by running that Python. No new npm dependency: packager
@@ -0,0 +1,128 @@
1
+ #!/bin/bash
2
+ # The Mac release's Developer ID, for .github/workflows/release.yml's Mac jobs
3
+ # (docs/brain/DESKTOP.md D4). Two commands:
4
+ #
5
+ # ci-mac-signing.sh setup VERSION DRY_RUN before the build
6
+ # ci-mac-signing.sh cleanup after it, always (if: always())
7
+ #
8
+ # setup asks scripts/mac-sign.mjs whether this release signs (release-plan):
9
+ # - all five secrets set: it signs, dry run or not;
10
+ # - none set: ad hoc, as before 1.0, unless this is a real release of 1.0.0 or
11
+ # later, which must be signed: then it fails here, before anything is built;
12
+ # - some but not all: always a mistake, and it fails, naming the missing ones.
13
+ # When it signs, it decodes the certificate (.p12, which carries Apple's
14
+ # Developer ID G2 intermediate too) into a temporary keychain with a random
15
+ # password, finds the "Developer ID Application" identity in it, decodes the App
16
+ # Store Connect API key (.p8) for notarytool, and hands the build their places
17
+ # through $GITHUB_ENV: SIX_DEGREES_SIGN_IDENTITY (the identity's SHA-1: names
18
+ # can repeat across renewals, a hash can't), SIX_DEGREES_SIGN_KEYCHAIN and
19
+ # SIX_DEGREES_NOTARY_KEY. The key's id and issuer reach the build step straight
20
+ # from the secrets (release.yml), never through a file. MAC_SIGNING says which
21
+ # it was (developer-id or ad-hoc), for the smoke test and the release notes.
22
+ #
23
+ # The secrets arrive as environment variables, set by release.yml from GitHub's
24
+ # secrets and nowhere else. Nothing here prints one: values go to files made
25
+ # under umask 077, or to `security` itself, and GitHub masks them in the log
26
+ # besides. Never run this with `bash -x`. cleanup deletes the keychain, puts the
27
+ # keychain search list back as it was, and removes every decoded file.
28
+
29
+ set -euo pipefail
30
+
31
+ work="${RUNNER_TEMP:?RUNNER_TEMP is not set (this runs in GitHub Actions)}/six-degrees-signing"
32
+ keychain="$work/signing.keychain-db"
33
+ here="$(cd "$(dirname "$0")" && pwd)"
34
+
35
+ say() { printf '%s\n' "$*"; }
36
+ die() { printf '::error::%s\n' "$*"; exit 1; }
37
+
38
+ setup() {
39
+ local version="${1:?usage: ci-mac-signing.sh setup VERSION DRY_RUN}" dry_run="${2:-false}" plan
40
+ local genv="${GITHUB_ENV:?GITHUB_ENV is not set}"
41
+ # release-plan reads only whether each secret is set, never a value.
42
+ if ! plan="$(node "$here/mac-sign.mjs" release-plan "$version" "$dry_run")"; then
43
+ die "The Mac app can't be built as asked: see the line above."
44
+ fi
45
+ if [ "$plan" != developer-id ]; then
46
+ echo "MAC_SIGNING=ad-hoc" >> "$genv"
47
+ say "Signing: ad hoc."
48
+ return 0
49
+ fi
50
+
51
+ umask 077
52
+ rm -rf "$work"
53
+ mkdir -p "$work"
54
+
55
+ # The certificate, for the keychain only; its file goes as soon as it's in.
56
+ printf '%s' "$MACOS_SIGN_P12_BASE64" | base64 --decode > "$work/cert.p12" 2>/dev/null \
57
+ || die "MACOS_SIGN_P12_BASE64 isn't base64 (set it again with scripts/set-signing-secrets.sh)."
58
+ [ -s "$work/cert.p12" ] || die "MACOS_SIGN_P12_BASE64 decodes to nothing."
59
+ # The API key, for notarytool, kept until cleanup.
60
+ printf '%s' "$APPLE_API_KEY_P8_BASE64" | base64 --decode > "$work/AuthKey.p8" 2>/dev/null \
61
+ || die "APPLE_API_KEY_P8_BASE64 isn't base64 (set it again with scripts/set-signing-secrets.sh)."
62
+ grep -q -- '-----BEGIN PRIVATE KEY-----' "$work/AuthKey.p8" \
63
+ || die "APPLE_API_KEY_P8_BASE64 doesn't decode to an App Store Connect API key (.p8)."
64
+
65
+ # A keychain of its own, with a password nobody needs to know, unlocked for
66
+ # the length of the job (6 hours), and codesign allowed to use the key without
67
+ # asking (the partition list): there is nobody to click Allow on a runner.
68
+ local kc_pass
69
+ kc_pass="$(head -c 32 /dev/urandom | base64 | tr -d '\n=+/')"
70
+ security create-keychain -p "$kc_pass" "$keychain"
71
+ security set-keychain-settings -lut 21600 "$keychain"
72
+ security unlock-keychain -p "$kc_pass" "$keychain"
73
+ security import "$work/cert.p12" -k "$keychain" -f pkcs12 -P "$MACOS_SIGN_P12_PASSWORD" \
74
+ -T /usr/bin/codesign -T /usr/bin/security > /dev/null \
75
+ || die "The certificate wouldn't import: is MACOS_SIGN_P12_PASSWORD the .p12's password?"
76
+ rm -f "$work/cert.p12"
77
+ security set-key-partition-list -S apple-tool:,apple: -s -k "$kc_pass" "$keychain" > /dev/null
78
+ kc_pass=""
79
+
80
+ # codesign finds an identity only in a keychain on the search list. The list as
81
+ # it was is kept, for cleanup to put back.
82
+ security list-keychains -d user > "$work/search-list"
83
+ local line orig=()
84
+ while IFS= read -r line; do
85
+ line="${line#"${line%%[![:space:]]*}"}"; line="${line%\"}"; line="${line#\"}"
86
+ [ -n "$line" ] && orig+=("$line")
87
+ done < "$work/search-list"
88
+ security list-keychains -d user -s "$keychain" ${orig[@]+"${orig[@]}"}
89
+
90
+ # By its kind, not its full name: whatever Developer ID Application identity
91
+ # the certificate holds, and it must be valid (its chain reaches Apple's root).
92
+ local found identity name
93
+ found="$(security find-identity -v -p codesigning "$keychain" | grep '"Developer ID Application: ' | head -1 || true)"
94
+ identity="$(printf '%s\n' "$found" | awk '{print $2}')"
95
+ name="$(printf '%s\n' "$found" | sed -n 's/.*"\(Developer ID Application: [^"]*\)".*/\1/p')"
96
+ if [ -z "$identity" ]; then
97
+ say "The keychain holds these code-signing identities (valid or not):"
98
+ security find-identity -p codesigning "$keychain" | sed 's/^/ /'
99
+ die "No valid \"Developer ID Application\" identity in MACOS_SIGN_P12_BASE64. Export the Developer ID Application certificate with its private key (and Apple's intermediate) as the .p12."
100
+ fi
101
+ {
102
+ echo "SIX_DEGREES_SIGN_IDENTITY=$identity"
103
+ echo "SIX_DEGREES_SIGN_KEYCHAIN=$keychain"
104
+ echo "SIX_DEGREES_NOTARY_KEY=$work/AuthKey.p8"
105
+ echo "MAC_SIGNING=developer-id"
106
+ } >> "$genv"
107
+ say "Signing: $name, from a temporary keychain; notarized with the App Store Connect API key."
108
+ }
109
+
110
+ cleanup() {
111
+ if [ -f "$work/search-list" ]; then
112
+ local line orig=()
113
+ while IFS= read -r line; do
114
+ line="${line#"${line%%[![:space:]]*}"}"; line="${line%\"}"; line="${line#\"}"
115
+ [ -n "$line" ] && orig+=("$line")
116
+ done < "$work/search-list"
117
+ security list-keychains -d user -s ${orig[@]+"${orig[@]}"} || true
118
+ fi
119
+ if [ -e "$keychain" ]; then security delete-keychain "$keychain" || true; fi
120
+ rm -rf "$work"
121
+ say "Signing: cleaned up (no keychain, key or certificate left)."
122
+ }
123
+
124
+ case "${1:-}" in
125
+ setup) shift; setup "$@" ;;
126
+ cleanup) cleanup ;;
127
+ *) echo "usage: ci-mac-signing.sh setup VERSION DRY_RUN | cleanup" >&2; exit 2 ;;
128
+ esac
@@ -0,0 +1,23 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <!--
4
+ Six Degrees.app and its Electron helper apps (GPU, Renderer, Plugin), signed
5
+ with Developer ID and the hardened runtime (scripts/mac-sign.mjs, DESKTOP.md D4).
6
+
7
+ allow-jit V8 compiles JavaScript as it runs; the hardened
8
+ runtime refuses that without it.
9
+ allow-unsigned-executable-memory what V8 still uses where it can't use MAP_JIT
10
+ (Intel Macs). Discord's and Electron's own
11
+ templates carry the same two.
12
+
13
+ Never disable-library-validation: every library the app loads is signed by the
14
+ same team in the same pass, and it loads nothing from outside itself.
15
+ -->
16
+ <plist version="1.0">
17
+ <dict>
18
+ <key>com.apple.security.cs.allow-jit</key>
19
+ <true/>
20
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
21
+ <true/>
22
+ </dict>
23
+ </plist>
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <!--
4
+ The Node inside the app (Contents/Resources/node), which runs the server, and
5
+ Playwright's driver's Node when it isn't a link to that one. Signed with
6
+ Developer ID and the hardened runtime (scripts/mac-sign.mjs, DESKTOP.md D4).
7
+
8
+ allow-jit V8 compiles JavaScript as it runs. Without it
9
+ Node 24 stops before running anything: "Failed
10
+ to reserve virtual memory for CodeRange"
11
+ (checked on this build's Node, 2026-10-04).
12
+ allow-unsigned-executable-memory what V8 still uses where it can't use MAP_JIT
13
+ (Intel Macs). Node's own release signature
14
+ carries both.
15
+
16
+ Never disable-library-validation, which Node's own signature does carry so that
17
+ anyone's native addons load: the only native code this server loads is the
18
+ app's own (sharp and its libvips), signed by the same team in the same pass.
19
+ -->
20
+ <plist version="1.0">
21
+ <dict>
22
+ <key>com.apple.security.cs.allow-jit</key>
23
+ <true/>
24
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
25
+ <true/>
26
+ </dict>
27
+ </plist>