mirror of
https://github.com/stablyai/orca.git
synced 2026-10-03 16:02:11 +00:00
* docs(security): add the antivirus clearance path for future releases Every AV false positive here has been handled one vendor and one shipped version at a time. Document the programs that clear future releases instead -- signer and product enrollment rather than per-build sample submission -- and add a script that reports an RC's current detection state by hash, so a verdict is found before users meet it in an issue report. Hash lookup only by default; --upload transmits the artifact and stays manual. * fix(windows): replace the managed CLI launcher with a native one resources\bin\orca.exe was a csc-compiled MSIL assembly: a small, freshly compiled .NET image in a user-writable directory that mutates environment variables and proxies a child process. That is the shape .NET dropper heuristics are trained on, and every verdict against it named the family -- MSILHeracles from two vendors, Wacatac!ml from a third. Signing the file does not change its shape, so signing never cleared it. Rebuild it in Rust. Same resolution, same environment contract, same argv passthrough that keeps newline-bearing orchestration bodies intact (#8374), and the child still inherits our environment block rather than an explicit map, so a block carrying both PATH and Path survives (#12046). The PE now carries publisher, version, icon and an asInvoker manifest from build.rs. Refs #23383 * ci(windows): install the Rust toolchain before building the CLI launcher The hosted runners happen to ship cargo, but a real Windows dev box does not -- verified on our own Windows QA host, where cargo and rustc were both absent. Relying on the image means a future image change fails deep inside electron-builder's native hook instead of at an obvious step.
64 lines
2.4 KiB
Rust
64 lines
2.4 KiB
Rust
//! Embeds the Windows PE version block, application manifest, and icon.
|
|
//!
|
|
//! Why this matters beyond cosmetics: an anonymous binary with no publisher,
|
|
//! no version, and no declared execution level scores worse under antivirus
|
|
//! heuristics than an identified one, and several vendor submission portals
|
|
//! reject a sample that carries no version metadata at all.
|
|
|
|
use std::env;
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=app.manifest");
|
|
println!("cargo:rerun-if-env-changed=ORCA_LAUNCHER_VERSION");
|
|
println!("cargo:rerun-if-env-changed=ORCA_LAUNCHER_ICON");
|
|
|
|
if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") {
|
|
return;
|
|
}
|
|
|
|
// Set by config/scripts/build-windows-cli-launcher.mjs from package.json, so
|
|
// the launcher always reports the release it shipped in.
|
|
let version = env::var("ORCA_LAUNCHER_VERSION")
|
|
.expect("ORCA_LAUNCHER_VERSION must be set; build through build-windows-cli-launcher.mjs");
|
|
let (major, minor, patch) = numeric_version_parts(&version);
|
|
|
|
let mut resource = winresource::WindowsResource::new();
|
|
resource.set("ProductName", "Orca");
|
|
resource.set("FileDescription", "Orca CLI Launcher");
|
|
resource.set("CompanyName", "Stably AI");
|
|
resource.set(
|
|
"LegalCopyright",
|
|
"Copyright (C) Stably AI. All rights reserved.",
|
|
);
|
|
resource.set("InternalName", "orca.exe");
|
|
resource.set("OriginalFilename", "orca.exe");
|
|
resource.set("FileVersion", &format!("{major}.{minor}.{patch}.0"));
|
|
resource.set("ProductVersion", &version);
|
|
resource.set_version_info(
|
|
winresource::VersionInfo::FILEVERSION,
|
|
(major << 48) | (minor << 32) | (patch << 16),
|
|
);
|
|
resource.set_version_info(
|
|
winresource::VersionInfo::PRODUCTVERSION,
|
|
(major << 48) | (minor << 32) | (patch << 16),
|
|
);
|
|
resource.set_manifest_file("app.manifest");
|
|
if let Ok(icon) = env::var("ORCA_LAUNCHER_ICON") {
|
|
resource.set_icon(&icon);
|
|
}
|
|
resource
|
|
.compile()
|
|
.expect("failed to compile Windows resources");
|
|
}
|
|
|
|
/// Strips any prerelease or build suffix; the PE numeric version accepts digits only.
|
|
fn numeric_version_parts(version: &str) -> (u64, u64, u64) {
|
|
let base = version.split(['-', '+']).next().unwrap_or_default();
|
|
let mut parts = base.split('.').map(|part| part.parse::<u64>().unwrap_or(0));
|
|
(
|
|
parts.next().unwrap_or(0),
|
|
parts.next().unwrap_or(0),
|
|
parts.next().unwrap_or(0),
|
|
)
|
|
}
|