Repository navigation
Description
Problem
PR #343 / #328 correctly made the installed WebScene SDK recursively audit every final-bundle Mach-O against the requested architecture set before outer signing. The first exact Code OSS package audit exposed a pre-existing input that now fails that contract:
Contents/Resources/server/node_modules/kerberos/build/Release/kerberos.node
architectures: x86_64 arm64
requested package: arm64
The package runs the arm64 slice, but retains an unused x86_64 slice. The current WebScene package_macos.py audits before AppScene package-policy transforms, so downstream symbol stripping cannot make the final bundle single-architecture. The historical vscode-demo direct packager already has an atomic lipo -thin arm64 workaround; reusable SDK packaging must own this behavior.
Exact reproduction inputs:
- AppScene
f52fb46b2fc494b78520f7102ae960606ab618cb - WebScene
348ea440501c4059da6f95d1fbd6f6159a5df47bpackage, followed by Add recursive final-bundle Mach-O audit #343 audit behavior - Code OSS
645f29cc3176500b4b5762ba887cf2a7f0ffdf2c - package:
dist/appscene-release-348ea440-f52fb46b/Code OSS AppScene.app - all other 21 Mach-O images are arm64; zero forbidden WebKit/Electron/Chromium/CEF dependencies; deep signature and native module load checks pass
Proposed WebScene SDK fix
Before recursive audit and signing, normalize every regular final-bundle Mach-O to the explicitly requested single architecture:
- enumerate with the same safe inventory used by Add recursive final-bundle Mach-O audit #343;
- leave exact-architecture files byte/mtime stable;
- reject files without the requested slice;
- run
lipo -thininto a same-directory private temporary file; - validate Mach-O type, resulting exact architecture, deployment target, mode, ownership assumptions, and dependency/install-name/rpath closure;
- atomically replace the original;
- never follow or replace symlinks, escape the bundle, or leave partial/temp files;
- record original/result bytes and SHA-256 in bounded deterministic audit evidence;
- sign only after every transform and full recursive audit succeed.
The transform should activate only for an explicitly single-architecture package. Multi-architecture publication must retain and audit every requested slice.
Acceptance gates
- thin/universal/wrong-architecture/fat64 fixtures, native extensions, dylibs and executables;
- symlink, hardlink, case/Unicode collision, mutation, special-file, mode, read-only, interrupted-
lipo, malformed-output, and missing-slice negatives; - unchanged exact-architecture idempotence and stable mtimes;
- 10,000-entry time, FD, peak temporary disk, RSS, evidence-size, and cleanup bounds;
- real installed-SDK macOS consumer containing a universal
.node, followed by load/sign/audit; - exact Code OSS package passes Add recursive final-bundle Mach-O audit #343 recursive audit as arm64-only and
kerberosstill loads through packaged Node; - no Code OSS paths or product-specific allowlists in WebScene.
Activity
wieslawsoltes commentedon Sep 18, 2026
Implemented by #345 at
005da9a5b3b0b07a230d0ce8e1149af7d05af640, based on exact1cf8bc52a3d0215f8fac415847cfa4d7f2dbf533.Evidence before CI:
.node, hard links, safe symlinks and path/case/Unicode checks inherited from the common inventory, mutation, special files, read-only mode, stable mtime/idempotence, interrupted/malformed/growinglipooutput, and cleanup..node, packages to the running architecture, verifies schema-v2 hashes/bytes/actions, verifies the deep signature, loads and calls the thinned extension, and completes 10 deterministic recursive audits in 1.739 seconds with 2,564-byte evidence.The implementation is product-neutral and contains no Code OSS paths or dependency allowlists. Multi-architecture packages skip normalization and continue to require every requested slice in every Mach-O.
wieslawsoltes commentedon Sep 18, 2026
Merged #345 as
b29684224dd2a7bff8398b82821c2803de4d43f0.Final direct workflow 35322585811 passed all scoped gates:
.nodethin/sign/deep-verify/load/auditThe exact downstream Code OSS package and packaged
kerberosload remain the consumer acceptance step after the next SDK/package build.