app
SOLIDWORKS Bridge
Public Made by Adomby adom
Launch, model and quit SOLIDWORKS from any Adom container. Nothing is ever lost.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
//! ADVERSARIAL REVIEW OF 0.6.6 — pass nineteen.
//!
//! Sign-in recovery RUNS now: my pass-18 positive case passes, and the root
//! cause the Builder found (the walk took the first sldworks.exe, which had no
//! parent) is genuinely fixed.
//!
//! But "ANY running SOLIDWORKS descends from our chain" is the wrong
//! proposition, and it is a consent bug. The attempt is marked attributed and
//! `attachedAfterSignIn` on the strength of lineage to one process, while COM —
//! which is what every subsequent verb acts through — is attached to a
//! DIFFERENT one. Nothing binds the claim to the pid it was proved for.
mod common;
use common::{Bridge, TempDir};
use serde_json::{json, Value};
fn s(v: &Value) -> String {
serde_json::to_string_pretty(v).unwrap_or_default()
}
/// `reattribute_after_attach` orders the candidates with the COM-attached pid
/// first and then takes the FIRST ONE THAT DESCENDS:
///
/// ```text
/// for cand in &ordered {
/// if let Some(why) = descends_from_our_chain(&census, cand.pid, &a) {
/// found = Some((cand, why));
/// break;
/// ```
///
/// `attached_pid` is used only to order the list. There is no check that the
/// process it settled on IS the attached one. So with more than one
/// `SLDWORKS.exe` running — ours, descended from our launcher, plus another COM
/// happens to be attached to — the attempt is claimed as ours on the strength of
/// a process nobody is talking to.
///
/// What follows is the consent problem. `quit-gate.py::require_bridge_launched`
/// reads `launch.attributed` and `runBeginSeen`; the quit ladder then builds its
/// `Identity` from the COM `processId`. So the ladder becomes willing to end a
/// session whose only qualification is that a DIFFERENT process descended from
/// our chain. `swx_close_all_documents` acts through the same COM connection.
///
/// The claim has to bind to the pid it was proved for: succeed only when the
/// descending process IS the COM-attached one, and otherwise refuse with a named
/// reason (`attached_pid_not_ours`) so a caller can see why.
#[test]
fn re_attribution_claims_only_the_process_com_is_attached_to() {
let dir = TempDir::new("adv18-twosw");
std::fs::write(
dir.join("routes.json"),
json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0,
"sldworksAfterMs": 0, "attachAfterMs": 6000}})
.to_string(),
)
.unwrap();
std::fs::write(dir.join("preexisting.json"), json!([]).to_string()).unwrap();
let lnk = format!("{}/SOLIDWORKS Design.lnk", dir.path());
std::fs::write(&lnk, "x").unwrap();
let b = Bridge::start_in(
TempDir::new("adv18-scratch"),
&[
("SWX_SOLIDWORKS_SHORTCUT", &lnk),
("SWX_LAUNCH_FAKE_DIR", &dir.path()),
("SWX_LAUNCH_RUN_BEGIN_SECS", "1"),
("SWX_LAUNCH_SLDWORKS_SECS", "2"),
("SWX_LAUNCH_ATTACH_SECS", "2"),
("SWX_LAUNCH_POLL_MS", "100"),
("SWX_LAUNCH_RETRY_SETTLE_MS", "400"),
("SWX_LAUNCH_BACKOFF_SECS", "0"),
],
);
b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
// A SECOND SOLIDWORKS appears while we are launching — the user's, with a
// parent that was never ours. (One already present would make swx_start
// refuse outright, which is why it has to arrive mid-flight.)
std::thread::sleep(std::time::Duration::from_millis(300));
std::fs::write(
dir.join("census-overrides.json"),
json!([{"pid": 88556, "image": "SLDWORKS.exe", "ageSeconds": 0, "ppid": 4242}]).to_string(),
)
.unwrap();
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(30);
loop {
let st = b.call("swx_status", json!({}));
if st["launch"]["finished"] == true || std::time::Instant::now() > deadline {
break;
}
std::thread::sleep(std::time::Duration::from_millis(150));
}
std::thread::sleep(std::time::Duration::from_millis(6000));
b.call("swx_start", json!({"reason": "polling after the sign-in"}));
let st = b.call("swx_status", json!({}));
// NOT VACUOUS: more than one SOLIDWORKS must really be running, and the
// attempt must really have been claimed.
let procs = st["solidworks"]["processes"].as_array().cloned().unwrap_or_default();
assert!(
procs.len() >= 2,
"precondition: more than one SLDWORKS.exe is running: {}",
s(&st["solidworks"])
);
if st["launch"]["outcome"] != "attachedAfterSignIn" {
return; // it refused; nothing to prove here.
}
// THE CLAIM MUST BE ABOUT THE PROCESS COM IS TALKING TO.
let attached = st["com"]["processId"].as_u64();
let chain: Vec<u64> = st["launch"]["chainPids"]
.as_array()
.map(|a| a.iter().filter_map(|p| p["pid"].as_u64()).collect())
.unwrap_or_default();
let attached_descends = attached
.and_then(|want| {
procs
.iter()
.find(|p| p["pid"].as_u64() == Some(want))
.and_then(|p| p["ppid"].as_u64())
})
.map(|ppid| chain.contains(&ppid))
.unwrap_or(false);
assert!(
attached_descends,
"the attempt was claimed as ours (`attachedAfterSignIn`, attributed:true) while COM is \
attached to pid {attached:?}, which does NOT descend from this attempt's chain \
{chain:?}. Lineage was proved for a different SOLIDWORKS. Every verb downstream acts \
through this COM connection — the quit ladder builds its Identity from this very \
processId, and quit-gate's require_bridge_launched reads only `attributed` and \
`runBeginSeen` — so the ladder becomes willing to end a session nothing proved was \
ours.\ncom: {}\nsolidworks: {}\nlaunch: {}",
s(&st["com"]),
s(&st["solidworks"]),
s(&st["launch"])
);
}
/// ...and the claim should be auditable. `reattributionEvidence` is the ROUTE
/// NAME (`"shellExecute"`); it does not say which pid's lineage was proved, so
/// nothing in the report lets a reader notice that the proved pid and the
/// attached pid differ.
#[test]
fn the_reattribution_evidence_names_the_process_it_proved() {
let dir = TempDir::new("adv18-evidence");
std::fs::write(
dir.join("routes.json"),
json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0,
"sldworksAfterMs": 0, "attachAfterMs": 6000}})
.to_string(),
)
.unwrap();
std::fs::write(dir.join("preexisting.json"), json!([]).to_string()).unwrap();
let lnk = format!("{}/SOLIDWORKS Design.lnk", dir.path());
std::fs::write(&lnk, "x").unwrap();
let b = Bridge::start_in(
TempDir::new("adv18-scratch2"),
&[
("SWX_SOLIDWORKS_SHORTCUT", &lnk),
("SWX_LAUNCH_FAKE_DIR", &dir.path()),
("SWX_LAUNCH_RUN_BEGIN_SECS", "1"),
("SWX_LAUNCH_SLDWORKS_SECS", "2"),
("SWX_LAUNCH_ATTACH_SECS", "2"),
("SWX_LAUNCH_POLL_MS", "100"),
("SWX_LAUNCH_RETRY_SETTLE_MS", "400"),
("SWX_LAUNCH_BACKOFF_SECS", "0"),
],
);
b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(30);
loop {
let st = b.call("swx_status", json!({}));
if st["launch"]["finished"] == true || std::time::Instant::now() > deadline {
break;
}
std::thread::sleep(std::time::Duration::from_millis(150));
}
std::thread::sleep(std::time::Duration::from_millis(6000));
b.call("swx_start", json!({"reason": "polling"}));
let st = b.call("swx_status", json!({}));
if st["launch"]["outcome"] != "attachedAfterSignIn" {
return;
}
let ev = st["launch"]["reattributionEvidence"].as_str().unwrap_or("");
assert!(
ev.chars().any(|c| c.is_ascii_digit()),
"`reattributionEvidence` is {ev:?} — the route name. A claim this consequential has to \
name the process it was proved for and the parent it descended from, or a reader cannot \
check it against the pid COM is attached to.\n{}",
s(&st["launch"])
);
}