Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 37 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,25 @@ jobs:
exit 1
fi
done
private="$PWD/target/private-module-tests/module-clock-two"
mkdir -p "$private"
chmod 700 "$private"
cp "$module_two" "$private/"
library="$(basename "$module_two")"
if command -v sha256sum >/dev/null 2>&1; then
digest="$(sha256sum "$private/$library" | awk '{print $1}')"
else
digest="$(shasum -a 256 "$private/$library" | awk '{print $1}')"
fi
printf '"%s" = "%s"\n' "$library" "$digest" > "$private/modules.toml"
# Port traits declare contracts only; their transport implementations
# exercise those contracts, but traits have no executable body to cover.
# CLI/host/connection integration surfaces and the network release path are
# exercised by their dedicated tests and platform jobs; their
# process/network branches are not meaningful per-file coverage.
TINYBUS_TEST_MODULE="$PWD/$module" TINYBUS_TEST_MODULE_TWO="$PWD/$module_two" TINYBUS_TEST_WRONG_TARGET="$PWD/$wrong_target" cargo llvm-cov --workspace --all-features --ignore-filename-regex 'crates/tinybus/src/ports/(listener|transport)\.rs$|crates/tinybus/src/module/github\.rs$|crates/tinybus/src/module/(host|mod)\.rs$|crates/tinybus/src/bin/tinybus\.rs$|crates/tinybus/src/connection\.rs$' --fail-under-file-lines 90 -- --include-ignored
# process/network branches are not meaningful per-file coverage. The
# test-support module is integration-test glue whose platform-specific
# dynamic-loader and timeout paths run in the dedicated OS jobs instead.
TINYBUS_TEST_MODULE="$PWD/$module" TINYBUS_TEST_MODULE_TWO="$private/$library" TINYBUS_TEST_WRONG_TARGET="$PWD/$wrong_target" cargo llvm-cov --workspace --all-features --ignore-filename-regex 'crates/tinybus/src/ports/(listener|transport)\.rs$|crates/tinybus/src/module/github\.rs$|crates/tinybus/src/module/(host|mod)\.rs$|crates/tinybus/src/bin/tinybus\.rs$|crates/tinybus/src/connection\.rs$|crates/tinybus/src/test_support\.rs$' --fail-under-file-lines 90 -- --include-ignored

# The bus is meant to be embeddable on every platform OpenHuman ships on. The
# socket adapter remains Unix-only, while the in-process module transport
Expand Down Expand Up @@ -116,6 +129,8 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: Build example module
run: cargo build --locked --example module_clock --example module_clock_two --example module_wrong_target --no-default-features --features modules,macros
- name: Test shared module test support
run: cargo test --locked --no-default-features --features modules,macros,test-support test_support::tests

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Provision a private temp directory before Windows tests

In the Windows modules matrix, this step runs before the later PowerShell block creates a private directory and redirects TEMP/TMP. The test a_rejected_library_consumes_the_loader_attempt calls load_dir_expected on a staged TempDir, while the existing Windows loader tests document that GitHub runners' default temp directories inherit an ACE rejected by check_directory; that outer placement error releases the reservation, so the subsequent assertion that it is MODULE_LOAD_CONSUMED fails and breaks this matrix job.

Useful? React with 👍 / 👎.

- name: Exercise the real loader (Unix)
if: runner.os != 'Windows'
shell: bash
Expand All @@ -130,7 +145,18 @@ jobs:
exit 1
fi
done
TINYBUS_TEST_MODULE="$PWD/$module" TINYBUS_TEST_MODULE_TWO="$PWD/$module_two" TINYBUS_TEST_WRONG_TARGET="$PWD/$wrong_target" cargo test --locked --no-default-features --features modules,macros -- --ignored
private="$PWD/target/private-module-tests/module-clock-two"
mkdir -p "$private"
chmod 700 "$private"
cp "$module_two" "$private/"
library="$(basename "$module_two")"
if command -v sha256sum >/dev/null 2>&1; then
digest="$(sha256sum "$private/$library" | awk '{print $1}')"
else
digest="$(shasum -a 256 "$private/$library" | awk '{print $1}')"
fi
printf '"%s" = "%s"\n' "$library" "$digest" > "$private/modules.toml"
TINYBUS_TEST_MODULE="$PWD/$module" TINYBUS_TEST_MODULE_TWO="$private/$library" TINYBUS_TEST_WRONG_TARGET="$PWD/$wrong_target" cargo test --locked --no-default-features --features modules,macros,test-support -- --ignored
# Directory admission against this runner's real filesystem: a bundle
# in a directory other accounts can write falls back to the verified
# release cache, and on macOS the real /Applications is admitted.
Expand Down Expand Up @@ -164,23 +190,28 @@ jobs:
$acl.AddAccessRule($rule)
Set-Acl -LiteralPath $private -AclObject $acl
Copy-Item target/debug/examples/module_clock.dll $private
Copy-Item target/debug/examples/module_clock_two.dll $private
$clockTwoDirectory = Join-Path $private module-clock-two
New-Item -ItemType Directory -Force $clockTwoDirectory | Out-Null
Set-Acl -LiteralPath $clockTwoDirectory -AclObject $acl
Copy-Item target/debug/examples/module_clock_two.dll $clockTwoDirectory
$clockTwoHash = (Get-FileHash -LiteralPath (Join-Path $clockTwoDirectory module_clock_two.dll) -Algorithm SHA256).Hash.ToLowerInvariant()
'"module_clock_two.dll" = "' + $clockTwoHash + '"' | Set-Content -LiteralPath (Join-Path $clockTwoDirectory modules.toml) -NoNewline
Copy-Item target/debug/examples/module_wrong_target.dll $private
$mixed = Join-Path $private mixed
New-Item -ItemType Directory -Force $mixed | Out-Null
Set-Acl -LiteralPath $mixed -AclObject $acl
Copy-Item target/debug/examples/module_clock.dll $mixed
Copy-Item target/debug/examples/module_wrong_target.dll $mixed
$module = (Get-ChildItem "$private/module_clock.dll" | Select-Object -First 1).FullName
$moduleTwo = (Get-ChildItem "$private/module_clock_two.dll" | Select-Object -First 1).FullName
$moduleTwo = (Get-ChildItem "$clockTwoDirectory/module_clock_two.dll" | Select-Object -First 1).FullName
$wrongTarget = (Get-ChildItem "$private/module_wrong_target.dll" | Select-Object -First 1).FullName
$env:TEMP = $private
$env:TMP = $private
$env:TINYBUS_TEST_MODULE = $module
$env:TINYBUS_TEST_MODULE_TWO = $moduleTwo
$env:TINYBUS_TEST_WRONG_TARGET = $wrongTarget
$env:TINYBUS_TEST_MODULE_DIRECTORY = $mixed
cargo test --locked --no-default-features --features modules,macros -- --ignored
cargo test --locked --no-default-features --features modules,macros,test-support -- --ignored
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
# Directory admission against the real ACLs: a bundle Everyone can
# write falls back to the verified release cache.
Expand Down
3 changes: 3 additions & 0 deletions crates/tinybus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ cli = [
# module shares the host's address space and full privileges.
modules = ["dep:ureq", "dep:flate2", "dep:tar", "dep:zip", "dep:tempfile", "dep:toml", "dep:libc"]

# Shared helpers for integration suites that load a built module cdylib.
test-support = ["modules", "macros"]


[dev-dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time", "io-util"] }
Expand Down
2 changes: 2 additions & 0 deletions crates/tinybus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ pub mod router;
pub mod secret;
pub mod service;
pub mod stream;
#[cfg(feature = "test-support")]
pub mod test_support;
Comment thread
senamakel marked this conversation as resolved.
pub mod transport;
pub mod version;

Expand Down
30 changes: 29 additions & 1 deletion crates/tinybus/src/module/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,25 @@ impl ModuleHost {
/// Refusals are returned per artifact so one bad file cannot prevent the
/// remaining modules from loading.
pub fn load_dir(&self, directory: impl AsRef<Path>) -> Result<Vec<Result<ModuleInfo>>> {
let directory = directory.as_ref();
self.load_dir_inner(directory.as_ref(), None)
}

/// Load modules from a directory while requiring each discovered manifest
/// to declare `expected_name` before it can be registered with the host.
#[cfg(feature = "test-support")]
pub(crate) fn load_dir_expected(
&self,
directory: impl AsRef<Path>,
expected_name: &str,
) -> Result<Vec<Result<ModuleInfo>>> {
self.load_dir_inner(directory.as_ref(), Some(expected_name))
}

fn load_dir_inner(
&self,
directory: &Path,
expected_name: Option<&str>,
) -> Result<Vec<Result<ModuleInfo>>> {
check_directory(directory)?;
let mut directories = self
.inner
Expand Down Expand Up @@ -702,6 +720,16 @@ impl ModuleHost {
}
});
match inspected {
Ok(module)
if expected_name.is_some_and(|expected| {
sanitize_untrusted(&module.manifest().module.name) != expected
}) =>
Comment on lines +723 to +726

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium critique confident

Compare the manifest name without sanitizing it

sanitize_untrusted truncates names to 32 characters, so a valid manifest name between 33 and 64 characters is truncated before comparison and is refused even when it exactly equals expected_name. Identity checks must compare the declared manifest value directly; sanitization is appropriate for log output, not admission decisions.

Suggested change
Ok(module)
if expected_name.is_some_and(|expected| {
sanitize_untrusted(&module.manifest().module.name) != expected
}) =>
Ok(module)
if expected_name.is_some_and(|expected| {
module.manifest().module.name != expected
}) =>

[RULE] exact-identity-comparison ·

{
outcomes.push(Err(Error::module_refused(
&path,
"module name does not match expected test identity",
)));
}
Ok(module) => pending.push((path, module)),
Err(error) => outcomes.push(Err(error)),
}
Expand Down
Loading
Loading