Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add E2E testing for usb #1214

Merged
merged 7 commits into from
Nov 1, 2023
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
2 changes: 2 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ jobs:
run: ./Testing/integration/test_config_changes.sh
- name: Test sync server changes
run: ./Testing/integration/test_sync_changes.sh
- name: Test USB blocking
run: ./Testing/integration/test_usb.sh
- name: Poweroff
if: ${{ always() }}
run: sudo shutdown -h +1
5 changes: 5 additions & 0 deletions Testing/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ run_command(
name = "dismiss_santa_popup",
cmd = "osascript $${BUILD_WORKSPACE_DIRECTORY}/Testing/integration/dismiss_santa_popup.scpt",
)

run_command(
name = "dismiss_usb_popup",
cmd = "osascript $${BUILD_WORKSPACE_DIRECTORY}/Testing/integration/dismiss_usb_popup.scpt",
)
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(NSString *)bundleDir;
+ (VZVirtualMachine *)createVirtualMachineWithBundleDir:(NSString *)bundleDir;
+ (VZVirtualMachine *)createVirtualMachineWithBundleDir:(NSString *)bundleDir
roDisk:(NSString *)roDisk;
roDisk:(NSString *)roDisk
usbDisk:(NSString *)usbDisk;

@end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,21 @@ + (VZVirtioBlockDeviceConfiguration *)createBlockDeviceConfigurationForDisk:(NSU
return disk;
}

+ (VZUSBMassStorageDeviceConfiguration *)createUSBDeviceConfigurationForDisk:(NSURL *)diskURL
readOnly:(BOOL)ro {
NSError *error;
VZDiskImageStorageDeviceAttachment *diskAttachment =
[[VZDiskImageStorageDeviceAttachment alloc] initWithURL:diskURL readOnly:ro error:&error];
if (!diskAttachment) {
NSLog(@"Failed to create VZDiskImageStorageDeviceAttachment: %@", error.localizedDescription);
exit(-1);
}
VZUSBMassStorageDeviceConfiguration *disk =
[[VZUSBMassStorageDeviceConfiguration alloc] initWithAttachment:diskAttachment];

return disk;
}

+ (VZVirtioNetworkDeviceConfiguration *)createNetworkDeviceConfiguration {
VZNATNetworkDeviceAttachment *natAttachment = [[VZNATNetworkDeviceAttachment alloc] init];
VZVirtioNetworkDeviceConfiguration *networkConfiguration =
Expand Down Expand Up @@ -189,15 +204,22 @@ + (VZVirtualMachineConfiguration *)createBaseVirtualMachineConfigurationWithBund
}

+ (VZVirtualMachine *)createVirtualMachineWithBundleDir:(NSString *)bundleDir
roDisk:(NSString *)roDisk {
roDisk:(NSString *)roDisk
usbDisk:(NSString*)usbDisk {
VZVirtualMachineConfiguration *configuration =
[self createBaseVirtualMachineConfigurationWithBundleDir:bundleDir];
if (roDisk) {
if (roDisk && ![roDisk isEqualToString:@""]) {
configuration.storageDevices = [configuration.storageDevices
arrayByAddingObject:[self createBlockDeviceConfigurationForDisk:[[NSURL alloc]
initFileURLWithPath:roDisk]
readOnly:YES]];
}
if (usbDisk && ![usbDisk isEqualToString:@""]) {
configuration.storageDevices = [configuration.storageDevices
arrayByAddingObject:[self createUSBDeviceConfigurationForDisk:[[NSURL alloc]
initFileURLWithPath:usbDisk]
readOnly:NO]];
}
NSError *error;
if (![configuration validateWithError:&error]) {
NSLog(@"Failed to validate configuration: %@", error.localizedDescription);
Expand All @@ -208,7 +230,7 @@ + (VZVirtualMachine *)createVirtualMachineWithBundleDir:(NSString *)bundleDir
}

+ (VZVirtualMachine *)createVirtualMachineWithBundleDir:(NSString *)bundleDir {
return [self createVirtualMachineWithBundleDir:bundleDir roDisk:nil];
return [self createVirtualMachineWithBundleDir:bundleDir roDisk:nil usbDisk:nil];
}

@end
2 changes: 1 addition & 1 deletion Testing/integration/VM/VMCLI/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ macos_application(
bundle_id = "com.google.santa.e2e.vmcli",
entitlements = "//Testing/integration/VM/Common:entitlements",
infoplists = ["//Testing/integration/VM/Common:plist"],
minimum_os_version = "12.0",
minimum_os_version = "13.0",
deps = [
":vmcli_lib",
],
Expand Down
11 changes: 8 additions & 3 deletions Testing/integration/VM/VMCLI/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ - (void)guestDidStopVirtualMachine:(VZVirtualMachine *)virtualMachine {
@end

int main(int argc, const char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s bundle_path", argv[0]);
if (argc < 2) {
fprintf(stderr, "Usage: %s bundle_path [usb_disk]", argv[0]);
exit(-1);
}

Expand All @@ -50,8 +50,13 @@ int main(int argc, const char *argv[]) {
bundleDir = [bundleDir stringByAppendingString:@"/"];
}

NSString *usbDisk;
if (argc > 2) {
usbDisk = @(argv[2]);
}

VZVirtualMachine *vm =
[MacOSVirtualMachineConfigurationHelper createVirtualMachineWithBundleDir:bundleDir];
[MacOSVirtualMachineConfigurationHelper createVirtualMachineWithBundleDir:bundleDir roDisk:nil usbDisk:usbDisk];

MacOSVirtualMachineDelegate *delegate = [MacOSVirtualMachineDelegate new];
vm.delegate = delegate;
Expand Down
34 changes: 22 additions & 12 deletions Testing/integration/VM/VMGUI/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,37 @@ @implementation AppDelegate {
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
#ifdef __arm64__
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *args = [[NSProcessInfo processInfo] arguments];
NSMutableArray *args = [NSMutableArray arrayWithArray:[[NSProcessInfo processInfo] arguments]];

VZMacOSVirtualMachineStartOptions *options = [VZMacOSVirtualMachineStartOptions new];
NSString *bundleDir;
NSString *roDisk;
NSString *usbDisk;

if (args.count < 2) {
abortWithErrorMessage(@"Usage: VMGUI [-recovery] bundle_path [ro_disk]");
[args removeObjectAtIndex:0];

if (args.count == 0) {
abortWithErrorMessage(@"Usage: VMGUI [-recovery] bundle_path [ro_disk] [usb_disk]");
}

int bundleArg = 1;
if ([args[1] isEqualToString:@"-recovery"]) {
if ([args[0] isEqualToString:@"-recovery"]) {
options.startUpFromMacOSRecovery = YES;
if (args.count < 3) {
abortWithErrorMessage(@"Usage: VMGUI [-recovery] bundle_path [ro_disk]");
[args removeObjectAtIndex:0];
if (args.count == 0) {
abortWithErrorMessage(@"Usage: VMGUI [-recovery] bundle_path [ro_disk] [usb_disk]");
}
bundleArg = 2;
}

bundleDir = args[bundleArg];
if (args.count > bundleArg + 1) {
roDisk = args[bundleArg + 1];
bundleDir = args[0];
[args removeObjectAtIndex:0];
if (args.count) {
roDisk = args[0];
[args removeObjectAtIndex:0];
}

if (args.count) {
usbDisk = args[0];
[args removeObjectAtIndex:0];
}

if (![bundleDir hasSuffix:@"/"]) {
Expand All @@ -77,7 +86,8 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

VZVirtualMachine *vm =
[MacOSVirtualMachineConfigurationHelper createVirtualMachineWithBundleDir:bundleDir
roDisk:roDisk];
roDisk:roDisk
usbDisk:usbDisk];
self->_virtualMachine = vm;

self->_delegate = [MacOSVirtualMachineDelegate new];
Expand Down
5 changes: 4 additions & 1 deletion Testing/integration/actions/start_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,12 @@
print(f"Snapshot: {snapshot_dir}")
# COW copy the image to this tempdir
subprocess.check_output(["cp", "-rc", extracted_path, snapshot_dir])
# Create a disk image for USB testing
usb_dmg = pathlib.Path(snapshot_dir) / "usb.dmg"
subprocess.check_output(["hdiutil", "create", "-size", "100M", "-fs", "ExFAT", "-volname", "USB", usb_dmg])
try:
subprocess.check_output(
[VMCLI, pathlib.Path(snapshot_dir) / extracted_path.name],
[VMCLI, pathlib.Path(snapshot_dir) / extracted_path.name, usb_dmg],
timeout=TIMEOUT,
)
except subprocess.TimeoutExpired:
Expand Down
10 changes: 10 additions & 0 deletions Testing/integration/dismiss_usb_popup.scpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Dismiss the "disk remounted" popup from Santa.
-- This is run inside test VMs.

on run argv
tell application "System Events"
tell process "Santa"
click button 1 of group 1 of window 1
end tell
end tell
end run
55 changes: 55 additions & 0 deletions Testing/integration/test_usb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/bash
set -xe

bazel run //Testing/integration:install_profile -- Testing/integration/configs/default.mobileconfig
sudo diskutil unmount force USB || true

killall moroz
/tmp/moroz -configs="$GITHUB_WORKSPACE/Testing/integration/configs/moroz_default/global.toml" -use-tls=false &
sudo santactl sync --debug
if [[ "$(sudo santactl status --json | jq .daemon.block_usb)" != "false" ]]; then
echo "USB blocking enabled with minimal config" >&2
exit 1
fi

sudo diskutil mount USB
echo test > /Volumes/USB/test
sync
sudo diskutil unmount force USB

killall moroz
/tmp/moroz -configs="$GITHUB_WORKSPACE/Testing/integration/configs/moroz_changed/global.toml" -use-tls=false &
sudo santactl sync --debug
if [[ "$(sudo santactl status --json | jq .daemon.block_usb)" != "true" ]]; then
echo "USB blocking config change didnt take effect" >&2
exit 1
fi

set +e
sudo diskutil mount USB
blocked=$?
set -e

if [[ $blocked == 0 ]]; then
echo "R/W mount succeeded with USB blocking enabled" >&2
exit 1
fi

sleep 5

# Santa should have remounted the disk RO for us. Check that it did.
bazel run //Testing/integration:dismiss_usb_popup
cat /Volumes/USB/test

sudo diskutil unmount force USB

# Ensure things can still be normally mounted if mount flags match remount opts.
set +e
sudo diskutil mount -mountOptions ro,noexec USB
blocked=$?
set -e

if [[ $blocked != 0 ]]; then
echo "RO+noexec mount failed with USB blocking enabled" >&2
exit 1
fi