Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
fee581f
feat(windows): support Host-sealed driver tools
Sep 27, 2026
479048a
Merge current main into Windows sealed tools
Sep 27, 2026
a0fbe5d
test(drivers): account for portable sealed tool table
Sep 27, 2026
13fd6e7
test(windows): reject sealed tool digest substitution
Sep 27, 2026
e259fda
Merge current main into Windows sealed tools
Sep 27, 2026
1d51ef6
test(windows): expose sealed tool spawn diagnostics
Sep 27, 2026
3c46737
fix(windows): grant sealed tool staging traversal
Sep 27, 2026
c02ecdb
Merge current main into Windows sealed tools
Sep 27, 2026
4db3391
fix(windows): allow sealed tool child processes explicitly
Sep 27, 2026
40bdfa3
fix(windows): anchor LPAC cwd in private profile
Sep 27, 2026
ae7efc4
fix(windows): materialize sealed tools inside LPAC profile
Sep 27, 2026
5a2f161
Merge current main and preserve Windows sealed tools
Sep 27, 2026
6ebe82a
fix(windows): import Write for sealed tool staging
Sep 27, 2026
5cffdd7
fix(windows): scope sealed tool write trait
Sep 27, 2026
1fbc90b
security(windows): narrow inherited sealed tool authority
Sep 27, 2026
28b8099
security(windows): protect sealed tool profile ACLs
Sep 27, 2026
f03b769
fix(windows): clean sealed tool ACL imports
Sep 27, 2026
1750504
fix(windows): allow sealed tool directory reads
Sep 27, 2026
b8102f2
Merge current main into Windows sealed tools
Sep 27, 2026
ef6185f
fix(windows): drop obsolete sealed-tool ACL import
Sep 27, 2026
f184844
test(windows): diagnose sealed tool child creation
Sep 27, 2026
32bfb4d
security(windows): keep sealed tool children inside LPAC tree
Sep 27, 2026
4fbaa96
security(windows): verify sealed-tool child process policy
Sep 27, 2026
e8186fd
test(windows): isolate sealed tool stdio spawn failure
Sep 27, 2026
378dd4f
ci(windows): isolate sealed tool host compatibility
Sep 27, 2026
9010163
fix(windows): keep sealed tool children in AppContainer
Sep 27, 2026
bd1a578
feat(windows): mediate sealed tools through Driver Host
Sep 27, 2026
b17a994
fix(driver-sdk): centralize sealed tool name validation
Sep 27, 2026
1e8238a
fix(driver-host): write Host tool replies through boxed transport
Sep 27, 2026
9e99435
fix(driver-host): scope Host-tool code to active platforms
Sep 27, 2026
5a38a03
diag(driver-host): report pre-Hello child exit code
Sep 27, 2026
3c5ec0e
fix(windows): budget x64-on-arm64 emulation overhead
Sep 27, 2026
ebce71a
fix(windows): make emulation memory budget explicit
Sep 27, 2026
7c509d2
fix(windows): run sealed x64 tools from native ARM host
Sep 27, 2026
a1802ba
test(windows): restore x64 emulation memory budget
Sep 28, 2026
d1ca6db
fix(windows): pin x64 sealed tool machine type on ARM64
Sep 28, 2026
3048699
fix(windows): budget one x64 emulation helper process
Sep 28, 2026
d8d2d15
fix(windows): let Prism select x64 tool emulation
Sep 28, 2026
fb40463
fix(windows): scope x64 emulation query to ARM64
Sep 28, 2026
1d70d3c
test(windows): isolate Prism memory-cap diagnosis
Sep 28, 2026
960bb65
test(windows): isolate LPAC impact on Prism
Sep 28, 2026
b1a9698
fix(windows): keep Prism sealed tools inside LPAC
Sep 28, 2026
5bda684
Merge current main into Windows sealed tools
Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/windows-platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ jobs:
run: cargo test --locked -p semwright-driver-host --test windows_secure_host -- secure_windows_driver_workspace --nocapture
- name: Secure Windows Driver secret grants
run: cargo test --locked -p semwright-driver-host --test windows_secure_host -- secure_windows_driver_secret --nocapture
- name: Secure Windows Driver sealed tools
run: cargo test --locked -p semwright-driver-host --test windows_secure_host -- secure_windows_driver_sealed_tool --nocapture
- name: Secure Windows Driver loopback bridge
run: cargo test --locked -p semwright-driver-host --test windows_secure_host -- secure_windows_driver_loopback --nocapture
- name: Secure Windows Plugin Host round-trip
Expand Down Expand Up @@ -167,3 +169,60 @@ jobs:
name: windows-${{ matrix.arch }}-evidence
path: verification/platform-ci/
retention-days: 14

sealed-tool-compat:
name: sealed-tool compat ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
include:
- name: server2022-x64
runs_on: windows-2022
toolchain: "1.98.1"
tool_target: ""
address_space_bytes: "536870912"
- name: win11-arm-native-host-x64tool
runs_on: windows-11-arm
toolchain: "1.98.1"
tool_target: "x86_64-pc-windows-msvc"
# Diagnostic-only probe budget: if Prism still fails with STATUS_NO_MEMORY at 4 GiB,
# do not expand production authority; investigate LPAC/emulation compatibility instead.
address_space_bytes: "4294967296"
runs-on: ${{ matrix.runs_on }}
timeout-minutes: 30
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
- name: Install diagnostic Rust toolchain
run: |
set -euo pipefail
rustup toolchain install "${{ matrix.toolchain }}" --profile minimal --force-non-host
- name: Record compatibility environment
run: |
set -euo pipefail
echo "RUNNER_ARCH=$RUNNER_ARCH"
echo "PROCESSOR_ARCHITECTURE=${PROCESSOR_ARCHITECTURE:-unknown}"
rustc +${{ matrix.toolchain }} -vV
- name: Build emulated sealed tool fixture
if: matrix.tool_target != ''
run: |
set -euo pipefail
rustup target add --toolchain "${{ matrix.toolchain }}" "${{ matrix.tool_target }}"
cargo +${{ matrix.toolchain }} build --locked \
-p semwright-driver-host \
--bin semwright-tool-fixture \
--target "${{ matrix.tool_target }}"
echo "SEMWRIGHT_TEST_TOOL_FIXTURE=$PWD/target/${{ matrix.tool_target }}/debug/semwright-tool-fixture.exe" >> "$GITHUB_ENV"
- name: Sealed tool nested execution probe
env:
SEMWRIGHT_TEST_ADDRESS_SPACE_BYTES: ${{ matrix.address_space_bytes }}
run: >-
cargo +${{ matrix.toolchain }} test --locked
-p semwright-driver-host
--test windows_secure_host
-- secure_windows_driver_sealed_tool_is_staged_immutable_and_executable
--nocapture
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions crates/driver-host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ tokio-util.workspace = true
async-trait.workspace = true
libc.workspace = true

[target.'cfg(windows)'.dependencies]
windows = { version = "0.62.2", features = [
"Win32_Foundation",
"Win32_Security",
"Win32_System_Threading",
] }

[dev-dependencies]
tempfile.workspace = true

Expand All @@ -35,6 +42,10 @@ workspace = true
name = "semwright-driver-fixture"
path = "src/bin/fixture.rs"

[[bin]]
name = "semwright-tool-fixture"
path = "src/bin/tool_fixture.rs"

[[bin]]
name = "semwright-adversarial-driver-fixture"
path = "src/bin/adversarial_fixture.rs"
Expand Down
212 changes: 211 additions & 1 deletion crates/driver-host/src/bin/fixture.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use async_trait::async_trait;
use semwright_driver_sdk::{
Capability, Driver, DriverExecutionContext, DriverInterfaces, descriptor_digest, secret_mount,
serve, system_config_mount, workspace_mount,
serve, system_config_mount, tool_path, workspace_mount,
};
use semwright_types::{
CommandDescriptor, Error, ErrorCode, Idempotency, JobArtifact, JobProgress, Result, Risk,
Expand Down Expand Up @@ -81,6 +81,45 @@ fn mount_capability() -> Capability {
}
}

fn tool_capability() -> Capability {
Capability {
descriptor: CommandDescriptor {
name: "driver.fixture.tool_probe".into(),
version: "1".into(),
description: "Execute one Host-sealed fixture tool and probe mutation authority".into(),
input_schema: json!({"type":"object","additionalProperties":false}),
output_schema: json!({
"type":"object",
"properties":{
"stdout":{"type":"string"},
"read_ok":{"type":"boolean"},
"execute_open_ok":{"type":"boolean"},
"self_spawn_ok":{"type":"boolean"},
"self_spawn_errno":{"type":"integer"},
"null_spawn_ok":{"type":"boolean"},
"null_spawn_errno":{"type":"integer"},
"write_ok":{"type":"boolean"},
"spawn_error_kind":{"type":"string"},
"spawn_errno":{"type":"integer"},
"exit_code":{"type":"integer"}
},
"required":["stdout","read_ok","execute_open_ok","self_spawn_ok","self_spawn_errno","null_spawn_ok","null_spawn_errno","write_ok","spawn_error_kind","spawn_errno","exit_code"],
"additionalProperties":false
}),
requires: vec!["driver:fixture".into()],
risk: Risk::ReadOnly,
idempotency: Idempotency::ReadOnly,
timeout_ms: 2_000,
dry_run: true,
interactive_consent: false,
backends: vec!["driver:fixture".into()],
},
aliases: vec!["tool_probe".into()],
tags: vec!["fixture".into(), "conformance".into(), "tool".into()],
object_types: vec![],
}
}

fn config_capability() -> Capability {
Capability {
descriptor: CommandDescriptor {
Expand Down Expand Up @@ -216,12 +255,14 @@ impl Driver for Fixture {
artifacts: true,
health: true,
native_refs: false,
host_tools: std::env::var_os("SEMWRIGHT_DRIVER_HOST_TOOLS").is_some(),
}
}
async fn capabilities(&mut self) -> Result<Vec<Capability>> {
Ok(vec![
capability(),
mount_capability(),
tool_capability(),
config_capability(),
secret_capability(),
long_capability(),
Expand All @@ -232,6 +273,7 @@ impl Driver for Fixture {
let capability = match command {
"driver.fixture.ping" => capability(),
"driver.fixture.mount_probe" => mount_capability(),
"driver.fixture.tool_probe" => tool_capability(),
"driver.fixture.config_probe" => config_capability(),
"driver.fixture.secret_probe" => secret_capability(),
"driver.fixture.disconnect" => disconnect_capability(),
Expand Down Expand Up @@ -259,6 +301,109 @@ impl Driver for Fixture {
let write_ok = std::fs::write(root.join("child.txt"), b"written").is_ok();
return Ok(json!({"read":read,"write_ok":write_ok}));
}
if command == "driver.fixture.tool_probe" {
if args.as_object().is_none_or(|args| !args.is_empty()) {
return Err(Error::invalid("fixture tool probe accepts an empty object"));
}
let tool = tool_path("probe")?;
let read_ok = std::fs::File::open(&tool).is_ok();
#[cfg(windows)]
let execute_open_ok = {
use std::os::windows::fs::OpenOptionsExt;
std::fs::OpenOptions::new()
.access_mode(0x0012_00A0)
.share_mode(0x7)
.open(&tool)
.is_ok()
};
#[cfg(not(windows))]
let execute_open_ok = read_ok;
#[cfg(windows)]
let (self_spawn_ok, self_spawn_errno) = match std::env::current_exe() {
Ok(executable) => match std::process::Command::new(executable)
.env("SEMWRIGHT_FIXTURE_SELF_PROBE", "1")
.output()
{
Ok(output) => (
output.status.success() && output.stdout.starts_with(b"self-ok"),
-1,
),
Err(error) => (false, error.raw_os_error().unwrap_or(-1)),
},
Err(error) => (false, error.raw_os_error().unwrap_or(-1)),
};
#[cfg(not(windows))]
let (self_spawn_ok, self_spawn_errno) = (true, -1);
#[cfg(windows)]
let (null_spawn_ok, null_spawn_errno) = {
use std::process::Stdio;
match std::process::Command::new(&tool)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
{
Ok(status) => (status.success(), -1),
Err(error) => (false, error.raw_os_error().unwrap_or(-1)),
}
};
#[cfg(not(windows))]
let (null_spawn_ok, null_spawn_errno) = (true, -1);
let write_ok = std::fs::OpenOptions::new().write(true).open(&tool).is_ok();
let output = match std::process::Command::new(&tool).output() {
Ok(output) => output,
Err(error) => {
return Ok(json!({
"stdout":"",
"read_ok":read_ok,
"execute_open_ok":execute_open_ok,
"self_spawn_ok":self_spawn_ok,
"self_spawn_errno":self_spawn_errno,
"null_spawn_ok":null_spawn_ok,
"null_spawn_errno":null_spawn_errno,
"write_ok":write_ok,
"spawn_error_kind":format!("{:?}", error.kind()),
"spawn_errno":error.raw_os_error().unwrap_or(-1),
"exit_code":-1
}));
}
};
let exit_code = output.status.code().unwrap_or(-1);
if !output.status.success() {
return Ok(json!({
"stdout":"",
"read_ok":read_ok,
"execute_open_ok":execute_open_ok,
"self_spawn_ok":self_spawn_ok,
"self_spawn_errno":self_spawn_errno,
"null_spawn_ok":null_spawn_ok,
"null_spawn_errno":null_spawn_errno,
"write_ok":write_ok,
"spawn_error_kind":"",
"spawn_errno":-1,
"exit_code":exit_code
}));
}
let stdout = String::from_utf8(output.stdout).map_err(|_| {
Error::new(
ErrorCode::BackendFailed,
"fixture tool output was not UTF-8",
)
})?;
return Ok(json!({
"stdout":stdout,
"read_ok":read_ok,
"execute_open_ok":execute_open_ok,
"self_spawn_ok":self_spawn_ok,
"self_spawn_errno":self_spawn_errno,
"null_spawn_ok":null_spawn_ok,
"null_spawn_errno":null_spawn_errno,
"write_ok":write_ok,
"spawn_error_kind":"",
"spawn_errno":-1,
"exit_code":exit_code
}));
}
if command == "driver.fixture.config_probe" {
if args.as_object().is_none_or(|args| !args.is_empty()) {
return Err(Error::invalid(
Expand Down Expand Up @@ -321,6 +466,67 @@ impl Driver for Fixture {
args: Value,
context: DriverExecutionContext,
) -> Result<Value> {
if command == "driver.fixture.tool_probe"
&& std::env::var_os("SEMWRIGHT_DRIVER_HOST_TOOLS").is_some()
{
let capability = tool_capability();
if descriptor_digest(&capability.descriptor)? != pinned_digest {
return Err(Error::new(
ErrorCode::StaleReference,
"Driver descriptor is not the pinned capability",
));
}
if args.as_object().is_none_or(|args| !args.is_empty()) {
return Err(Error::invalid("fixture tool probe accepts an empty object"));
}

let direct_path_visible = tool_path("probe").is_ok();
#[cfg(windows)]
let (self_spawn_ok, self_spawn_errno) = match std::env::current_exe() {
Ok(executable) => match std::process::Command::new(executable)
.env("SEMWRIGHT_FIXTURE_SELF_PROBE", "1")
.output()
{
Ok(output) => (
output.status.success() && output.stdout.starts_with(b"self-ok"),
-1,
),
Err(error) => (false, error.raw_os_error().unwrap_or(-1)),
},
Err(error) => (false, error.raw_os_error().unwrap_or(-1)),
};
#[cfg(not(windows))]
let (self_spawn_ok, self_spawn_errno) = (false, -1);

let output = context
.execute_tool(
"probe",
Vec::new(),
Vec::new(),
std::time::Duration::from_millis(1_500),
)
.await?;
let stdout = String::from_utf8(output.stdout).map_err(|_| {
Error::new(
ErrorCode::BackendFailed,
"fixture Host-tool output was not UTF-8",
)
})?;
return Ok(json!({
"stdout":stdout,
"read_ok":direct_path_visible,
"execute_open_ok":false,
"self_spawn_ok":self_spawn_ok,
"self_spawn_errno":self_spawn_errno,
"null_spawn_ok":false,
"null_spawn_errno":-1,
"write_ok":false,
"spawn_error_kind":"",
"spawn_errno":-1,
"exit_code":output.exit_code
}));
}

if command != "driver.fixture.long" {
return self.execute(command, pinned_digest, args).await;
}
Expand Down Expand Up @@ -421,6 +627,10 @@ async fn loopback_echo_task(path: String) {

#[tokio::main(flavor = "current_thread")]
async fn main() {
if std::env::var_os("SEMWRIGHT_FIXTURE_SELF_PROBE").is_some() {
println!("self-ok");
return;
}
#[cfg(windows)]
if let Ok(path) = std::env::var("SEMWRIGHT_DRIVER_LOOPBACK_PIPE") {
tokio::spawn(loopback_echo_task(path));
Expand Down
Loading
Loading