* [PATCH access-control 0/2] fix: #6510: Allow deleting ACLs for non-existent entities & add API tests @ 2026-07-20 13:45 Elias Huhsovitz 2026-07-20 13:45 ` [PATCH access-control 1/2] fix #6510: api: acl: allow deleting ACLs for non-existent entities Elias Huhsovitz 2026-07-20 13:45 ` [PATCH access-control 2/2] test: api: add tests for ACL modification endpoint Elias Huhsovitz 0 siblings, 2 replies; 5+ messages in thread From: Elias Huhsovitz @ 2026-07-20 13:45 UTC (permalink / raw) To: pve-devel; +Cc: Elias Huhsovitz This series fixes Bug #6510, which prevents the deletion of ACLs for non-existent users, groups, or API tokens. Patch 1/2 modifies the `update_acl` API endpoint to bypass the entity existence check when the `delete` flag is set. This change allows administrators to clean up orphaned ACLs without weakening the strict validation applied when adding new permissions. Patch 2/2 introduces automated tests for the `PUT /access/acl` endpoint. The test suite verifies standard creation, modification, and deletion workflows, enforces privilege boundaries, and specifically tests the edge case resolved in the first patch. Elias Huhsovitz (2): fix #6510: api: acl: allow deleting ACLs for non-existent entities test: api: add tests for ACL modification endpoint src/PVE/API2/ACL.pm | 6 +- src/test/api-tests.pl | 2 +- src/test/api-update-acl-test.pl | 301 ++++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+), 4 deletions(-) create mode 100644 src/test/api-update-acl-test.pl -- 2.47.3 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH access-control 1/2] fix #6510: api: acl: allow deleting ACLs for non-existent entities 2026-07-20 13:45 [PATCH access-control 0/2] fix: #6510: Allow deleting ACLs for non-existent entities & add API tests Elias Huhsovitz @ 2026-07-20 13:45 ` Elias Huhsovitz 2026-07-21 14:40 ` Daniel Kral 2026-07-20 13:45 ` [PATCH access-control 2/2] test: api: add tests for ACL modification endpoint Elias Huhsovitz 1 sibling, 1 reply; 5+ messages in thread From: Elias Huhsovitz @ 2026-07-20 13:45 UTC (permalink / raw) To: pve-devel; +Cc: Elias Huhsovitz When a user, group, or API token is deleted, the system usually cleans up the associated ACLs. However, edge cases like manual configuration edits can leave orphaned ACL entries in the cluster configuration. Currently, the `update_acl` API endpoint strictly validates the existence of the target entity before processing any request. If the entity is missing, the API throws an error (e.g., "user 'foo@pve' does not exist") and aborts the operation. This prevents administrators from cleaning up leftover ACLs through the API. Bypass the existence check when the `delete` flag is set. This change allows the API to remove orphaned ACL entries. Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> --- src/PVE/API2/ACL.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PVE/API2/ACL.pm b/src/PVE/API2/ACL.pm index c57dd38..01329f7 100644 --- a/src/PVE/API2/ACL.pm +++ b/src/PVE/API2/ACL.pm @@ -224,7 +224,7 @@ __PACKAGE__->register_method({ foreach my $group (split_list($param->{groups})) { die "group '$group' does not exist\n" - if !$cfg->{groups}->{$group}; + if !$param->{delete} && !$cfg->{groups}->{$group}; if ($param->{delete}) { delete($node->{groups}->{$group}->{$role}); @@ -237,7 +237,7 @@ __PACKAGE__->register_method({ my $username = PVE::AccessControl::verify_username($userid); die "user '$username' does not exist\n" - if !$cfg->{users}->{$username}; + if !$param->{delete} && !$cfg->{users}->{$username}; if ($param->{delete}) { delete($node->{users}->{$username}->{$role}); @@ -248,7 +248,7 @@ __PACKAGE__->register_method({ foreach my $tokenid (split_list($param->{tokens})) { my ($username, $token) = PVE::AccessControl::split_tokenid($tokenid); - PVE::AccessControl::check_token_exist($cfg, $username, $token); + PVE::AccessControl::check_token_exist($cfg, $username, $token) if !$param->{delete}; if ($param->{delete}) { delete $node->{tokens}->{$tokenid}->{$role}; -- 2.47.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH access-control 1/2] fix #6510: api: acl: allow deleting ACLs for non-existent entities 2026-07-20 13:45 ` [PATCH access-control 1/2] fix #6510: api: acl: allow deleting ACLs for non-existent entities Elias Huhsovitz @ 2026-07-21 14:40 ` Daniel Kral 0 siblings, 0 replies; 5+ messages in thread From: Daniel Kral @ 2026-07-21 14:40 UTC (permalink / raw) To: Elias Huhsovitz, pve-devel On Mon Jul 20, 2026 at 3:45 PM CEST, Elias Huhsovitz wrote: > When a user, group, or API token is deleted, the system usually cleans > up the associated ACLs. However, edge cases like > manual configuration edits can leave orphaned ACL entries in the > cluster configuration. > > Currently, the `update_acl` API endpoint strictly validates the > existence of the target entity before processing any request. If the > entity is missing, the API throws an error (e.g., "user 'foo@pve' does > not exist") and aborts the operation. This prevents administrators from > cleaning up leftover ACLs through the API. > > Bypass the existence check when the `delete` flag is set. This change > allows the API to remove orphaned ACL entries. > > Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> > --- > src/PVE/API2/ACL.pm | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/src/PVE/API2/ACL.pm b/src/PVE/API2/ACL.pm > index c57dd38..01329f7 100644 > --- a/src/PVE/API2/ACL.pm > +++ b/src/PVE/API2/ACL.pm > @@ -224,7 +224,7 @@ __PACKAGE__->register_method({ > foreach my $group (split_list($param->{groups})) { > > die "group '$group' does not exist\n" > - if !$cfg->{groups}->{$group}; > + if !$param->{delete} && !$cfg->{groups}->{$group}; > > if ($param->{delete}) { > delete($node->{groups}->{$group}->{$role}); > @@ -237,7 +237,7 @@ __PACKAGE__->register_method({ > my $username = PVE::AccessControl::verify_username($userid); > > die "user '$username' does not exist\n" > - if !$cfg->{users}->{$username}; > + if !$param->{delete} && !$cfg->{users}->{$username}; > > if ($param->{delete}) { > delete($node->{users}->{$username}->{$role}); > @@ -248,7 +248,7 @@ __PACKAGE__->register_method({ > > foreach my $tokenid (split_list($param->{tokens})) { > my ($username, $token) = PVE::AccessControl::split_tokenid($tokenid); > - PVE::AccessControl::check_token_exist($cfg, $username, $token); > + PVE::AccessControl::check_token_exist($cfg, $username, $token) if !$param->{delete}; This line is a bit too long, please run `make tidy` on the individual patches before sending. > > if ($param->{delete}) { > delete $node->{tokens}->{$tokenid}->{$role}; Otherwise, this looks good to me and works as expected testing with some ACLs and removing non-existing users, groups or tokens from ACL paths, so modulo the make tidy consider this as: Reviewed-by: Daniel Kral <d.kral@proxmox.com> Tested-by: Daniel Kral <d.kral@proxmox.com> ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH access-control 2/2] test: api: add tests for ACL modification endpoint 2026-07-20 13:45 [PATCH access-control 0/2] fix: #6510: Allow deleting ACLs for non-existent entities & add API tests Elias Huhsovitz 2026-07-20 13:45 ` [PATCH access-control 1/2] fix #6510: api: acl: allow deleting ACLs for non-existent entities Elias Huhsovitz @ 2026-07-20 13:45 ` Elias Huhsovitz 2026-07-21 15:20 ` Daniel Kral 1 sibling, 1 reply; 5+ messages in thread From: Elias Huhsovitz @ 2026-07-20 13:45 UTC (permalink / raw) To: pve-devel; +Cc: Elias Huhsovitz The `PUT /access/acl` endpoint previously lacked automated test coverage. Introduce `api-update-acl-test.pl` to verify the ACL modification logic. The tests cover the following scenarios: - Adding, modifying, and deleting ACLs for existing users, groups, and tokens. - Rejecting requests to add ACLs for non-existent entities. - Enforcing privilege boundaries by rejecting calls lacking the `Permissions.Modify` privilege. - Deleting ACLs for non-existent entities. Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> --- src/test/api-tests.pl | 2 +- src/test/api-update-acl-test.pl | 301 ++++++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 src/test/api-update-acl-test.pl diff --git a/src/test/api-tests.pl b/src/test/api-tests.pl index a1a987a..e9c400a 100755 --- a/src/test/api-tests.pl +++ b/src/test/api-tests.pl @@ -7,6 +7,6 @@ use TAP::Harness; my $harness = TAP::Harness->new({ verbosity => -1 }); -my $result = $harness->runtests('api-get-permissions-test.pl'); +my $result = $harness->runtests('api-get-permissions-test.pl', 'api-update-acl-test.pl'); exit -1 if $result->{failed}; diff --git a/src/test/api-update-acl-test.pl b/src/test/api-update-acl-test.pl new file mode 100644 index 0000000..0157533 --- /dev/null +++ b/src/test/api-update-acl-test.pl @@ -0,0 +1,301 @@ +#!/usr/bin/env perl +use v5.36; + +use lib qw(..); + +use Test::More; +use Test::MockModule; + +use PVE::AccessControl; +use PVE::RPCEnvironment; +use PVE::API2::ACL; + +# This test suite verifies the `PUT /access/acl` API endpoint. +# +# It mocks the cluster filesystem and the RPC environment to isolate +# the API logic from external dependencies. The tests pass mock +# configuration hashes directly to the API handler and verify the +# resulting state changes and error messages. +# +# The `get_base_cfg` function generates a clean, default configuration +# hash. The `before_each` helper resets the configuration and all mock +# behaviors before each test to isolate the test cases. + +my $current_cfg; + +# --- MOCKS --- + +my $cluster_module = Test::MockModule->new('PVE::Cluster'); +$cluster_module->noop('cfs_update'); +$cluster_module->mock('cfs_read_file', sub ($filename) { + die "unknown file '$filename'\n" if $filename ne 'user.cfg'; + return $current_cfg; +}); +$cluster_module->mock('cfs_write_file', sub ($filename, $data, $force_utf8 = undef) { + die "unknown file '$filename'\n" if $filename ne 'user.cfg'; + $current_cfg = $data; +}); + +# Re-assign sub-routines to our mocked versions if imported into PVE::API2::ACL. +no warnings 'redefine'; +*PVE::API2::ACL::cfs_read_file = \&PVE::Cluster::cfs_read_file; +*PVE::API2::ACL::cfs_write_file = \&PVE::Cluster::cfs_write_file; + +# Mock lock_user_config to execute the callback immediately. +my $acl_module = Test::MockModule->new('PVE::AccessControl'); +$acl_module->mock('lock_user_config', sub ($code, @args) { + return $code->(@args); +}); + +my $rpcenv_module = Test::MockModule->new('PVE::RPCEnvironment'); + +my $rpcenv = PVE::RPCEnvironment->init('cli'); + +my ($handler, $handler_info) = PVE::API2::ACL->find_handler('PUT', ''); + +# --- HELPER FUNCTIONS --- + +sub get_base_cfg () { + return { + users => { + 'admin@pve' => { + enable => 1, + tokens => { + 'mytoken' => { privsep => 1 }, + }, + }, + }, + groups => { 'admin_group' => {} }, + roles => { + 'PVEAdmin' => { 'Permissions.Modify' => 1 }, + 'NoAccess' => {}, + }, + acl_root => {}, + }; +} + +sub before_each () { + $current_cfg = get_base_cfg(); + + $rpcenv_module->mock('permissions', sub { + return { 'Permissions.Modify' => 1 }; + }); + $rpcenv_module->mock('get_user', sub { + return 'admin@pve'; + }); +} + +sub run_update_acl ($params) { + my $result = eval { $handler->handle($handler_info, $params) }; + return ($result, $@); +} + +# --- TESTS --- + +subtest 'Add ACL for existing user succeeds' => sub { + before_each(); + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'admin@pve', + roles => 'PVEAdmin', + }); + + is($err, '', 'API call succeeds without throwing an error'); + ok(exists($current_cfg->{acl_root}->{users}->{'admin@pve'}->{PVEAdmin}), + 'admin@pve ACL was added to config'); +}; + +subtest 'Delete ACL for existing user succeeds' => sub { + before_each(); + $current_cfg->{acl_root}->{users} = { 'admin@pve' => { PVEAdmin => 1 } }; + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'admin@pve', + roles => 'PVEAdmin', + delete => 1, + }); + + is($err, '', 'API call succeeds without throwing an error'); + ok(!exists($current_cfg->{acl_root}->{users}->{'admin@pve'}->{PVEAdmin}), + 'admin@pve ACL was removed from config'); +}; + +subtest 'Add ACL without Permissions.Modify fails' => sub { + before_each(); + + $rpcenv_module->mock('permissions', sub { return {}; }); + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'admin@pve', + roles => 'PVEAdmin', + }); + + like($err, qr/requires 'Permissions.Modify'/, 'API call fails due to missing privileges'); + is($res, undef, 'API call returns undef on failure'); +}; + +subtest 'Modify existing ACL to add a second role' => sub { + before_each(); + $current_cfg->{acl_root}->{users} = { 'admin@pve' => { PVEAdmin => 1 } }; + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'admin@pve', + roles => 'NoAccess', + }); + + is($err, '', 'API call succeeds without throwing an error'); + ok(exists($current_cfg->{acl_root}->{users}->{'admin@pve'}->{PVEAdmin}), + 'Original PVEAdmin role is preserved'); + ok(exists($current_cfg->{acl_root}->{users}->{'admin@pve'}->{NoAccess}), + 'New NoAccess role was added successfully'); +}; + +subtest 'Modify existing ACL to change propagation flag' => sub { + before_each(); + $current_cfg->{acl_root}->{users} = { 'admin@pve' => { PVEAdmin => 1 } }; + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'admin@pve', + roles => 'PVEAdmin', + propagate => 0, + }); + + is($err, '', 'API call succeeds without throwing an error'); + is($current_cfg->{acl_root}->{users}->{'admin@pve'}->{PVEAdmin}, 0, + 'Propagation flag was updated from 1 to 0'); +}; + +subtest 'Modify existing ACL for group and token' => sub { + before_each(); + $current_cfg->{acl_root}->{groups} = { 'admin_group' => { PVEAdmin => 1 } }; + $current_cfg->{acl_root}->{tokens} = { 'admin@pve!mytoken' => { PVEAdmin => 1 } }; + + my ($res, $err) = run_update_acl({ + path => '/', + groups => 'admin_group', + tokens => 'admin@pve!mytoken', + roles => 'NoAccess', + propagate => 0, + }); + + is($err, '', 'API call succeeds without throwing an error'); + + is($current_cfg->{acl_root}->{groups}->{'admin_group'}->{PVEAdmin}, 1, + 'Group PVEAdmin role is preserved'); + ok(exists($current_cfg->{acl_root}->{groups}->{'admin_group'}->{NoAccess}), + 'Group NoAccess role was added'); + + is($current_cfg->{acl_root}->{tokens}->{'admin@pve!mytoken'}->{PVEAdmin}, 1, + 'Token PVEAdmin role is preserved'); + ok(exists($current_cfg->{acl_root}->{tokens}->{'admin@pve!mytoken'}->{NoAccess}), + 'Token NoAccess role was added'); +}; + +subtest 'Delete ACL for non-existing user' => sub { + before_each(); + $current_cfg->{acl_root}->{users} = { 'ghost@pve' => { PVEAdmin => 1 } }; + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'ghost@pve', + roles => 'PVEAdmin', + delete => 1, + }); + + is($err, '', 'API call succeeds without throwing an error'); + ok(!exists($current_cfg->{acl_root}->{users}->{'ghost@pve'}->{PVEAdmin}), + 'ghost@pve ACL was removed from config'); +}; + +subtest 'Add ACL for non-existing user fails' => sub { + before_each(); + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'ghost@pve', + roles => 'PVEAdmin', + }); + + like($err, qr/user 'ghost\@pve' does not exist/, 'API call fails with correct error message'); + is($res, undef, 'API call returns undef on failure'); +}; + +subtest 'Delete ACL for non-existing group' => sub { + before_each(); + $current_cfg->{acl_root}->{groups} = { 'ghost_group' => { PVEAdmin => 1 } }; + + my ($res, $err) = run_update_acl({ + path => '/', + groups => 'ghost_group', + roles => 'PVEAdmin', + delete => 1, + }); + + is($err, '', 'API call succeeds without throwing an error'); + ok(!exists($current_cfg->{acl_root}->{groups}->{'ghost_group'}->{PVEAdmin}), + 'ghost_group ACL was removed from config'); +}; + +subtest 'Add ACL for non-existing group fails' => sub { + before_each(); + + my ($res, $err) = run_update_acl({ + path => '/', + groups => 'ghost_group', + roles => 'PVEAdmin', + }); + + like($err, qr/group 'ghost_group' does not exist/, 'API call fails with correct error message'); + is($res, undef, 'API call returns undef on failure'); +}; + +subtest 'Delete ACL for non-existing token' => sub { + before_each(); + my $token_id = 'ghost@pve!ghost_token'; + $current_cfg->{acl_root}->{tokens} = { $token_id => { PVEAdmin => 1 } }; + + my ($res, $err) = run_update_acl({ + path => '/', + tokens => $token_id, + roles => 'PVEAdmin', + delete => 1, + }); + + is($err, '', 'API call succeeds without throwing an error'); + ok(!exists($current_cfg->{acl_root}->{tokens}->{$token_id}->{PVEAdmin}), + 'ghost token ACL was removed from config'); +}; + +subtest 'Add ACL for non-existing token fails' => sub { + before_each(); + + my ($res, $err) = run_update_acl({ + path => '/', + tokens => 'admin@pve!ghost_token', + roles => 'PVEAdmin', + }); + + like($err, qr/no such token/, 'API call fails with correct error message'); + is($res, undef, 'API call returns undef on failure'); +}; + +subtest 'Add ACL with non-existing role fails' => sub { + before_each(); + + my ($res, $err) = run_update_acl({ + path => '/', + users => 'admin@pve', + roles => 'InvalidRole', + }); + + like($err, qr/role 'InvalidRole' does not exist/, + 'API call fails with correct error message for invalid role'); + is($res, undef, 'API call returns undef on failure'); +}; + +done_testing(); -- 2.47.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH access-control 2/2] test: api: add tests for ACL modification endpoint 2026-07-20 13:45 ` [PATCH access-control 2/2] test: api: add tests for ACL modification endpoint Elias Huhsovitz @ 2026-07-21 15:20 ` Daniel Kral 0 siblings, 0 replies; 5+ messages in thread From: Daniel Kral @ 2026-07-21 15:20 UTC (permalink / raw) To: Elias Huhsovitz, pve-devel Thanks for adding some test cases for this! See below for some comments inline. The patch also needs a run of `make tidy`. On Mon Jul 20, 2026 at 3:45 PM CEST, Elias Huhsovitz wrote: > The `PUT /access/acl` endpoint previously lacked automated test > coverage. Introduce `api-update-acl-test.pl` to verify the ACL > modification logic. > > The tests cover the following scenarios: > - Adding, modifying, and deleting ACLs for existing users, groups, and > tokens. > - Rejecting requests to add ACLs for non-existent entities. > - Enforcing privilege boundaries by rejecting calls lacking the > `Permissions.Modify` privilege. > - Deleting ACLs for non-existent entities. > > Signed-off-by: Elias Huhsovitz <e.huhsovitz@proxmox.com> It might be nice to have these test cases precede the fixing patch so that the change in logic is directly visible and verifiable in the fixing patch through the change in the test outcomes. > --- > src/test/api-tests.pl | 2 +- > src/test/api-update-acl-test.pl | 301 ++++++++++++++++++++++++++++++++ > 2 files changed, 302 insertions(+), 1 deletion(-) > create mode 100644 src/test/api-update-acl-test.pl > > diff --git a/src/test/api-tests.pl b/src/test/api-tests.pl > index a1a987a..e9c400a 100755 > --- a/src/test/api-tests.pl > +++ b/src/test/api-tests.pl > @@ -7,6 +7,6 @@ use TAP::Harness; > > my $harness = TAP::Harness->new({ verbosity => -1 }); > > -my $result = $harness->runtests('api-get-permissions-test.pl'); > +my $result = $harness->runtests('api-get-permissions-test.pl', 'api-update-acl-test.pl'); > > exit -1 if $result->{failed}; > diff --git a/src/test/api-update-acl-test.pl b/src/test/api-update-acl-test.pl > new file mode 100644 > index 0000000..0157533 > --- /dev/null > +++ b/src/test/api-update-acl-test.pl > @@ -0,0 +1,301 @@ > +#!/usr/bin/env perl > +use v5.36; nit: missing empty newline between shebang and first use statement > + > +use lib qw(..); > + > +use Test::More; > +use Test::MockModule; > + > +use PVE::AccessControl; > +use PVE::RPCEnvironment; > +use PVE::API2::ACL; > + > +# This test suite verifies the `PUT /access/acl` API endpoint. > +# > +# It mocks the cluster filesystem and the RPC environment to isolate > +# the API logic from external dependencies. The tests pass mock > +# configuration hashes directly to the API handler and verify the > +# resulting state changes and error messages. > +# > +# The `get_base_cfg` function generates a clean, default configuration > +# hash. The `before_each` helper resets the configuration and all mock > +# behaviors before each test to isolate the test cases. > + > +my $current_cfg; > + > +# --- MOCKS --- > + > +my $cluster_module = Test::MockModule->new('PVE::Cluster'); > +$cluster_module->noop('cfs_update'); > +$cluster_module->mock('cfs_read_file', sub ($filename) { > + die "unknown file '$filename'\n" if $filename ne 'user.cfg'; > + return $current_cfg; > +}); > +$cluster_module->mock('cfs_write_file', sub ($filename, $data, $force_utf8 = undef) { > + die "unknown file '$filename'\n" if $filename ne 'user.cfg'; > + $current_cfg = $data; > +}); > + > +# Re-assign sub-routines to our mocked versions if imported into PVE::API2::ACL. > +no warnings 'redefine'; > +*PVE::API2::ACL::cfs_read_file = \&PVE::Cluster::cfs_read_file; > +*PVE::API2::ACL::cfs_write_file = \&PVE::Cluster::cfs_write_file; I tend to not redefine functions here at all. This could be rewritten as: my $api_acl_module = Test::MockModule->new('PVE::API2::ACL'); $api_acl_module->noop('cfs_update'); $api_acl_module->mock( 'cfs_read_file' => sub($filename) { ... }, 'cfs_write_file' => sub($filename, $data, $force_utf8 = undef) { ... }, ); > + > +# Mock lock_user_config to execute the callback immediately. > +my $acl_module = Test::MockModule->new('PVE::AccessControl'); > +$acl_module->mock('lock_user_config', sub ($code, @args) { > + return $code->(@args); > +}); > + > +my $rpcenv_module = Test::MockModule->new('PVE::RPCEnvironment'); > + > +my $rpcenv = PVE::RPCEnvironment->init('cli'); > + > +my ($handler, $handler_info) = PVE::API2::ACL->find_handler('PUT', ''); > + > +# --- HELPER FUNCTIONS --- > + > +sub get_base_cfg () { > + return { > + users => { > + 'admin@pve' => { > + enable => 1, > + tokens => { > + 'mytoken' => { privsep => 1 }, > + }, > + }, > + }, > + groups => { 'admin_group' => {} }, > + roles => { > + 'PVEAdmin' => { 'Permissions.Modify' => 1 }, > + 'NoAccess' => {}, > + }, > + acl_root => {}, > + }; > +} > + > +sub before_each () { > + $current_cfg = get_base_cfg(); > + > + $rpcenv_module->mock('permissions', sub { > + return { 'Permissions.Modify' => 1 }; > + }); > + $rpcenv_module->mock('get_user', sub { > + return 'admin@pve'; > + }); get_user doesn't need to be mocked every time, if you use $rpcenv->set_user('admin@pve'); > +} > + > +sub run_update_acl ($params) { > + my $result = eval { $handler->handle($handler_info, $params) }; > + return ($result, $@); > +} Hm, I wonder whether the test cases would be a little more compact and reviewable by following the usual test case structure which is - defining an array full of hashes where each hash represents a test case - a loop then goes through each test case Each test case could then make a deep comparison between the resulting $current_cfg->{acl_root}, which is reset for each test case entry. As a proposal for a possible test case entry could be: { update_acl_params => { ... }, # can be made empty for specific test cases, etc. permissions => { 'Permissions.Modify' => 1 }, expected_acl_root => { ... }, } What do you think? ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-21 15:21 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-20 13:45 [PATCH access-control 0/2] fix: #6510: Allow deleting ACLs for non-existent entities & add API tests Elias Huhsovitz 2026-07-20 13:45 ` [PATCH access-control 1/2] fix #6510: api: acl: allow deleting ACLs for non-existent entities Elias Huhsovitz 2026-07-21 14:40 ` Daniel Kral 2026-07-20 13:45 ` [PATCH access-control 2/2] test: api: add tests for ACL modification endpoint Elias Huhsovitz 2026-07-21 15:20 ` Daniel Kral
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.