mirror of
https://github.com/stablyai/orca.git
synced 2026-10-13 08:02:52 +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.
103 lines
3.4 KiB
Rust
103 lines
3.4 KiB
Rust
//! Launches the Orca CLI by running the packaged Electron binary as Node.
|
|
//!
|
|
//! Why a native binary rather than the `.cmd` alone: `cmd.exe` reparses `%*` and
|
|
//! executes or truncates embedded newlines, so orchestration message bodies
|
|
//! cannot survive it (#8374). `orca.cmd` refuses those subcommands and defers
|
|
//! here.
|
|
//!
|
|
//! Why not a managed assembly: a small freshly-compiled MSIL image in a
|
|
//! user-writable directory that mutates environment variables and proxies a
|
|
//! child process is the shape antivirus MSIL heuristics are trained on, and it
|
|
//! was flagged as exactly that across several vendors (#23383).
|
|
|
|
use std::env;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::{exit, Command};
|
|
|
|
fn main() {
|
|
let launcher = match env::current_exe() {
|
|
Ok(path) => path,
|
|
Err(error) => fail(&format!("Unable to start the Orca CLI: {error}")),
|
|
};
|
|
|
|
let Some(resources_directory) = launcher.parent().and_then(Path::parent) else {
|
|
fail(&format!(
|
|
"Unable to locate Orca.exe next to \"{}\"",
|
|
launcher.display()
|
|
))
|
|
};
|
|
let Some(app_directory) = resources_directory.parent() else {
|
|
fail(&format!(
|
|
"Unable to locate Orca.exe next to \"{}\"",
|
|
resources_directory.display()
|
|
))
|
|
};
|
|
|
|
let electron_path = app_directory.join("Orca.exe");
|
|
if !electron_path.is_file() {
|
|
fail(&format!(
|
|
"Unable to locate Orca.exe next to \"{}\"",
|
|
resources_directory.display()
|
|
));
|
|
}
|
|
|
|
let cli_path: PathBuf = resources_directory
|
|
.join("app.asar.unpacked")
|
|
.join("out")
|
|
.join("cli")
|
|
.join("index.js");
|
|
if !cli_path.is_file() {
|
|
fail(&format!(
|
|
"Unable to locate the Orca CLI entrypoint at \"{}\"",
|
|
cli_path.display()
|
|
));
|
|
}
|
|
|
|
// Why mutate this process rather than hand the child an environment map:
|
|
// an explicit map collapses a block carrying both PATH and Path into one
|
|
// entry, which is what killed the CLI in #12046. Leaving the map untouched
|
|
// makes the child inherit our block verbatim.
|
|
move_environment_variable("NODE_OPTIONS", "ORCA_NODE_OPTIONS");
|
|
move_environment_variable(
|
|
"NODE_REPL_EXTERNAL_MODULE",
|
|
"ORCA_NODE_REPL_EXTERNAL_MODULE",
|
|
);
|
|
env::set_var("ELECTRON_RUN_AS_NODE", "1");
|
|
env::set_var("ORCA_WINDOWS_PACKAGED_CLI_LAUNCHER", "1");
|
|
let requested_command = env::var("ORCA_CLI_COMMAND").unwrap_or_default();
|
|
env::set_var(
|
|
"ORCA_CLI_COMMAND",
|
|
if requested_command == "orca-ide" {
|
|
"orca-ide"
|
|
} else {
|
|
"orca"
|
|
},
|
|
);
|
|
|
|
// Each argument stays its own argv entry, so a body holding newlines reaches
|
|
// the CLI intact.
|
|
let mut command = Command::new(&electron_path);
|
|
command.arg(&cli_path).args(env::args_os().skip(1));
|
|
|
|
match command.status() {
|
|
Ok(status) => exit(status.code().unwrap_or(1)),
|
|
Err(error) => fail(&format!("Unable to start the Orca CLI: {error}")),
|
|
}
|
|
}
|
|
|
|
fn move_environment_variable(source_name: &str, target_name: &str) {
|
|
match env::var_os(source_name) {
|
|
// A missing source clears the target, so a stale value cannot leak in.
|
|
None => env::remove_var(target_name),
|
|
Some(value) => {
|
|
env::remove_var(source_name);
|
|
env::set_var(target_name, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn fail(message: &str) -> ! {
|
|
eprintln!("{message}");
|
|
exit(1)
|
|
}
|