main
Drew Owens 0.6.9 source: launch resilience, honest counts, ownership persistence, drain, quit ladder — 21 adversary passes, 303 te… cf16621 1mo ago
//! ADVERSARIAL REVIEW OF 0.5.8 — final pass.
//!
//! The third outcome is right: `close_outcome_unknown` sets
//! `outcome:"undetermined"`, names the victim's title and path and the pre-close
//! count, says in words that it cannot be told whether nothing closed or another
//! document did, and BREAKS. It never makes the benign claim. Every count read in
//! the drain goes through the one `Self::document_count` seam, so the mock can
//! make it unreadable everywhere at once.
//!
//! The remaining finding is in the write gate, and it is data loss.

mod common;

use common::Bridge;
use serde_json::{json, Value};
use std::os::unix::fs::PermissionsExt;

fn s(v: &Value) -> String {
    serde_json::to_string_pretty(v).unwrap_or_default()
}

/// THE DESTINATION TEST CANNOT TELL "ABSENT" FROM "COULD NOT LOOK".
///
/// The choke point's second condition is:
///
/// ```text
/// let clobbers = destination
///     .map(|d| !d.is_empty() && std::path::Path::new(d).exists())
///     .unwrap_or(false);
/// ```
///
/// `Path::exists()` is `fs::metadata(p).is_ok()` — it returns **false** for a
/// path that does not exist AND for one the process could not stat: permission
/// denied on a parent, a UNC share the bridge has no token for, a device not
/// ready, a path over the length limit. All of those become "the destination is
/// free", and a bridge-created document is then written there in the DEFAULT
/// posture with no opt-in, no `confirm` and no reason.
///
/// The bridge and SOLIDWORKS do not always have the same view of the filesystem.
/// The com host is a child of ab; SOLIDWORKS runs in the user's interactive
/// session with their network token. `\\server\share\part.sldprt` that the bridge
/// cannot stat is one SOLIDWORKS can open and overwrite — and the gate has
/// already said yes.
///
/// This is the one rule in the bridge that decides whether somebody's file
/// survives, and it is the only place left where an unanswerable question is
/// read as permission. `fs::try_exists` returns `io::Result<bool>` and
/// distinguishes the three cases; an `Err` must refuse.
#[test]
fn a_destination_the_bridge_cannot_stat_is_not_treated_as_free() {
    let base = std::path::PathBuf::from("/tmp/adv12-unreadable-dest");
    let _ = std::fs::remove_dir_all(&base);
    std::fs::create_dir_all(base.join("share")).unwrap();
    // The user's file. It is really there.
    std::fs::write(base.join("share/user-part.SLDPRT"), b"the user's only copy").unwrap();
    // ...behind a parent the bridge cannot traverse, which is what an
    // unreachable UNC share or a permission-denied path looks like to `exists()`.
    std::fs::set_permissions(base.join("share"), std::fs::Permissions::from_mode(0o000)).unwrap();
    let dest = base.join("share/user-part.SLDPRT");
    assert!(
        !dest.exists(),
        "precondition: Path::exists() reports FALSE for a file that is really there"
    );

    let b = Bridge::start(); // DEFAULT posture: no SWX_ALLOW_USER_WRITES
    b.call("swx_start", json!({"reason": "modelling"}));
    let made = b.call("swx_new_document", json!({"type": "part"}));
    let title = made["created"]["title"].as_str().unwrap_or("Part1").to_string();

    let r = b.call(
        "swx_save_as",
        json!({"targetDocument": title, "out": dest.to_string_lossy()}),
    );
    // Restore before asserting, so a failure cannot leave an unreadable dir behind.
    let _ = std::fs::set_permissions(base.join("share"), std::fs::Permissions::from_mode(0o755));

    let code = r["errorCode"].as_str().unwrap_or("");
    assert!(
        // `destination_unverifiable` is the code 0.5.9 shipped for this refusal —
        // added to this list, not substituted for it: the assertion is still
        // "the gate REFUSED, with a refusal code", and the list was written
        // before the name existed. Nothing that means "allowed" is in it.
        matches!(
            code,
            "destination_exists"
                | "user_writes_disabled"
                | "destination_unreadable"
                | "destination_unverifiable"
        ),
        "the write gate GRANTED a save into a destination it could not stat — a file the user \
         owns is sitting at that exact path. The call then failed only because this test's \
         filesystem refused it; on Windows, where SOLIDWORKS holds the user's token and the \
         bridge may not, the host would have written and the user's file would be gone. \
         `Path::exists()` cannot tell 'absent' from 'could not look', and the choke point reads \
         the second as permission.\nerrorCode: {code:?}\n{}",
        s(&r)
    );
}

/// The rest of the destination rule, pinned. These pass and must keep passing:
/// an existing file blocks the write in the default posture, and a genuinely new
/// path under a readable directory is allowed without any opt-in (the
/// choke-point rule the drain gate depends on).
#[test]
fn the_destination_rule_still_holds_where_the_answer_is_knowable() {
    let base = std::path::PathBuf::from("/tmp/adv12-knowable");
    let _ = std::fs::remove_dir_all(&base);
    std::fs::create_dir_all(&base).unwrap();
    std::fs::write(base.join("taken.SLDPRT"), b"the user's file").unwrap();

    let b = Bridge::start();
    b.call("swx_start", json!({"reason": "modelling"}));
    let made = b.call("swx_new_document", json!({"type": "part"}));
    let title = made["created"]["title"].as_str().unwrap_or("Part1").to_string();

    // An OCCUPIED destination is refused without the opt-in.
    let over = b.call(
        "swx_save_as",
        json!({"targetDocument": title, "out": base.join("taken.SLDPRT").to_string_lossy()}),
    );
    assert!(
        over["success"] != true,
        "an existing user file was overwritten in the default posture: {}",
        s(&over)
    );

    // A NEW path is allowed with no opt-in at all — bridge-created document,
    // destination that does not exist.
    let fresh = b.call(
        "swx_save_as",
        json!({"targetDocument": title, "out": base.join("fresh.SLDPRT").to_string_lossy()}),
    );
    assert!(
        fresh["success"] == true,
        "the choke-point rule should allow a bridge-created document to a NEW path without an \
         opt-in; this is the case tools/drain-gate.py depends on: {}",
        s(&fresh)
    );
}