| … | … | @@ -51,7 +51,7 @@ const DEFAULT_CATALOGS = [ |
| 51 | 51 | ] |
| 52 | 52 | const REQUIRED_FEATURED = ['Keet', 'PearPass', 'anonGPT', 'Paste', 'Peercord'] |
| 53 | 53 | const CATALOG_SEARCH_TERMS = ['peercord', 'peerit', 'keet', 'paste'] |
| 54 | | const PEERCORD_LINK = 'pear://wmir47w7mai3b1skj66mx7fzso6k6o91kipaney7gtt69npimouy' |
| 54 | const PEERCORD_MIGRATION_ID = 'wmir47w7mai3b1skj66mx7fzso6k6o91kipaney7gtt69npimouy' |
| 55 | 55 | const RELEASE_EVIDENCE_SECTION = 'Desktop GUI And User Stories' |
| 56 | 56 | |
| 57 | 57 | function parseArgs (argv) { |
| … | … | @@ -472,20 +472,20 @@ function assertCatalogues (catalogResult) { |
| 472 | 472 | |
| 473 | 473 | const peercord = byName.get('peercord') |
| 474 | 474 | if (!peercord) throw new Error('Peercord missing from catalogue') |
| 475 | | if (peercord.type !== 'standalone') throw new Error(`Peercord type mismatch: expected standalone, got ${peercord.type || '(missing)'}`) |
| 476 | | if (peercord.link !== PEERCORD_LINK) throw new Error(`Peercord link mismatch: ${peercord.link || '(missing)'}`) |
| 477 | | if (peercord.driveKey) throw new Error('Peercord unexpectedly has a driveKey; standalone pear:// apps should launch in a window') |
| 475 | if (peercord.legacyMigrationId !== PEERCORD_MIGRATION_ID) throw new Error(`Peercord migration id mismatch: ${peercord.legacyMigrationId || '(missing)'}`) |
| 476 | if (peercord.nativeDelivery?.status !== 'migration-required') throw new Error('Peercord must require a verified native v3 package') |
| 477 | if (peercord.link || peercord.driveKey) throw new Error('Peercord must not expose a remote executable or browsable content target') |
| 478 | 478 | |
| 479 | 479 | return { |
| 480 | 480 | catalogs: catalogs.length, |
| 481 | 481 | apps: apps.length, |
| 482 | 482 | featured, |
| 483 | 483 | peercord: { |
| 484 | | type: peercord.type, |
| 485 | | link: peercord.link, |
| 484 | nativeDelivery: peercord.nativeDelivery, |
| 485 | legacyMigrationId: peercord.legacyMigrationId, |
| 486 | 486 | sourceUrl: peercord.sourceUrl || null, |
| 487 | 487 | license: peercord.license || null, |
| 488 | | runMode: 'window' |
| 488 | runMode: 'migration-required' |
| 489 | 489 | } |
| 490 | 490 | } |
| 491 | 491 | } |
| … | … | @@ -892,23 +892,23 @@ async function runSafeCatalogueAppOpenStory (ws, args, catalogResult) { |
| 892 | 892 | |
| 893 | 893 | function runFeaturedAppRegressionStory (catalogResult, safeOpen) { |
| 894 | 894 | const apps = Array.isArray(catalogResult?.apps) ? catalogResult.apps : [] |
| 895 | | const standaloneTargets = REQUIRED_FEATURED |
| 895 | const migrationRequired = REQUIRED_FEATURED |
| 896 | 896 | .map((name) => findAppByName(apps, name)) |
| 897 | 897 | .filter(Boolean) |
| 898 | | .filter((app) => /^pear:\/\//i.test(String(app.link || ''))) |
| 898 | .filter((app) => app.nativeDelivery?.status === 'migration-required') |
| 899 | 899 | .map((app) => ({ |
| 900 | 900 | name: app.name || app.id, |
| 901 | | type: app.type || 'standalone', |
| 902 | | link: app.link, |
| 901 | legacyMigrationId: app.legacyMigrationId || null, |
| 902 | nativeDelivery: app.nativeDelivery, |
| 903 | 903 | action: launchActionForApp(app) |
| 904 | 904 | })) |
| 905 | 905 | |
| 906 | | if (!standaloneTargets.some((app) => sameNameOrId(app, 'keet'))) { |
| 907 | | throw new Error('featured app regression story could not verify Keet window launch target') |
| 906 | if (!migrationRequired.some((app) => sameNameOrId(app, 'keet'))) { |
| 907 | throw new Error('featured app regression story could not verify Keet migration state') |
| 908 | 908 | } |
| 909 | | for (const app of standaloneTargets) { |
| 910 | | if (app.action.primary !== 'open-window') { |
| 911 | | throw new Error(`featured app regression launch action mismatch for ${app.name}`) |
| 909 | for (const app of migrationRequired) { |
| 910 | if (app.action.primary !== 'migration-required' || !app.legacyMigrationId) { |
| 911 | throw new Error(`featured app regression migration state mismatch for ${app.name}`) |
| 912 | 912 | } |
| 913 | 913 | } |
| 914 | 914 | |
| … | … | @@ -920,8 +920,8 @@ function runFeaturedAppRegressionStory (catalogResult, safeOpen) { |
| 920 | 920 | bytes: safeOpen.bytes, |
| 921 | 921 | action: safeOpen.action |
| 922 | 922 | }, |
| 923 | | standaloneTargets, |
| 924 | | automationScope: 'safe featured Hyperdrive open plus standalone pear:// target validation; no third-party trust approval' |
| 923 | migrationRequired, |
| 924 | automationScope: 'safe featured Hyperdrive open plus non-executable native migration-state validation; no third-party code execution' |
| 925 | 925 | } |
| 926 | 926 | } |
| 927 | 927 | |
| … | … | @@ -1061,12 +1061,12 @@ function launchActionForApp (app) { |
| 1061 | 1061 | const link = String(app?.link || '').trim() |
| 1062 | 1062 | const driveKey = String(app?.driveKey || '').trim().toLowerCase() |
| 1063 | 1063 | const hasDrive = isHyperDriveKey(driveKey) |
| 1064 | | if (/^(pear|file):\/\//i.test(link)) { |
| 1064 | if (app?.nativeDelivery?.status === 'migration-required') { |
| 1065 | 1065 | return { |
| 1066 | | primary: 'open-window', |
| 1067 | | openPage: hasDrive, |
| 1066 | primary: 'migration-required', |
| 1067 | openPage: false, |
| 1068 | 1068 | runInTab: false, |
| 1069 | | reason: `${app?.type || 'standalone'} pear/file app` |
| 1069 | reason: 'verified native v3 package required' |
| 1070 | 1070 | } |
| 1071 | 1071 | } |
| 1072 | 1072 | if (/^hyper:\/\//i.test(link) || hasDrive) { |
| … | … | @@ -1139,7 +1139,7 @@ function buildReleaseEvidence (result) { |
| 1139 | 1139 | add('Latest-app-without-download story', `release RPC desktop-gui smoke: opened ${desktop.latestAppWithoutDownload.name} from catalogue row via Browse at ${shortHyper(desktop.latestAppWithoutDownload.url)}, HTTP ${desktop.latestAppWithoutDownload.statusCode} ${desktop.latestAppWithoutDownload.bytes} bytes, no project page download or manual update`) |
| 1140 | 1140 | } |
| 1141 | 1141 | if (desktop?.featuredAppRegression) { |
| 1142 | | add('Existing featured app regression', `release RPC desktop-gui smoke: safe featured app ${desktop.featuredAppRegression.safeOpenedFeaturedApp.name} opened via Browse HTTP ${desktop.featuredAppRegression.safeOpenedFeaturedApp.statusCode}; standalone featured targets ${desktop.featuredAppRegression.standaloneTargets.map((app) => app.name).join(', ')} remain pear window targets with no trust approval automated`) |
| 1142 | add('Existing featured app regression', `release RPC desktop-gui smoke: safe featured app ${desktop.featuredAppRegression.safeOpenedFeaturedApp.name} opened via Browse HTTP ${desktop.featuredAppRegression.safeOpenedFeaturedApp.statusCode}; legacy native records ${desktop.featuredAppRegression.migrationRequired.map((app) => app.name).join(', ')} require verified packages and no code execution was automated`) |
| 1143 | 1143 | } |
| 1144 | 1144 | if (desktop?.nostrTrustedContact) { |
| 1145 | 1145 | add('Nostr trusted-contact story', `release RPC desktop-gui smoke: Nostr trust proof exposed ${desktop.nostrTrustedContact.visibleEvents} attested contact event via ${desktop.nostrTrustedContact.trustedVia} and quarantined ${desktop.nostrTrustedContact.hidden.quarantined} revoked or forged event(s)`) |
| … | … | @@ -1242,7 +1242,7 @@ function printHuman (result) { |
| 1242 | 1242 | console.log(` homepage: HTTP ${result.homepage.statusCode}, ${result.homepage.bytes} bytes${result.homepage.title ? `, "${result.homepage.title}"` : ''}`) |
| 1243 | 1243 | console.log(` catalogues: ${result.catalog.catalogs} loaded, ${result.catalog.apps} aggregated apps`) |
| 1244 | 1244 | console.log(` featured: ${result.catalog.featured.map((app) => app.name).join(', ')}`) |
| 1245 | | console.log(` Peercord: ${result.catalog.peercord.type}, ${result.catalog.peercord.runMode}, ${result.catalog.peercord.link}`) |
| 1245 | console.log(` Peercord: ${result.catalog.peercord.runMode}, ${result.catalog.peercord.legacyMigrationId}`) |
| 1246 | 1246 | if (result.localStories) { |
| 1247 | 1247 | console.log(` local search: ${result.localStories.search.results} result(s), doc ${result.localStories.search.docId}`) |
| 1248 | 1248 | console.log(` naming: ${result.localStories.naming.curated.name} curated + ${result.localStories.naming.petname.name} petname`) |