[pve-devel] [PATCH v2 storage] test: add tests for volume access checks
Fiona Ebner
f.ebner at proxmox.com
Wed Jul 30 15:04:20 CEST 2025
Signed-off-by: Fiona Ebner <f.ebner at proxmox.com>
---
Changes in v2:
* Fix includes, sorry for the noise!
src/test/Makefile | 5 +-
src/test/run_volume_access_tests.pl | 260 ++++++++++++++++++++++++++++
2 files changed, 264 insertions(+), 1 deletion(-)
create mode 100755 src/test/run_volume_access_tests.pl
diff --git a/src/test/Makefile b/src/test/Makefile
index 9186303..ee025bc 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -1,6 +1,6 @@
all: test
-test: test_zfspoolplugin test_lvmplugin test_disklist test_bwlimit test_plugin test_ovf
+test: test_zfspoolplugin test_lvmplugin test_disklist test_bwlimit test_plugin test_ovf test_volume_access
test_zfspoolplugin: run_test_zfspoolplugin.pl
./run_test_zfspoolplugin.pl
@@ -19,3 +19,6 @@ test_plugin: run_plugin_tests.pl
test_ovf: run_ovf_tests.pl
./run_ovf_tests.pl
+
+test_volume_access: run_volume_access_tests.pl
+ ./run_volume_access_tests.pl
diff --git a/src/test/run_volume_access_tests.pl b/src/test/run_volume_access_tests.pl
new file mode 100755
index 0000000..ce9fc2e
--- /dev/null
+++ b/src/test/run_volume_access_tests.pl
@@ -0,0 +1,260 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::MockModule;
+use Test::More;
+
+use lib ('.', '..');
+
+use PVE::RPCEnvironment;
+use PVE::Storage;
+use PVE::Storage::Plugin;
+
+my $storage_cfg = <<'EOF';
+dir: dir
+ path /mnt/pve/dir
+ content vztmpl,snippets,iso,backup,rootdir,images
+EOF
+
+my $user_cfg = <<'EOF';
+user:root at pam:1:0::::::
+user:noperm at pve:1:0::::::
+user:otherstorage at pve:1:0::::::
+user:dsallocate at pve:1:0::::::
+user:dsaudit at pve:1:0::::::
+user:backup at pve:1:0::::::
+user:vmuser at pve:1:0::::::
+
+
+role:dsallocate:Datastore.Allocate:
+role:dsaudit:Datastore.Audit:
+role:vmuser:VM.Config.Disk,Datastore.Audit:
+role:backup:VM.Backup,Datastore.AllocateSpace:
+
+acl:1:/storage/foo:otherstorage at pve:dsallocate:
+acl:1:/storage/dir:dsallocate at pve:dsallocate:
+acl:1:/storage/dir:dsaudit at pve:dsaudit:
+acl:1:/vms/100:backup at pve:backup:
+acl:1:/storage/dir:backup at pve:backup:
+acl:1:/vms/100:vmuser at pve:vmuser:
+acl:1:/vms/111:vmuser at pve:vmuser:
+acl:1:/storage/dir:vmuser at pve:vmuser:
+EOF
+
+my @users = qw(root at pam noperm at pve otherstorage at pve dsallocate at pve dsaudit at pve backup at pve vmuser at pve);
+
+
+my $pve_cluster_module;
+$pve_cluster_module = Test::MockModule->new('PVE::Cluster');
+$pve_cluster_module->mock(
+ cfs_update => sub { },
+ get_config => sub {
+ my ($file) = @_;
+ if ($file eq 'storage.cfg') {
+ return $storage_cfg;
+ } elsif ($file eq 'user.cfg') {
+ return $user_cfg;
+ }
+ die "TODO: mock get_config($file)\n";
+ },
+);
+
+my $rpcenv = PVE::RPCEnvironment->init('pub');
+$rpcenv->init_request();
+
+my @types = sort keys PVE::Storage::Plugin::get_vtype_subdirs()->%*;
+my $all_types = { map { $_ => 1 } @types };
+
+my @tests = (
+ {
+ volid => 'dir:backup/vzdump-qemu-100-2025_07_29-13_00_55.vma',
+ denied_users => {
+ 'dsaudit at pve' => 1,
+ 'vmuser at pve' => 1,
+ },
+ allowed_types => {
+ 'backup' => 1,
+ },
+ },
+ {
+ volid => 'dir:100/vm-100-disk-0.qcow2',
+ denied_users => {
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ },
+ allowed_types => {
+ 'images' => 1,
+ 'rootdir' => 1,
+ },
+ },
+ {
+ volid => 'dir:vztmpl/alpine-3.22-default_20250617_amd64.tar.xz',
+ denied_users => {
+ },
+ allowed_types => {
+ 'vztmpl' => 1,
+ },
+ },
+ {
+ volid => 'dir:iso/virtio-win-0.1.271.iso',
+ denied_users => {
+ },
+ allowed_types => {
+ 'iso' => 1,
+ },
+ },
+ {
+ volid => 'dir:111/subvol-111-disk-0.subvol',
+ denied_users => {
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ },
+ allowed_types => {
+ 'images' => 1,
+ 'rootdir' => 1,
+ },
+ },
+ # test different VM IDs
+ {
+ volid => 'dir:backup/vzdump-qemu-200-2025_07_29-13_00_55.vma',
+ denied_users => {
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ 'vmuser at pve' => 1,
+ },
+ allowed_types => {
+ 'backup' => 1,
+ },
+ },
+ {
+ volid => 'dir:200/vm-200-disk-0.qcow2',
+ denied_users => {
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ 'vmuser at pve' => 1,
+ },
+ allowed_types => {
+ 'images' => 1,
+ 'rootdir' => 1,
+ },
+ },
+ {
+ volid => 'dir:backup/vzdump-qemu-200-2025_07_29-13_00_55.vma',
+ vmid => 200,
+ denied_users => {},
+ allowed_types => {
+ 'backup' => 1,
+ },
+ },
+ {
+ volid => 'dir:200/vm-200-disk-0.qcow2',
+ vmid => 200,
+ denied_users => {},
+ allowed_types => {
+ 'images' => 1,
+ 'rootdir' => 1,
+ },
+ },
+ {
+ volid => 'dir:backup/vzdump-qemu-200-2025_07_29-13_00_55.vma',
+ vmid => 300,
+ denied_users => {
+ 'noperm at pve' => 1,
+ 'otherstorage at pve' => 1,
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ 'vmuser at pve' => 1,
+ },
+ allowed_types => {
+ 'backup' => 1,
+ },
+ },
+ {
+ volid => 'dir:200/vm-200-disk-0.qcow2',
+ vmid => 300,
+ denied_users => {
+ 'noperm at pve' => 1,
+ 'otherstorage at pve' => 1,
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ 'vmuser at pve' => 1,
+ },
+ allowed_types => {
+ 'images' => 1,
+ 'rootdir' => 1,
+ },
+ },
+ # test paths
+ {
+ volid => 'relative_path',
+ denied_users => {
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ 'dsallocate at pve' => 1,
+ 'vmuser at pve' => 1,
+ },
+ allowed_types => $all_types,
+ },
+ {
+ volid => '/absolute_path',
+ denied_users => {
+ 'backup at pve' => 1,
+ 'dsaudit at pve' => 1,
+ 'dsallocate at pve' => 1,
+ 'vmuser at pve' => 1,
+ },
+ allowed_types => $all_types,
+ },
+);
+
+my $cfg = PVE::Storage::config();
+
+is(scalar(@users), 7, 'number of users');
+
+for my $t (@tests) {
+ my ($volid, $vmid, $expected_denied_users, $expected_allowed_types) =
+ $t->@{qw(volid vmid denied_users allowed_types)};
+
+ # certain users are always expected to be denied, except in the special case where VM ID is set
+ $expected_denied_users->{'noperm at pve'} = 1 if !$vmid;
+ $expected_denied_users->{'otherstorage at pve'} = 1 if !$vmid;
+
+ for my $user (@users) {
+ my $description = "user: $user, volid: $volid";
+ $rpcenv->set_user($user);
+
+ my $actual_denied;
+
+ eval {
+ PVE::Storage::check_volume_access($rpcenv, $user, $cfg, $vmid, $volid, undef);
+ };
+ if (my $err = $@) {
+ $actual_denied = 1;
+ note($@) if !$expected_denied_users->{$user} # log the error for easy analysis
+ }
+
+ is($actual_denied, $expected_denied_users->{$user}, $description);
+ }
+
+ for my $type (@types) {
+ my $user = 'root at pam'; # type mismatch should not even work for root!
+
+ my $description = "type $type, volid: $volid";
+ $rpcenv->set_user($user);
+
+ my $actual_allowed = 1;
+
+ eval {
+ PVE::Storage::check_volume_access($rpcenv, $user, $cfg, $vmid, $volid, $type);
+ };
+ if (my $err = $@) {
+ $actual_allowed = undef;
+ note($@) if $expected_allowed_types->{$type} # log the error for easy analysis
+ }
+
+ is($actual_allowed, $expected_allowed_types->{$type}, $description);
+ }
+}
+done_testing();
--
2.47.2
More information about the pve-devel
mailing list