|
8 | 8 | ALLOWED_ASAR_ROOTS, |
9 | 9 | ALLOWED_ASAR_OUT_ROOTS, |
10 | 10 | REQUIRED_MAC_BUNDLE_FILES, |
| 11 | + assertAsarEntryInventory, |
11 | 12 | assertAsarInventory, |
12 | 13 | verifyBundlePair, |
13 | 14 | verifyZipArtifact |
@@ -164,6 +165,52 @@ describe('macOS artifact integrity', () => { |
164 | 165 | ) |
165 | 166 | }) |
166 | 167 |
|
| 168 | + // Regression: @electron/asar's listPackage yields OS-separator paths — backslashes on |
| 169 | + // the Windows runner ("\node_modules") — so the POSIX allowlist rejected EVERY entry |
| 170 | + // and failed an otherwise-valid app.asar (the build-win release regression). The pure |
| 171 | + // entry check must normalize separators so an identical tree passes on either host, |
| 172 | + // WITHOUT weakening the forbidden-path checks. |
| 173 | + describe('assertAsarEntryInventory — cross-platform path separators', () => { |
| 174 | + const POSIX_TREE = [ |
| 175 | + '/package.json', |
| 176 | + '/out', |
| 177 | + '/out/main/index.js', |
| 178 | + '/out/preload/index.js', |
| 179 | + '/out/renderer/index.html', |
| 180 | + '/node_modules/electron/package.json' |
| 181 | + ] |
| 182 | + const toWindows = (entries: string[]): string[] => entries.map((e) => e.replace(/\//g, '\\')) |
| 183 | + |
| 184 | + it('accepts a valid runtime tree with POSIX separators', () => { |
| 185 | + expect(() => assertAsarEntryInventory(POSIX_TREE)).not.toThrow() |
| 186 | + }) |
| 187 | + |
| 188 | + it('accepts the SAME valid tree with Windows backslash separators', () => { |
| 189 | + expect(() => assertAsarEntryInventory(toWindows(POSIX_TREE))).not.toThrow() |
| 190 | + }) |
| 191 | + |
| 192 | + it('still rejects an unexpected root delivered with Windows separators', () => { |
| 193 | + expect(() => assertAsarEntryInventory(['\\marketing', '\\marketing\\list.csv'])).toThrow( |
| 194 | + 'app.asar contains unexpected application root' |
| 195 | + ) |
| 196 | + }) |
| 197 | + |
| 198 | + it('still rejects private state + build output with Windows separators', () => { |
| 199 | + expect(() => assertAsarEntryInventory(['\\out\\main\\.OFFGRID\\private.db'])).toThrow( |
| 200 | + 'forbidden private state' |
| 201 | + ) |
| 202 | + expect(() => |
| 203 | + assertAsarEntryInventory(['\\out\\packaged-helpers-stale\\package\\x.js']) |
| 204 | + ).toThrow('unexpected build output') |
| 205 | + }) |
| 206 | + |
| 207 | + it('still rejects a nested application bundle with Windows separators', () => { |
| 208 | + expect(() => |
| 209 | + assertAsarEntryInventory(['\\out\\main\\Nested.APP\\Contents\\Info.plist']) |
| 210 | + ).toThrow('nested application bundle') |
| 211 | + }) |
| 212 | + }) |
| 213 | + |
167 | 214 | it('enforces ASAR inventory on the real Windows artifact hook', async () => { |
168 | 215 | const root = fs.mkdtempSync(path.join(os.tmpdir(), 'offgrid-windows-artifact-')) |
169 | 216 | tempRoots.push(root) |
|
0 commit comments