#25

RFC: Bundle.toml as the primary, framework-independent distribution API

Open1byeopened 6d ago

Summary

Make Bundle.toml the primary user-facing distribution configuration, while retaining the existing Cargo metadata integration as a compatibility adapter. The same distribution engine should package Rake apps, ordinary Rust apps using other UI toolkits, and existing native executables.

This is an RFC for the complete current distribution API: configuration, CLI, planning, build integration, native components, resources, helpers, platform packaging, updates, release publication, extensions, and the Rust library. It does not propose replacing Rake's application/router/view APIs.

Status: design proposal, not implemented. All new fields, flags, functions, and defaults below require implementation and tests. Existing capabilities are identified separately. No end-to-end CEF bundle has been produced through the proposed path.

Motivation and goals

Packaging settings are easier to discover and review in a dedicated file than inside a large Cargo.toml. A project should normally run:

rake bundle
rake bundle --debug
rake bundle --plan --json

Rake should own mechanical distribution work: resolving declared inputs, collecting executables, staging native payloads, checking dependencies, signing, verification, archives/installers, and explicit release publication. Applications should declare their requirements and retain ownership of runtime behavior.

Silicon/CEF motivates several missing pieces: one main executable, a Chromium framework, and five macOS helper applications that share one Cargo binary but have distinct names and identities. It is an acceptance case for generic capabilities, not a reason to put a browser engine into Rake's runtime.

Goals:

  • One authoritative configuration per invocation, with predictable paths and useful diagnostics.
  • A small, readable starting file that can express the full existing configuration surface.
  • No dependency on Rake's UI runtime or GPUI for packaging another application.
  • Cargo and prebuilt inputs feeding the same validated model and worker pipeline.
  • Existing consumers and valid configuration preserved; no silent loss of settings during migration.
  • Reproducible native inputs and correct helper signing without an application-specific packaging script.

Non-goals for the first implementation: arbitrary build-command orchestration, a new plugin framework, config includes/inheritance, automatic adoption/re-signing of an already assembled .app, or automatic key creation/publication during bundling.

Current API and what should be reused

Source baseline: 5c818c4d5ee6721546663d7f7e5aac1710c9a6d0.

  • rake-dist-core::Config already owns the portable configuration and validates plans. Config::plan_for is independent of Cargo metadata and native packaging tools.
  • BundledDependency already lowers grouped dependencies into components, sidecars, resources, and runtime recipes.
  • rake-dist already exposes planning, native execution, artifact reports, publication, and extension adapters without a Rake UI dependency.
  • execution.rs already resolves native components before the Cargo build, owns staging/output transactions, and produces Distribution records with hashes and trust evidence. However, execution currently assumes Cargo metadata and one selected main binary.
  • rake-build already embeds build-time resource/update metadata. It currently reads Cargo package metadata directly; that must change for a first-class standalone file.
  • Existing framework recipes, locks, native loader checks, worker isolation, signing, release verification, and command/Rust extension contracts should be reused.

Coverage of the entire existing configuration

The standalone file should retain the existing names, nested fields, validation, and override semantics for all of these sections. This table is an API coverage map, not a replacement for the generated schema.

Current surfaceStandalone representation / intended treatment
schema_version, name, identifier, icon, assets, resourcesSame top-level keys; paths use the selected input root.
build_number, package_version, minimum_system_versionSame top-level keys and native-version/deployment rules. Cargo semantic version is obtained from Cargo; prebuilt version is explicit.
desktopPreserve category, URL schemes, file associations, and localized labels.
macosPreserve formats, privacy strings, universal settings, plist, entitlements, signing identity, and notary profile. Add helper-app declarations.
windows / windows.msixPreserve formats, manifest, system DLL declarations, certificate/timestamp references, MSIX publisher and manifest. Remove implicit UI assumptions from the generic path.
linux / linux.flatpakPreserve formats, package name, desktop/AppStream metadata, baseline, per-format dependencies, Flatpak runtime/SDK pins and permissions.
dependenciesSame prepared-tree convenience API, including executables, resources, licenses, and directory/framework/GStreamer library recipes.
componentsSame exact-target local or HTTPS/SHA-256 inputs, archive validation, and component locking.
sidecarsPreserve ordinary helper installation and descriptor lookup; add Cargo-bin input without changing the existing file-path form.
runtimesPreserve built-in/custom recipes, component references, selected plugins, link policy, system dependencies, and options.
target_overrides, format_overridesPreserve current layering and replacement/merge rules. Do not invent implicit deep merging.
updatesPreserve public update policy, provider keys, and installation-channel ownership. Runtime integration remains an explicit capability.
releasePreserve publishers, required target/format matrix, custom required artifacts, signing references/commands, Sparkle tools, GPG/repository settings, and feed validity.
custom_formats, component_recipesPreserve explicit argv/Rust contracts, independent verification, bounded execution, and trust rules.
webPreserve base_path, routing, and offline through an adapter to the existing Web pipeline; do not silently ignore them. This does not make native prebuilt programs Web inputs or extend the currently supported Web runtime.

Every currently valid field must either work with the standalone source or be rejected with a documented, specific unsupported-combination error. No parser may silently accept unknown fields, or ignore settings applicable to the selected source and target.

Proposed file model

Use the existing flat Config plus a separate input envelope:

  • Required schema_version = 1 in a standalone file.
  • Required standalone name, identifier, and [program].
  • [program] is a tagged choice: cargo or prebuilt.
  • Optional root selects the input root explicitly; it is not another configuration layer.
  • program and root are file/source-adapter fields, not a second copy of Config or an additional [app] identity section.
  • Keep strict unknown-key and source-specific validation. In particular, do not rely on unsupported combinations of Serde flatten and deny_unknown_fields; preserve useful field/file diagnostics.

Minimal Cargo example

# Bundle.toml
schema_version = 1
name = "My App"
identifier = "com.example.my-app"

[program]
type = "cargo"

manifest defaults to Cargo.toml at the selected root. A single-package, single-binary project requires no further Cargo selection. The application need not depend on Rake's UI.

Cargo workspace selection

schema_version = 1
name = "Silicon"
identifier = "dev.silicon.browser"
minimum_system_version = "13.0"

[program]
type = "cargo"
manifest = "Cargo.toml"
package = "browser"
bin = "silicon"
features = []

package and bin become required when selection is ambiguous. Error messages should list the available choices. One selected Cargo package per invocation is sufficient initially; the main binary and Cargo-built helpers share that package, target, profile, feature selection, and SDK bindings.

Version comes from the selected Cargo package. A competing program.version in Cargo mode is rejected. Existing native package_version and build_number overrides remain available.

Prebuilt executable example

schema_version = 1
name = "Native Viewer"
identifier = "com.example.native-viewer"

[program]
type = "prebuilt"
path = "build/{target}/native-viewer{exe}"
version = "1.0.0"
target = "aarch64-apple-darwin"

This means a loose executable plus explicitly declared payload, not an existing application bundle. It must work with neither cargo nor rustc on PATH. Require a target in the file or via --target-triple in the first version, and verify the actual binary architecture. Reject conflicting targets, Cargo-only settings, and unsupported universal combinations.

The prebuilt path must not inherit a GPUI Windows manifest, require a Rake application runtime, or claim to install a working updater without explicit integration support.

Proposed Silicon / CEF example

This is an illustrative macOS configuration for a prepared, versioned SDK tree. The preparation step must supply the declared CEF license and exact matching SDK metadata; these files are not assumed to appear automatically in an upstream archive.

# Bundle.toml at the repository root
schema_version = 1
name = "Silicon"
identifier = "dev.silicon.browser"
minimum_system_version = "13.0"

[program]
type = "cargo"
package = "browser"
bin = "silicon"

[program.build_env]
CEF_PATH = { component = "cef" }

[dependencies.cef]
path = "vendor/cef/156.0.14/{target}"
licenses = ["CEF-LICENSE.txt"]
resources = { "Chromium-CREDITS.html" = "CREDITS.html" }
libraries = { path = "Chromium Embedded Framework.framework", recipe = "framework" }

[macos]
formats = ["app", "zip", "dmg"]
entitlements = "crates/browser/entitlements.plist"

[[macos.helper_apps]]
name = "Silicon Helper"
identifier = "dev.silicon.browser.helper"
bin = "silicon-helper"
entitlements = "crates/browser/entitlements.plist"
info_plist = "packaging/Helper.plist"

[[macos.helper_apps]]
name = "Silicon Helper (GPU)"
identifier = "dev.silicon.browser.helper.gpu"
bin = "silicon-helper"
entitlements = "crates/browser/entitlements.plist"
info_plist = "packaging/Helper.plist"

[[macos.helper_apps]]
name = "Silicon Helper (Renderer)"
identifier = "dev.silicon.browser.helper.renderer"
bin = "silicon-helper"
entitlements = "crates/browser/entitlements.plist"
info_plist = "packaging/Helper.plist"

[[macos.helper_apps]]
name = "Silicon Helper (Plugin)"
identifier = "dev.silicon.browser.helper.plugin"
bin = "silicon-helper"
entitlements = "crates/browser/entitlements.plist"
info_plist = "packaging/Helper.plist"

[[macos.helper_apps]]
name = "Silicon Helper (Alerts)"
identifier = "dev.silicon.browser.helper.alerts"
bin = "silicon-helper"
entitlements = "crates/browser/entitlements.plist"
info_plist = "packaging/Helper.plist"

The framework is at the flattened SDK root consumed by the current CEF bindings, not an assumed Release/ subdirectory. The license is a license entry; Chromium credits remain a separately mapped app resource.

The same source binary is built once per distinct build input and copied into five wrappers. Each wrapper gets its declared identity, generated/validated plist, and explicit entitlement policy. info_plist is optional and can supply additional helper metadata such as activation behavior; it cannot silently override protected identity fields.

Helper input contract

  • bin = "worker" means a Cargo binary in the selected package.
  • path = "bin/worker" means an existing executable, optionally relative to a declared component.
  • Exactly one is permitted. Represent that choice as an enum in the validated Rust model.
  • Apply the same binary-input choice to ordinary sidecars, preserving existing path behavior.
  • A bin reference is invalid with a prebuilt main program in v1.
  • macos.helper_apps is separate from sidecars: helper apps live in Contents/Frameworks and have bundle identities, while ordinary sidecars retain their existing installed location and resources.helper() lookup.
  • Do not add helper-app fields to the existing installed descriptor without an independently versioned compatibility plan.
  • Do not add arbitrary location or per-helper Cargo project fields before there is a concrete requirement.

For example, an ordinary Cargo worker is still small:

[[sidecars]]
name = "indexer"
bin = "indexer"

Examples retaining the wider current API

These are independent fragments illustrating the existing configuration moved into the standalone file. They are not one universally valid application/release combination: native hosts, enrolled signing references, payloads, runtime integration, and format prerequisites still apply.

Resources, desktop integration, and platform settings

icon = "assets/icon.svg"
resources = [{ from = "assets/help.txt", to = "help.txt" }]
build_number = "12"

[desktop]
category = "developer_tool"
url_schemes = ["my-app"]
file_associations = [{ extensions = ["mynote"], name = "My Note", mime_type = "application/x-my-note" }]

[desktop.localizations.fr]
name = "Mes notes"
description = "Documents et notes"

[macos]
formats = ["app", "zip", "dmg"]
info_plist = "packaging/Info.plist"
entitlements = "packaging/app.entitlements"
# Existing local identity/profile references, never private credentials:
# signing_identity = "Developer ID Application: Example (TEAMID)"
# notary_profile = "existing-keychain-profile"

[macos.privacy]
NSCameraUsageDescription = "Capture an image for a document"

[windows]
formats = ["nsis", "msix"]
manifest = "packaging/app.manifest"
system_dlls = []

[windows.msix]
publisher = "CN=Publisher matching the signing certificate"

[linux]
package_name = "my-app"
formats = ["deb", "rpm", "appimage"]
desktop_entry = "packaging/my-app.desktop"
appstream = "packaging/my-app.metainfo.xml"

[linux.dependencies]
deb = ["libc6 (>= 2.39)"]
rpm = ["glibc >= 2.39"]

[linux.baseline]
name = "ubuntu-24.04"
glibc = "2.39"
kernel = "6.8"

[linux.flatpak]
runtime = "org.freedesktop.Platform"
sdk = "org.freedesktop.Sdk"
runtime_version = "25.08"
finish_args = ["--socket=wayland", "--socket=fallback-x11", "--share=ipc", "--device=dri"]

[web]
base_path = "/my-app/"
routing = "path"
offline = true

Grouped dependencies, explicit components, runtimes, and overrides

[dependencies.ffmpeg]
path = "vendor/ffmpeg/{target}"
executables = { ffmpeg = "bin/ffmpeg{exe}", ffprobe = "bin/ffprobe{exe}" }
licenses = ["LICENSE"]
resources = { "ffmpeg/presets" = "share/presets" }
libraries = { path = "lib" }

[[components]]
name = "media"
target = "aarch64-apple-darwin"
source = { type = "local", path = "vendor/media" }
licenses = ["LICENSE"]

[[runtimes]]
name = "media-runtime"
recipe = "directory"
component = "media"
source = "lib"

[target_overrides.x86_64-pc-windows-msvc]
formats = ["msi"]

[format_overrides.msi]
package_version = "1.2.301"

Keep existing HTTPS/SHA-256 component sources and supported archive types as well. The SDK binding proposed here initially targets stable local components; it does not pretend all existing remote runtime recipes automatically produce stable build SDK paths.

Updates and complete release/publication policy

[updates]
enabled = true
channel = "stable"
base_url = "https://downloads.example.com/my-app"

[updates.public_keys]
sparkle = "packaging/sparkle.pub"
velopack = "packaging/velopack.pub"
appimage = "packaging/appimage.pub"

[release]
feed_validity_seconds = 604800
sparkle_tool = "/path/to/Sparkle-2.10.1/bin/generate_appcast"
sparkle_account = "ed25519"
gpg_key = "0123456789ABCDEF0123456789ABCDEF01234567"

[release.publisher]
kind = "directory"
path = "release-site"
public_url = "https://downloads.example.com/my-app"

[release.required]
aarch64-apple-darwin = ["zip", "dmg"]
x86_64-pc-windows-msvc = ["msix", "velopack"]
x86_64-unknown-linux-gnu = ["deb", "rpm", "appimage"]

[release.signing_keys.appimage]
kind = "environment"
variable = "MY_APP_APPIMAGE_SEED"

[release.signing_keys.velopack]
kind = "keychain"
service = "com.example.my-app.updates"
account = "velopack"

[release.repositories]
x86_64-unknown-linux-gnu = ["deb", "rpm", "arch", "flatpak"]

Retain release.custom_required, external release.signers, file/environment/Keychain signing references, and directory/GitHub/HTTPS publishers. Existing trust, feed verification, repository preparation, all-target promotion, and failed-publication recovery semantics do not change.

A selected bundle file must also be available to release planning and promotion, rather than requiring duplicated Cargo packaging metadata:

rake release --config Bundle.toml --plan --json
rake release --config Bundle.toml --from mac-output --from windows-output --from linux-output

The new --config source selection is proposed; release, --from, and the existing publication responsibilities are not new. Merely reading a config or running bundle must never publish, generate keys, enroll credentials, or start update polling.

Existing extension contracts

[[custom_formats]]
name = "company-macos"
platform = "macos"
input_format = "app"
command = ["python3", "packaging/company.py", "package"]
verify_command = ["python3", "packaging/company.py", "verify"]

[component_recipes]
codec = ["python3", "packaging/codec.py"]

[[runtimes]]
name = "codec"
recipe = "codec"
source = "vendor/codec"
options = { plugins = "decoder" }

[release.custom_required]
aarch64-apple-darwin = ["company-macos"]

Keep the existing PackageBackend / ComponentRecipe Rust contracts and explicit JSON command protocol. Do not introduce another plugin system or treat a plugin's success response as native signing/verification evidence.

Configuration selection, paths, defaults, and locks

  1. An explicit --config <file> selects that file. Otherwise discover exactly ./Bundle.toml; do not walk ancestors looking for a nearer/different app. If neither applies, retain the existing Cargo metadata path.
  2. A selected file is authoritative. Do not merge its distribution settings with package.metadata.rake.bundle. Report selected and shadowed sources in the plan. An explicit legacy --manifest-path selects the metadata adapter instead of automatic file discovery.
  3. Source selectors cannot disagree: --config conflicts with --manifest-path, --package, and --bin. With an automatically discovered file, --package/--bin alone should be a conflict error, not a hidden switch of authority.
  4. Keep execution overrides for target, formats, output, trust, and component policy. --features is Cargo-only and augments declared Cargo features. --debug is Cargo-only; release is the default. Preserve current target/format override semantics.
  5. All declared input paths and the default dist/ output use the canonical input root. It defaults to the config directory. An optional root = ".." can select an ancestor explicitly; require the config to remain inside the selected root. Continue rejecting payload/archive traversal and symlink escapes. This deliberate root selection does not relax native-input confinement.
  6. For packaging/Bundle.toml, put root = ".." at the top level; paths such as Cargo.toml and assets/icon.svg then refer to the project root. The plan must print the effective root.
  7. Propose <config-stem>.lock next to a standalone file (Bundle.toml -> Bundle.lock). Legacy metadata retains rake-dist.lock. Expose the resolved lock path in the plan and worker request. Programmatic sources need an explicit lock origin/path instead of guessing from a missing config filename.
  8. Explicit CLI --output remains relative to the invocation directory; default output is root-relative. Tool, signing-store, and publisher references retain their explicitly allowed external-path rules and are not copied into payloads.
  9. Cargo version comes from Cargo. A prebuilt source requires explicit semantic version and target. Unsupported format/platform/updater combinations fail during planning.
  10. --plan does no builds, native packaging, signing, downloads, secret-store access, or publication. Cargo-mode metadata inspection may retain its existing locked/offline Cargo metadata call; prebuilt mode must not invoke Cargo/rustc at all.
  11. Emit a standalone-file JSON schema including program, root, all existing Config sections and proposed helper declarations. Retain configuration_schema() for the legacy Config contract; do not silently change that public function's meaning. Unknown keys must remain errors with useful source context.

For example, a config in a subdirectory can begin:

# packaging/Bundle.toml
schema_version = 1
root = ".."
name = "My App"
identifier = "com.example.my-app"

[program]
type = "cargo"

Build handoff: one source of truth, including build.rs

Standalone file parsing alone is insufficient. Today rake-build::build() reads CARGO_MANIFEST_DIR/Cargo.toml and may embed a different identity, resource directory, desktop metadata, or update policy than the packager selected.

Proposed contract:

  • Resolve the small build-relevant projection of the selected configuration in shared code, including package/version/target/format, public desktop/update bindings, resource naming, and applicable Windows build resources.
  • Write an immutable, content-addressed build-context snapshot under the Cargo target cache and pass its path as RAKE_BUILD_CONTEXT to Cargo.
  • rake-build tracks that environment key, verifies schema/package/version/content identity, and consumes the same resolved build settings. Identical build settings yield the same context path across runs.
  • Exclude private credentials, release.*, machine-specific publication paths, and unrelated signing settings. Editing a signing identity or release destination must not cause recompilation.
  • Embed/track public-key bytes and content hashes for relevant assets so a real resource change invalidates the build. Handle Flatpak's sandbox paths explicitly.
  • Keep SDK/toolchain environment bindings separate and scoped to child builds; never mutate global process environment.
  • Support an explicit proposed rake_build::build_from("Bundle.toml") for direct cargo build, with its selector resolved relative to CARGO_MANIFEST_DIR (for example, ../../Bundle.toml in a nested crate). Declared payload paths still use the selected bundle root. A supplied build context takes precedence; legacy metadata remains the fallback. Do not add hidden upward config discovery inside build scripts.
  • A non-Rake UI application may have no build hook at all. Basic packaging must still work. Features that need embedded policy/resources must require a verifiable integration acknowledgement and fail early if absent; do not claim updater support merely because a dependency exists.
  • Preserve worker isolation and native output verification. A content hash is a consistency/cache key, not a sandbox or authentication boundary against trusted project build scripts.

The exact build-context type, error reporting, and Cargo cached build-script message behavior need implementation tests before this becomes a stable public contract.

SDK path binding and reproducibility

program.build_env belongs to the Cargo input variant. A value such as CEF_PATH = { component = "cef" } references the named component produced by existing dependency lowering. An optional confined subpath can serve SDKs that need a lib/ or bin/ directory. Unknown components, escaping paths, and reserved orchestration-variable overrides must be rejected.

For the first version:

  • Bind to verified local, stable, versioned source roots, e.g. vendor/cef/<cef-version>/{target}. Keep development and distribution on the same SDK contract.
  • Resolve/verify the declared component lock and relevant architecture before compiling. Keep the existing final lock verification as well; generated runtime/CRT inputs may only be known after building.
  • Stage the input for packaging and re-digest the bound local source after the build; fail if it changed.
  • Do not use a random job directory as CEF_PATH: it changes the Cargo build-script input each run and causes avoidable rebuilds.
  • Version the SDK path on upgrades, so Cargo does not reuse objects compiled against an SDK replaced in place.
  • Reject HTTPS-backed or universal SDK binding until a stable prepared-tree contract exists. Existing remote runtime component support remains available.
  • --offline-components governs Rake component downloads, not all network access by Cargo or arbitrary build scripts. Do not describe it as a hermetic/offline-build guarantee.

CEF-specific exact archive/API compatibility validation and extraction remain a thin SDK preparation step owned by the consumer or an explicit recipe. The current CEF binding may download into an invalid CEF_PATH; an acceptance test must prove the selected prepared SDK is valid and remains unchanged. Rake should not hard-code CEF version rules or silently claim support for archive formats its component extractor lacks.

Proposed CLI coverage

Entry pointProposed behavior
rake bundleDiscover standalone file first; existing metadata fallback. Release profile by default.
rake bundle --config ...Explicit standalone source.
rake bundle --plan --jsonShow source/root/program/build selections, effective configuration, lock, output and pending native validation.
rake bundle --schemaDescribe the standalone document; preserve an explicit way to obtain the legacy Config schema.
rake build --native --config ...Build declared Cargo artifacts using the same source/build-context adapter; reject prebuilt input instead of pretending to compile it.
rake doctor --distribution --config ...Inspect that source and tools without downloading, signing, or requiring Cargo for a prebuilt input.
rake release --config ... --planResolve the same public source and release policy without accessing credentials or publishing.
rake release --config ... [--from ...]Explicit native release/promotion using that source and existing verification/atomicity rules.
rake update-key ...Preserve the existing explicit independent key-management interface. No automatic key enrollment through bundle/config discovery.
rake bundle --target webRoute supported Cargo inputs and the selected web settings to the existing Web pipeline; reject unsupported prebuilt combinations.

Keep existing supported signing, target/format, features, output, component-lock/offline, and compatibility options. Do not turn this into a generic project/build supervisor.

Proposed Rust API and compatibility boundary

Keep rake-dist-core as the portable validated model, and rake-dist as the host-side coordinator. No new UI dependency or replacement packaging framework is required.

Schematic additions (names/signatures to finalize during implementation):

pub enum Program {
    Cargo(CargoProgram),
    Prebuilt(PrebuiltProgram),
}

pub struct BundleSource {
    pub root: PathBuf,
    pub program: Program,
    pub config: Config,
}

pub fn load_bundle_file(path: &Path) -> Result<BundleSource, Error>;

pub fn plan_source(
    source: &BundleSource,
    platform: Platform,
    target: Option<&str>,
    formats: Option<&[Format]>,
) -> Result<Plan, Error>;

pub fn dispatch_worker(
    args_without_argv0: &[OsString],
) -> Option<Result<Distribution, Error>>;
  • Preserve existing plan, plan_with, plan_metadata, plan_metadata_with, bundle, execute_worker, schema, publication, signing-key and extension entry points. Add adapters; do not silently reinterpret existing signatures.
  • The file lowers into existing Config plus an explicit program/root envelope. Programmatic callers can supply equivalent data without authoring a TOML file.
  • Carry normalized source data into the existing owned worker job, including explicit root/lock/output provenance. Avoid a second live parse of a different config during execution. Keep Cargo selection, version resolution, and plan revalidation where required.
  • Retain bundle(request, packager_host, cancelled) as the process-isolated execution path. Evolve its request compatibly or add a new source request adapter; reject conflicting legacy/source fields. Do not overload a fake empty manifest path as a source selector.
  • The dispatcher returns typed errors and never calls exit or prints on behalf of the embedding host. Mark its result must-use. A caller must handle it before starting any UI/runtime and map errors to process exit status.
  • packager_host means the binary implementing the worker protocol, not the application being packaged. Document that distinction and provide a tiny non-Rake packager-host example.
  • Keep publication and custom-backend/native-verifier APIs attached to the same resolved identity/configuration. Private signing material stays out of serialized requests, build contexts, artifact metadata, and examples.
  • Retain existing installed descriptor compatibility. Helper-app declarations do not justify adding unversioned fields to a strict reader.

Confirmed implementation gaps and items needing validation

  1. Cargo-coupled execution: the current coordinator always calls Cargo metadata, and builds only one selected main bin. Add the source boundary and collect the deduplicated required Cargo bins.
  2. Helper wrapper staging: generic sidecars do not produce CEF's nested application layout. Stage declared helper apps after the package engine creates the app and before final signing.
  3. Filename inspection: otool -L currently fails on the actual Silicon Helper (Renderer) filename, interpreting the final parentheses as archive-member notation. This was reproduced locally. Replace fragile textual inspection or otherwise prove robust handling of legal filenames; the existing binary parser dependency is a candidate.
  4. Per-helper entitlements: current signing preserves entitlements on already-signed nested code. It does not express the explicit declared policy for newly generated helper wrappers. Apply each helper policy and verify the resulting entitlements; do not blanket-apply the main app's policy to every framework/XPC object.
  5. Hardened Runtime: local signature integrity alone does not establish Hardened Runtime behavior or Developer ID/Gatekeeper readiness. Test those separately and preserve native trust requirements.
  6. Build configuration ownership: rake-build must stop silently deriving a different configuration from Cargo metadata when a standalone source is selected.
  7. Non-Rake/prebuilt gates: current Windows/build/update integration checks and host-target detection must not force a Rust toolchain or GPUI defaults onto prebuilt programs. Unsupported integrations should fail explicitly before expensive work.
  8. Naming and SDK details: settle CEF main/helper executable conventions with a relocated real-process launch test before adding speculative executable-name options. Verify the prepared SDK layout, version match, license/credits, and read-only build behavior.

These findings do not establish that Rake has already successfully packaged and launched CEF through this proposed API.

Acceptance criteria

  • Standalone parsing has a documented schema, typo/unknown-key diagnostics, and validation for incompatible program/helper forms.
  • Every current Config field/nested section remains represented and validated; tests cover migration of current examples, platform settings, overrides, updates, release, extensions, and supported Web configuration.
  • Explicit/discovered/fallback selection, shadowed metadata, CLI conflicts, roots, lock names, output bases, and symlink/traversal rejection have tests.
  • A plain Rust app with no Rake UI/runtime dependency packages and launches after relocation, using a packager host that does not depend on rake-cli.
  • A prebuilt native executable packages with Cargo/rustc unavailable; wrong architecture, unsupported integrations, and invalid inputs fail clearly.
  • A generic Cargo worker is built/installed correctly and remains discoverable using the existing sidecar contract.
  • Build scripts receive the same effective identity/resources/update policy as the packager. Cached Cargo builds replay/acknowledge the binding correctly. Unrelated signing/release changes do not trigger recompilation.
  • Two identical SDK-bound runs do not recompile CEF solely because a staging path changed. An SDK upgrade changes the input path/build fingerprint. Mutation and lock mismatch fail before signing or publication.
  • All five CEF helper wrappers retain the expected names/IDs/plists and explicit entitlements. Test parenthesized names and paths containing spaces.
  • Relocate the generated app, launch from an unrelated working directory, and observe real renderer and GPU subprocesses with the packaged framework.
  • Verify native imports/loader paths, every helper's entitlements, strict signatures, and a Hardened Runtime run. Developer ID/notarization/Gatekeeper claims require an actual enrolled native release test.
  • Cancellation during build/staging/signing/archive work terminates owned subprocesses, removes temporary state, and preserves the previous successful output.
  • File-based release planning/promotion uses the same configuration and keeps existing secret handling, independent verification, native-host requirements, all-target checks, and transactional publication.
  • Existing Cargo metadata users and public library entry points continue working.

Suggested implementation sequence

  1. Add standalone source loading/planning/schema and worker-source plumbing, with plain Cargo and prebuilt fixtures from the start.
  2. Unify the build-context handoff with rake-build before relying on the new source for embedded metadata or updates.
  3. Fix filename inspection and add multi-binary collection, ordinary Cargo sidecars, and macOS helper-app staging/signing.
  4. Add local SDK bindings, early lock/architecture checks, input-mutation checks, and repeat-build coverage.
  5. Migrate the CEF consumer to the new API, retaining only SDK preparation and a thin run convenience if needed.
  6. Complete parity across doctor, release, extensions, and supported Web paths; document explicit unsupported combinations.
  7. Run native release/trust acceptance before declaring the migration complete.

Decisions for discussion

  • Confirm Bundle.toml / Bundle.lock naming and config-root/ancestor-root rules.
  • Confirm the proposed Cargo/prebuilt vocabulary, source-selection precedence, and CLI conflict rules.
  • Decide the final source-request and build-context public/private boundaries without duplicating Config or weakening worker isolation.
  • Decide how helper lists participate in override layers, using existing array replacement rules unless there is a demonstrated need for merging.
  • Decide whether an explicit empty entitlement file is sufficient, or whether a typed explicit-none policy is needed; never silently inherit stale policy for a newly declared helper.
  • Define the supported standalone Web/update/Windows integration matrix precisely. Do not equate generic packaging with automatic runtime/updater integration.

The key proposal is one readable standalone file, one validated distribution model, and one packaging engine, usable independently of Rake's application framework.

Activity

0

No activity yet.