ReviewOS

also looking at this

craft-native/craft

feat: add Linux and Windows named-window routing

#325
Merged glennmichael123 wants to merge codex/multi-window-linux-windows into main
29 files +2250 -200

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

scripts/release-workflow.test.tsmodified+14-0
Changes to scripts/release-workflow.test.ts
@@ -65,6 +65,20 @@ test('npm publication follows artifact validation, and macOS downloads run on bo
6565 expect(steps(release.jobs['attach-release-sbom'])).toContain('cmp "sbom/$document" "$VERIFY_DIR/$document"')
6666})
6767
68test('Windows release stages the pinned WebView2 loader before scanning and publishing', () => {
69 const native = release.jobs.pantry.steps!
70 const staged = native.findIndex(step => step.name === 'Stage Windows WebView2 loader')
71 const scan = native.findIndex(step => step.name === 'Scan binaries prepared for publication')
72 const publish = native.findIndex(step => step.name === 'Publish & Release')
73 expect(staged).toBeGreaterThan(native.findIndex(step => step.name === 'Cross-compile additional targets (Linux)'))
74 expect(scan).toBeGreaterThan(staged)
75 expect(publish).toBeGreaterThan(scan)
76 const command = native[staged]?.run ?? ''
77 expect(command).toContain('1.0.4191.47')
78 expect(command).toContain('f492bbf547d0da329553b6727435b677579b1e9f91cc9e4a1ad029366d5f23d0')
79 expect(command).toContain('zig-out/cross/windows-x64/WebView2Loader.dll')
80})
81
6882test('a registry network failure remains a visible best-effort warning', () => {
6983 const command = steps(release.jobs['notify-registry'])
7084 expect(command).not.toBe('')
scripts/scan-release-artifacts.test.tsmodified+8-1
Changes to scripts/scan-release-artifacts.test.ts
@@ -70,13 +70,20 @@ test('native inventory binds exact binaries and Zig runtime version', () => {
7070 const root = fixture()
7171 binary(root, 'bin/craft', '7f454c46')
7272 binary(root, 'cross/windows-x64/craft.exe', '4d5a')
73 binary(root, 'cross/windows-x64/WebView2Loader.dll', '4d5a')
7374 const inventory = nativeInventory(root, 'linux', '1.2.3', '0.17.0-dev.1963')
74 expect(inventory.components.map(component => component.name)).toEqual(['craft-linux-x64', 'craft-windows-x64', 'zig-std'])
75 expect(inventory.components.map(component => component.name)).toEqual(['craft-linux-x64', 'craft-windows-x64', 'WebView2Loader', 'zig-std'])
7576 expect(inventory.components[0]?.hashes).toEqual([{ alg: 'SHA-256', content: createHash('sha256').update(readFileSync(join(root, 'bin/craft'))).digest('hex') }])
77 expect(inventory.components[2]?.version).toBe('1.0.4191.47')
78 expect(inventory.components[2]?.type).toBe('library')
79 expect(inventory.dependencies).toContainEqual({ ref: 'urn:craft:binary:craft-windows-x64', dependsOn: ['urn:craft:zig-std', 'urn:craft:binary:WebView2Loader'] })
7680 writeFileSync(join(root, 'cross/windows-x64/craft.exe'), 'not a binary')
7781 expect(() => nativeInventory(root, 'linux', '1.2.3', '0.17.0-dev.1963')).toThrow('missing or empty')
7882 binary(root, 'cross/windows-x64/craft.exe', '7f454c46')
7983 expect(() => nativeInventory(root, 'linux', '1.2.3', '0.17.0-dev.1963')).toThrow('unexpected executable format')
84 binary(root, 'cross/windows-x64/craft.exe', '4d5a')
85 writeFileSync(join(root, 'cross/windows-x64/WebView2Loader.dll'), 'not a binary')
86 expect(() => nativeInventory(root, 'linux', '1.2.3', '0.17.0-dev.1963')).toThrow('WebView2Loader: missing or empty')
8087})
8188
8289test('publisher uses only hash-verified archives and skips an existing version', () => {
scripts/scan-release-artifacts.tsmodified+16-9
Changes to scripts/scan-release-artifacts.ts
@@ -7,6 +7,7 @@ import { enforceScanPolicy, scanSbom } from './scan-sbom'
77type Archive = { name: string, version: string, file: string, sha256: string }
88type Component = { name: string, version?: string, 'bom-ref'?: string, [key: string]: unknown }
99type Inventory = { bomFormat: string, components: Component[], [key: string]: unknown }
10type NativeArtifact = { path: string, name: string, magic: string[], type: 'application' | 'library', version?: string }
1011
1112const root = resolve(import.meta.dir, '..')
1213const sha256 = (path: string) => createHash('sha256').update(readFileSync(path)).digest('hex')
@@ -108,18 +109,21 @@ function scanNpm(directory: string, output: string, syft: string, grype: string)
108109 finally { rmSync(consumer, { recursive: true, force: true }) }
109110}
110111
112function nativeArtifacts(platform: 'macos' | 'linux'): NativeArtifact[] {
113 return platform === 'macos'
114 ? [{ path: 'bin/craft', name: 'craft-darwin-arm64', magic: ['cffaedfe', 'feedfacf'], type: 'application' }, { path: 'cross/darwin-x64/craft', name: 'craft-darwin-x64', magic: ['cffaedfe', 'feedfacf'], type: 'application' }]
115 : [{ path: 'bin/craft', name: 'craft-linux-x64', magic: ['7f454c46'], type: 'application' }, { path: 'cross/windows-x64/craft.exe', name: 'craft-windows-x64', magic: ['4d5a'], type: 'application' }, { path: 'cross/windows-x64/WebView2Loader.dll', name: 'WebView2Loader', magic: ['4d5a'], type: 'library', version: '1.0.4191.47' }]
116}
117
111118export function nativeInventory(binaryRoot: string, platform: 'macos' | 'linux', version: string, zigVersion: string, discovered: Component[][] = []): Inventory {
112 const entries = platform === 'macos'
113 ? [{ path: 'bin/craft', name: 'craft-darwin-arm64', magic: ['cffaedfe', 'feedfacf'] }, { path: 'cross/darwin-x64/craft', name: 'craft-darwin-x64', magic: ['cffaedfe', 'feedfacf'] }]
114 : [{ path: 'bin/craft', name: 'craft-linux-x64', magic: ['7f454c46'] }, { path: 'cross/windows-x64/craft.exe', name: 'craft-windows-x64', magic: ['4d5a'] }]
115 const binaries: Component[] = entries.map(({ path, name, magic }) => {
119 const artifacts: Component[] = nativeArtifacts(platform).map(({ path, name, magic, type, version: artifactVersion }) => {
116120 const absolute = join(binaryRoot, path)
117121 if (!existsSync(absolute) || !statSync(absolute).isFile() || statSync(absolute).size < 1024)
118122 throw new Error(`${name}: missing or empty release binary`)
119123 const bytes = readFileSync(absolute)
120124 if (!magic.some(prefix => bytes.subarray(0, prefix.length / 2).toString('hex') === prefix))
121125 throw new Error(`${name}: unexpected executable format`)
122 return { 'bom-ref': `urn:craft:binary:${name}`, type: 'application', name, version,
126 return { 'bom-ref': `urn:craft:binary:${name}`, type, name, version: artifactVersion ?? version,
123127 hashes: [{ alg: 'SHA-256', content: createHash('sha256').update(bytes).digest('hex') }],
124128 properties: [{ name: 'craft:artifact-path', value: path }],
125129 }
@@ -128,8 +132,11 @@ export function nativeInventory(binaryRoot: string, platform: 'macos' | 'linux',
128132 return {
129133 bomFormat: 'CycloneDX', specVersion: '1.6', version: 1,
130134 metadata: { component: { type: 'application', name: 'craft-native-release', version } },
131 components: [...binaries, zig, ...discovered.flat()],
132 dependencies: binaries.map(binary => ({ ref: binary['bom-ref'], dependsOn: [zig['bom-ref']] })),
135 components: [...artifacts, zig, ...discovered.flat()],
136 dependencies: artifacts.filter(artifact => artifact.type === 'application').map(artifact => ({
137 ref: artifact['bom-ref'],
138 dependsOn: artifact.name === 'craft-windows-x64' ? [zig['bom-ref'], 'urn:craft:binary:WebView2Loader'] : [zig['bom-ref']],
139 })),
133140 }
134141}
135142
@@ -137,7 +144,7 @@ function scanNative(binaryRoot: string, platform: 'macos' | 'linux', output: str
137144 mkdirSync(output, { recursive: true })
138145 const { version } = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as { version: string }
139146 const zigVersion = Bun.JSONC.parse(readFileSync(join(root, 'pantry.jsonc'), 'utf8')).dependencies['ziglang.org'] as string
140 const paths = platform === 'macos' ? ['bin/craft', 'cross/darwin-x64/craft'] : ['bin/craft', 'cross/windows-x64/craft.exe']
147 const paths = nativeArtifacts(platform).map(artifact => artifact.path)
141148 const discovered = paths.map((path, index) => {
142149 const report = join(output, `native-${index}.cyclonedx.json`)
143150 run([syft, join(binaryRoot, path), '-o', `cyclonedx-json=${report}`])
@@ -152,7 +159,7 @@ function scanNative(binaryRoot: string, platform: 'macos' | 'linux', output: str
152159 const summary = scanSbom(sbom, join(output, 'grype'), grype)
153160 enforceScanPolicy(summary.counts, true)
154161 const after = nativeInventory(binaryRoot, platform, version, zigVersion)
155 for (const [index, binary] of after.components.slice(0, 2).entries()) {
162 for (const [index, binary] of after.components.slice(0, paths.length).entries()) {
156163 if (JSON.stringify(binary.hashes) !== JSON.stringify(inventory.components[index]!.hashes))
157164 throw new Error(`${binary.name}: release binary changed after scanning`)
158165 }