Skip to content

Normalize universal Mach-O inputs before single-architecture package audit #344

Closed

Description

@wieslawsoltes

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 348ea440501c4059da6f95d1fbd6f6159a5df47b package, 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:

  1. enumerate with the same safe inventory used by Add recursive final-bundle Mach-O audit #343;
  2. leave exact-architecture files byte/mtime stable;
  3. reject files without the requested slice;
  4. run lipo -thin into a same-directory private temporary file;
  5. validate Mach-O type, resulting exact architecture, deployment target, mode, ownership assumptions, and dependency/install-name/rpath closure;
  6. atomically replace the original;
  7. never follow or replace symlinks, escape the bundle, or leave partial/temp files;
  8. record original/result bytes and SHA-256 in bounded deterministic audit evidence;
  9. 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 kerberos still loads through packaged Node;
  • no Code OSS paths or product-specific allowlists in WebScene.

Activity

  1. added
    bugSomething isn't working
    vscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration
    on Sep 18, 2026
  2. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Implemented by #345 at 005da9a5b3b0b07a230d0ce8e1149af7d05af640, based on exact 1cf8bc52a3d0215f8fac415847cfa4d7f2dbf533.

    Evidence before CI:

    • 21 portable adversarial contracts pass, covering FAT64 universal thinning, wrong/missing slices, native executable/dylib/.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/growing lipo output, and cleanup.
    • Exact 10,000-entry normalization gate passes under 15 seconds with bounded FD/RSS, peak temporary bytes, evidence below 64 KiB, and no temporary residue.
    • Real installed-SDK macOS consumer builds an arm64+x86_64 .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.
    • Python compile, JSON parse, and whitespace checks pass.

    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.

  3. wieslawsoltes commented on Sep 18, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Merged #345 as b29684224dd2a7bff8398b82821c2803de4d43f0.

    Final direct workflow 35322585811 passed all scoped gates:

    • portable source/schema — Linux
    • portable source/schema — Windows
    • installed SDK macOS consumer — real universal .node thin/sign/deep-verify/load/audit

    The exact downstream Code OSS package and packaged kerberos load remain the consumer acceptance step after the next SDK/package build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingvscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions