You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by "sunrioa (via GitHub)" <gi...@apache.org> on 2026/09/20 07:28:47 UTC

[PR] fix(release): restore the macOS icon at 16px and 32px [maka]

sunrioa opened a new pull request, #5529:
URL: https://github.com/apache/maka/pull/5529

   ## Summary
   
   The macOS `.icns` we ship stores its 16px and 32px faces as PNG in the legacy `icp4`/`icp5`/`icp6`
   slots, which macOS does not decode. Finder list rows, the Trash, Activity Monitor and the installer
   volume therefore show noise instead of the icon, while 128px and up stay correct. electron-builder
   introduced that in 26.15.2 and fixed it in 26.16.0; this bumps the pin to 26.16.1.
   
   The bytes come from an icons toolset electron-builder downloads at build time, so the version pin
   alone proves nothing about what was produced. `verifyPackagedMacApp` now reads the bundled icon and
   rejects the broken shape, so the next toolset regression fails the packaging check instead of
   shipping.
   
   Fixes #5528
   
   ## Verification
   
   ```
   node --test scripts/verify-packaged-app.test.mjs      # 25 pass, 0 fail
   node --test scripts/product-release.test.mjs          # 33 pass, 0 fail
   node --test scripts/ci-test-plan.test.mjs             # 40 pass, 0 fail
   node --test scripts/verify-packaged-app-icons.test.mjs #  4 pass, 0 fail
   biome lint / biome format on both changed scripts     # clean
   ```
   
   The new guard run against real artifacts, which is the check that fails without this change:
   
   ```
   FAIL  shipped 0.2.0-dev.43 icon (built with electron-builder 26.15.3)
         Maka icon stores PNG data in ICNS slots macOS does not render: 16x16 (icp4), 32x32 (icp5), 64x64 (icp6).
   PASS  same source PNG regenerated with the toolset 26.16.1 pins
   ```
   
   Running the two toolsets by hand on `apps/desktop/assets/app-icons/sky.png`:
   
   | icons toolset | small-size slots | output |
   | --- | --- | --- |
   | 1.1.0 (26.15.3) | `icp4`/`icp5`/`icp6` PNG | 159115 bytes, byte-identical to the shipped icon |
   | 1.2.3 (26.16.1) | `ic04`/`ic05` ARGB | 123793 bytes, renders correctly at 16px |
   
   I have not produced a signed DMG, so `verify:macos` end to end is unrun — it needs the release
   credentials. The icon assertion it gained is covered by the unit tests above and by the artifact run
   quoted above.
   
   ## Review focus
   
   The lockfile carries the electron-builder family plus its transitive drift. The one direction worth
   a look is `@noble/hashes` 2.2.0 → 1.8.0, which is not a downgrade we chose: app-builder-lib 26.16.1
   declares `^1.8.0` where 26.15.3 declared `^2.2.0`. Every new `resolved` URL stays on
   `registry.npmjs.org`, and the lockfile was regenerated with the pinned npm 11.19.0.
   
   ## AI use
   
   - [ ] No generative tool made a substantive contribution
   - [x] Generative tooling made a substantive contribution
   
   Tool(s) and scope: Claude Code diagnosed the ICNS slot layout, located the upstream regression and
   its fix, and drafted the verifier guard, its tests and this description. I reproduced both toolsets
   against the shipped artifacts, reviewed the diff and the lockfile, and am submitting it as my own.
   
   ## Checklist
   
   - [x] Tests cover the change and fail without it
   - [x] Lint, format, typecheck and the affected suites pass locally
   
   Does this PR entail a change in behavior?
   
   - [x] Yes — described under Summary above
   - [ ] No
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


Re: [PR] fix(release): restore the macOS icon at 16px and 32px [maka]

Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han commented on PR #5529:
URL: https://github.com/apache/maka/pull/5529#issuecomment-5863316330

   Thanks @sunrioa for tracking this down to the icon toolset and for the thorough verification, including the unsigned macOS packaging run. Merging.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


Re: [PR] fix(release): restore the macOS icon at 16px and 32px [maka]

Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han commented on code in PR #5529:
URL: https://github.com/apache/maka/pull/5529#discussion_r4114666429


##########
scripts/verify-macos-dmg.mjs:
##########
@@ -121,6 +121,67 @@ function assertSingleArchitecture(output, subject, expectedArch) {
   }
 }
 
+/**
+ * macOS draws the 16px and 32px faces of an ICNS from the ARGB slots `ic04`
+ * and `ic05`. PNG data packed into the legacy `icp4`/`icp5`/`icp6` slots is
+ * not decoded, so it renders as noise — which is what a Finder list row, the
+ * Dock's Trash, Activity Monitor and the DMG's own volume icon show. Every
+ * larger size keeps working, so nothing else in this verifier notices.
+ *
+ * electron-builder shipped that exact shape from 26.15.2 through 26.15.3
+ * (electron-userland/electron-builder#9940). The icon is generated by a
+ * toolset the builder downloads at build time, so the bundle is the only
+ * place the result can be seen: assert on it here rather than on a version
+ * pin that says nothing about what was produced.
+ */
+const UNRENDERABLE_ICNS_SLOTS = new Map([
+  ['icp4', '16x16'],
+  ['icp5', '32x32'],
+  ['icp6', '64x64'],
+]);
+const RENDERED_ICNS_SLOTS = new Map([
+  ['ic04', '16x16'],
+  ['ic05', '32x32'],
+]);
+const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
+
+function readIcnsSlots(icns) {
+  if (icns.length < 8 || icns.subarray(0, 4).toString('latin1') !== 'icns') {
+    throw new Error('Maka icon is not an ICNS archive.');
+  }
+  const slots = new Map();
+  // Every entry declares its own length including the 8-byte header, so a zero
+  // or truncated length is the difference between a parse error and a loop.
+  for (let offset = 8; offset + 8 <= icns.length; ) {
+    const type = icns.subarray(offset, offset + 4).toString('latin1');
+    const length = icns.readUInt32BE(offset + 4);
+    if (length < 8 || offset + length > icns.length) {
+      throw new Error(`Maka icon entry ${type} declares an unusable length of ${length}.`);
+    }
+    slots.set(type, icns.subarray(offset + 8, offset + length));
+    offset += length;
+  }
+  return slots;
+}
+
+export async function assertRenderableAppIcon(resourcesPath, { readIcon = readFile } = {}) {
+  const slots = readIcnsSlots(await readIcon(join(resourcesPath, 'icon.icns')));
+  const unrenderable = [...UNRENDERABLE_ICNS_SLOTS]
+    .filter(([type]) => slots.get(type)?.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE))
+    .map(([type, size]) => `${size} (${type})`);
+  if (unrenderable.length > 0) {
+    throw new Error(
+      `Maka icon stores PNG data in ICNS slots macOS does not render: ${unrenderable.join(', ')}.`,
+    );
+  }
+  const missing = [...RENDERED_ICNS_SLOTS]
+    .filter(([type]) => !slots.has(type))

Review Comment:
   **P2** — The gate only checks that `ic04`/`ic05` exist, not that their payloads are decodable. `readIcnsSlots` validates each entry's local length but ignores the top-level ICNS length, and here the required slots are checked with `slots.has(type)`. Calling the verifier at this head accepts an empty payload, a one-byte payload, and a file whose top-level size says 8 but is followed by entries. So if the toolset regresses to producing broken or truncated small icons, `verifyPackagedMacApp()` still passes, which undercuts the goal of checking the artifact rather than trusting the version. Suggest validating the top-level length and full entry consumption, and decoding the 16 px / 32 px entries with `iconutil` or `sips` in the macOS gate; the positive test at `verify-packaged-app.test.mjs:260-264` should use a real decodable fixture, plus a corrupt-payload negative case. Checking each PNG slot's dimensions would also catch wrong-size art in `ic13`/`ic14`.



##########
apps/desktop/package.json:
##########
@@ -89,7 +89,7 @@
     "@xterm/addon-fit": "^0.11.0",
     "@xterm/xterm": "^6.0.0",
     "electron": "43.4.1",
-    "electron-builder": "26.15.3",
+    "electron-builder": "26.16.1",

Review Comment:
   **P2** — In 26.16.1 the macOS auto-update ZIP is built with 7za (`-snl`) instead of the system `zip -y`: `archive.js:159-174` now sets `use7z = true` except for NFD paths, and `ArchiveTarget` preserves symlinks via `shouldPreserveSymlinks`. In 26.15.3 (`archive.js:120`) macOS ZIPs went through system `zip`, so Maka's patch (7za flags) did not touch them; now it does. If 7za handles the `Versions/Current` symlinks, executable bits or timestamps in Electron Framework differently, Squirrel.Mac / MacUpdater will fail `codesign --verify --deep --strict` after extraction and auto-update breaks. The only check that would catch this, `verify:macos-autoupdate` (`release.yml:220`), runs only in the real release pipeline, and the PR notes `verify:macos` is unrun. Please run macOS packaging with both verifiers on the signing runner before merging. (The first delta update from a `zip`-built to a `7za`-built archive will also mostly miss the blockmap and download close to the full size; that 
 affects bandwidth only.)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


Re: [PR] fix(release): restore the macOS icon at 16px and 32px [maka]

Posted by "hqhq1025 (via GitHub)" <gi...@apache.org>.
hqhq1025 commented on code in PR #5529:
URL: https://github.com/apache/maka/pull/5529#discussion_r4115485387


##########
scripts/verify-macos-dmg.mjs:
##########
@@ -121,6 +121,141 @@ function assertSingleArchitecture(output, subject, expectedArch) {
   }
 }
 
+/**
+ * macOS draws the 16px and 32px faces of an ICNS from the ARGB slots `ic04`
+ * and `ic05`. PNG data packed into the legacy `icp4`/`icp5`/`icp6` slots is
+ * not decoded, so it renders as noise — which is what a Finder list row, the
+ * Dock's Trash, Activity Monitor and the DMG's own volume icon show. Every
+ * larger size keeps working, so nothing else in this verifier notices.
+ *
+ * electron-builder shipped that exact shape from 26.15.2 through 26.15.3
+ * (electron-userland/electron-builder#9940). The icon is generated by a
+ * toolset the builder downloads at build time, so the bundle is the only
+ * place the result can be seen: assert on it here rather than on a version
+ * pin that says nothing about what was produced.
+ */
+const UNRENDERABLE_ICNS_SLOTS = new Map([
+  ['icp4', '16x16'],
+  ['icp5', '32x32'],
+  ['icp6', '64x64'],
+]);
+// Side length of each slot's art. `iconutil` and the builder's toolset both
+// write `ic04`/`ic05` as ARGB planes and every larger size as PNG. The toolset
+// 26.15.3 pinned also put 512px and 1024px art in `ic13`/`ic14`.
+const ARGB_ICNS_SLOTS = new Map([
+  ['ic04', 16],
+  ['ic05', 32],
+]);
+const PNG_ICNS_SLOTS = new Map([
+  ['ic07', 128],
+  ['ic08', 256],
+  ['ic09', 512],
+  ['ic10', 1024],
+  ['ic11', 32],
+  ['ic12', 64],
+  ['ic13', 256],
+  ['ic14', 512],
+]);
+const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
+
+function readIcnsSlots(icns) {
+  if (icns.length < 8 || icns.subarray(0, 4).toString('latin1') !== 'icns') {
+    throw new Error('Maka icon is not an ICNS archive.');
+  }
+  // A header that disagrees with the file is a truncated or padded archive,
+  // and its entries cannot be trusted to end where they claim.
+  const declared = icns.readUInt32BE(4);
+  if (declared !== icns.length) {
+    throw new Error(`Maka icon declares ${declared} bytes but holds ${icns.length}.`);
+  }
+  const slots = new Map();
+  // Every entry declares its own length including the 8-byte header, so a zero
+  // or truncated length is the difference between a parse error and a loop.
+  // The entries must account for every byte after the header.
+  for (let offset = 8; offset < icns.length; ) {
+    if (offset + 8 > icns.length) {
+      throw new Error(`Maka icon ends inside an entry header at byte ${offset}.`);
+    }
+    const type = icns.subarray(offset, offset + 4).toString('latin1');
+    const length = icns.readUInt32BE(offset + 4);
+    if (length < 8 || offset + length > icns.length) {
+      throw new Error(`Maka icon entry ${type} declares an unusable length of ${length}.`);
+    }
+    slots.set(type, icns.subarray(offset + 8, offset + length));
+    offset += length;
+  }
+  return slots;
+}
+
+/**
+ * An `ic04`/`ic05` payload is `ARGB` followed by the alpha, red, green and
+ * blue planes, packed the ICNS way: a control byte below 0x80 copies the next
+ * `control + 1` bytes, and one from 0x80 up repeats the next byte
+ * `control - 0x80 + 3` times. macOS can draw it only if it unpacks to exactly
+ * four `side` × `side` planes with no bytes left over.
+ */
+function isDecodableArgb(payload, side) {
+  if (payload.subarray(0, 4).toString('latin1') !== 'ARGB') return false;
+  const expected = 4 * side * side;
+  let produced = 0;
+  for (let offset = 4; offset < payload.length; ) {
+    const control = payload[offset];
+    const literal = control < 0x80;
+    const count = literal ? control + 1 : control - 0x80 + 3;
+    const consumed = 1 + (literal ? count : 1);
+    if (offset + consumed > payload.length) return false;
+    produced += count;
+    offset += consumed;
+  }
+  return produced === expected;

Review Comment:
   **P2 — Validate each ARGB plane, not just the combined byte count.** An ICNS `ic04`/`ic05` contains four independently decoded `side × side` planes, but this loop only compares their *total*. I fed `assertRenderableAppIcon()` a well-framed ICNS whose `ic04` RLE tokens expand to 260/252/256/256 bytes for the four 16px planes (1024 total), alongside a valid `ic05`; it returned successfully. The first plane overruns its 256-byte boundary while the second is short, so the gate still accepts malformed small-icon art. Check the expansion boundary after each plane (or decode with the native macOS icon tooling), and add an overfull/short-plane negative test. Separately, the `ic07` test fixture is only a PNG signature and IHDR, without IDAT/IEND or valid chunk CRC, yet the gate accepts it; this test cannot establish that larger PNG art is decodable.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


Re: [PR] fix(release): restore the macOS icon at 16px and 32px [maka]

Posted by "sunrioa (via GitHub)" <gi...@apache.org>.
sunrioa commented on code in PR #5529:
URL: https://github.com/apache/maka/pull/5529#discussion_r4115884718


##########
apps/desktop/package.json:
##########
@@ -89,7 +89,7 @@
     "@xterm/addon-fit": "^0.11.0",
     "@xterm/xterm": "^6.0.0",
     "electron": "43.4.1",
-    "electron-builder": "26.15.3",
+    "electron-builder": "26.16.1",

Review Comment:
   Fixed in `801af6465`: macOS ZIPs are built with the system `zip` again, as in 26.15.3, so the auto-update archive is byte-identical to before and keeps its timestamps. Windows ZIPs still go through 7za, and the Release Windows check passes.
   
   Without signing credentials, I packaged the arm64 app (ad-hoc signed, not notarized) locally and on a `macos-15` runner, unpacked the update ZIP with `ditto`, and ran `codesign --verify --deep --strict` and `verifyMacosDmg`. Everything passed apart from `spctl` and `stapler`, which I skipped because they need a Developer ID signature and a notarization ticket. Developer ID signing, notarization and `verify:macos-autoupdate` still need a maintainer to run.
   



##########
scripts/verify-macos-dmg.mjs:
##########
@@ -121,6 +121,67 @@ function assertSingleArchitecture(output, subject, expectedArch) {
   }
 }
 
+/**
+ * macOS draws the 16px and 32px faces of an ICNS from the ARGB slots `ic04`
+ * and `ic05`. PNG data packed into the legacy `icp4`/`icp5`/`icp6` slots is
+ * not decoded, so it renders as noise — which is what a Finder list row, the
+ * Dock's Trash, Activity Monitor and the DMG's own volume icon show. Every
+ * larger size keeps working, so nothing else in this verifier notices.
+ *
+ * electron-builder shipped that exact shape from 26.15.2 through 26.15.3
+ * (electron-userland/electron-builder#9940). The icon is generated by a
+ * toolset the builder downloads at build time, so the bundle is the only
+ * place the result can be seen: assert on it here rather than on a version
+ * pin that says nothing about what was produced.
+ */
+const UNRENDERABLE_ICNS_SLOTS = new Map([
+  ['icp4', '16x16'],
+  ['icp5', '32x32'],
+  ['icp6', '64x64'],
+]);
+const RENDERED_ICNS_SLOTS = new Map([
+  ['ic04', '16x16'],
+  ['ic05', '32x32'],
+]);
+const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
+
+function readIcnsSlots(icns) {
+  if (icns.length < 8 || icns.subarray(0, 4).toString('latin1') !== 'icns') {
+    throw new Error('Maka icon is not an ICNS archive.');
+  }
+  const slots = new Map();
+  // Every entry declares its own length including the 8-byte header, so a zero
+  // or truncated length is the difference between a parse error and a loop.
+  for (let offset = 8; offset + 8 <= icns.length; ) {
+    const type = icns.subarray(offset, offset + 4).toString('latin1');
+    const length = icns.readUInt32BE(offset + 4);
+    if (length < 8 || offset + length > icns.length) {
+      throw new Error(`Maka icon entry ${type} declares an unusable length of ${length}.`);
+    }
+    slots.set(type, icns.subarray(offset + 8, offset + length));
+    offset += length;
+  }
+  return slots;
+}
+
+export async function assertRenderableAppIcon(resourcesPath, { readIcon = readFile } = {}) {
+  const slots = readIcnsSlots(await readIcon(join(resourcesPath, 'icon.icns')));
+  const unrenderable = [...UNRENDERABLE_ICNS_SLOTS]
+    .filter(([type]) => slots.get(type)?.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE))
+    .map(([type, size]) => `${size} (${type})`);
+  if (unrenderable.length > 0) {
+    throw new Error(
+      `Maka icon stores PNG data in ICNS slots macOS does not render: ${unrenderable.join(', ')}.`,
+    );
+  }
+  const missing = [...RENDERED_ICNS_SLOTS]
+    .filter(([type]) => !slots.has(type))

Review Comment:
   Fixed in `9933280a6` and `10fc393f7`, and tightened in `b82ad9f36`: the gate now requires `ic04`/`ic05` to unpack plane by plane to exactly four full planes, PNG slots to decode at the size their slot expects, and the archive header and entries to cover the whole file.
   
   The tests now use real ARGB and PNG data instead of `ARGBfixture`, with your empty, one-byte and understated-header cases as negatives, and each of 27 mutations of the gate fails a test. On real icons, those from the 26.16.1 toolset and `iconutil` pass, and the shipped 26.15.3 icon is rejected.
   



##########
scripts/verify-macos-dmg.mjs:
##########
@@ -121,6 +121,141 @@ function assertSingleArchitecture(output, subject, expectedArch) {
   }
 }
 
+/**
+ * macOS draws the 16px and 32px faces of an ICNS from the ARGB slots `ic04`
+ * and `ic05`. PNG data packed into the legacy `icp4`/`icp5`/`icp6` slots is
+ * not decoded, so it renders as noise — which is what a Finder list row, the
+ * Dock's Trash, Activity Monitor and the DMG's own volume icon show. Every
+ * larger size keeps working, so nothing else in this verifier notices.
+ *
+ * electron-builder shipped that exact shape from 26.15.2 through 26.15.3
+ * (electron-userland/electron-builder#9940). The icon is generated by a
+ * toolset the builder downloads at build time, so the bundle is the only
+ * place the result can be seen: assert on it here rather than on a version
+ * pin that says nothing about what was produced.
+ */
+const UNRENDERABLE_ICNS_SLOTS = new Map([
+  ['icp4', '16x16'],
+  ['icp5', '32x32'],
+  ['icp6', '64x64'],
+]);
+// Side length of each slot's art. `iconutil` and the builder's toolset both
+// write `ic04`/`ic05` as ARGB planes and every larger size as PNG. The toolset
+// 26.15.3 pinned also put 512px and 1024px art in `ic13`/`ic14`.
+const ARGB_ICNS_SLOTS = new Map([
+  ['ic04', 16],
+  ['ic05', 32],
+]);
+const PNG_ICNS_SLOTS = new Map([
+  ['ic07', 128],
+  ['ic08', 256],
+  ['ic09', 512],
+  ['ic10', 1024],
+  ['ic11', 32],
+  ['ic12', 64],
+  ['ic13', 256],
+  ['ic14', 512],
+]);
+const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
+
+function readIcnsSlots(icns) {
+  if (icns.length < 8 || icns.subarray(0, 4).toString('latin1') !== 'icns') {
+    throw new Error('Maka icon is not an ICNS archive.');
+  }
+  // A header that disagrees with the file is a truncated or padded archive,
+  // and its entries cannot be trusted to end where they claim.
+  const declared = icns.readUInt32BE(4);
+  if (declared !== icns.length) {
+    throw new Error(`Maka icon declares ${declared} bytes but holds ${icns.length}.`);
+  }
+  const slots = new Map();
+  // Every entry declares its own length including the 8-byte header, so a zero
+  // or truncated length is the difference between a parse error and a loop.
+  // The entries must account for every byte after the header.
+  for (let offset = 8; offset < icns.length; ) {
+    if (offset + 8 > icns.length) {
+      throw new Error(`Maka icon ends inside an entry header at byte ${offset}.`);
+    }
+    const type = icns.subarray(offset, offset + 4).toString('latin1');
+    const length = icns.readUInt32BE(offset + 4);
+    if (length < 8 || offset + length > icns.length) {
+      throw new Error(`Maka icon entry ${type} declares an unusable length of ${length}.`);
+    }
+    slots.set(type, icns.subarray(offset + 8, offset + length));
+    offset += length;
+  }
+  return slots;
+}
+
+/**
+ * An `ic04`/`ic05` payload is `ARGB` followed by the alpha, red, green and
+ * blue planes, packed the ICNS way: a control byte below 0x80 copies the next
+ * `control + 1` bytes, and one from 0x80 up repeats the next byte
+ * `control - 0x80 + 3` times. macOS can draw it only if it unpacks to exactly
+ * four `side` × `side` planes with no bytes left over.
+ */
+function isDecodableArgb(payload, side) {
+  if (payload.subarray(0, 4).toString('latin1') !== 'ARGB') return false;
+  const expected = 4 * side * side;
+  let produced = 0;
+  for (let offset = 4; offset < payload.length; ) {
+    const control = payload[offset];
+    const literal = control < 0x80;
+    const count = literal ? control + 1 : control - 0x80 + 3;
+    const consumed = 1 + (literal ? count : 1);
+    if (offset + consumed > payload.length) return false;
+    produced += count;
+    offset += consumed;
+  }
+  return produced === expected;

Review Comment:
   Fixed in `b82ad9f36`: the gate now rejects a token that runs past its plane, and requires PNG slots to decode: CRCs through IEND, and IDAT that inflates to one filter byte and one scanline per row.
   
   I reproduced your 260/252/256/256 payload with `iconutil`, which draws it with the blue plane all zero, so macOS does unpack each plane on its own; the gate now rejects it. The fixtures are real PNGs, a signature-plus-IHDR PNG is now a negative case, and each of 27 mutations of the gate fails a test. The icons from the 26.16.1 toolset and `iconutil` still pass, and the macOS-only ZIP test passed on a `macos-15` runner.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


Re: [PR] fix(release): restore the macOS icon at 16px and 32px [maka]

Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han merged PR #5529:
URL: https://github.com/apache/maka/pull/5529


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org