clan-cli: do not skip secrets.update_secrets when a group is removed
We need to remove all keys that were in the group from affected secrets.
With this change we now take `group_name` as an argument in
`{add,remove}_member`, which is a little bit more readable than
`group_folder.parent.name`, and helps DRY the code a bit.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
from collections.abc import Callable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from clan_cli.completions import (
|
from clan_cli.completions import (
|
||||||
@@ -103,13 +104,19 @@ def update_group_keys(flake_dir: Path, group: str) -> list[Path]:
|
|||||||
|
|
||||||
|
|
||||||
def add_member(
|
def add_member(
|
||||||
flake_dir: Path, group_folder: Path, source_folder: Path, name: str
|
flake_dir: Path,
|
||||||
|
group_name: str,
|
||||||
|
get_group_folder: Callable[[Path, str], Path],
|
||||||
|
get_source_folder: Callable[[Path], Path],
|
||||||
|
name: str,
|
||||||
) -> list[Path]:
|
) -> list[Path]:
|
||||||
|
source_folder = get_source_folder(flake_dir)
|
||||||
source = source_folder / name
|
source = source_folder / name
|
||||||
if not source.exists():
|
if not source.exists():
|
||||||
msg = f"{name} does not exist in {source_folder}: "
|
msg = f"{name} does not exist in {source_folder}: "
|
||||||
msg += list_directory(source_folder)
|
msg += list_directory(source_folder)
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
|
group_folder = get_group_folder(flake_dir, group_name)
|
||||||
group_folder.mkdir(parents=True, exist_ok=True)
|
group_folder.mkdir(parents=True, exist_ok=True)
|
||||||
user_target = group_folder / name
|
user_target = group_folder / name
|
||||||
if user_target.exists():
|
if user_target.exists():
|
||||||
@@ -119,11 +126,18 @@ def add_member(
|
|||||||
user_target.unlink()
|
user_target.unlink()
|
||||||
user_target.symlink_to(os.path.relpath(source, user_target.parent))
|
user_target.symlink_to(os.path.relpath(source, user_target.parent))
|
||||||
changed_files = [user_target]
|
changed_files = [user_target]
|
||||||
changed_files.extend(update_group_keys(flake_dir, group_folder.parent.name))
|
group_name = group_folder.parent.name
|
||||||
|
changed_files.extend(update_group_keys(flake_dir, group_name))
|
||||||
return changed_files
|
return changed_files
|
||||||
|
|
||||||
|
|
||||||
def remove_member(flake_dir: Path, group_folder: Path, name: str) -> list[Path]:
|
def remove_member(
|
||||||
|
flake_dir: Path,
|
||||||
|
group_name: str,
|
||||||
|
get_group_folder: Callable[[Path, str], Path],
|
||||||
|
name: str,
|
||||||
|
) -> list[Path]:
|
||||||
|
group_folder = get_group_folder(flake_dir, group_name)
|
||||||
target = group_folder / name
|
target = group_folder / name
|
||||||
if not target.exists():
|
if not target.exists():
|
||||||
msg = f"{name} does not exist in group in {group_folder}: "
|
msg = f"{name} does not exist in group in {group_folder}: "
|
||||||
@@ -132,21 +146,24 @@ def remove_member(flake_dir: Path, group_folder: Path, name: str) -> list[Path]:
|
|||||||
target.unlink()
|
target.unlink()
|
||||||
updated_files = [target]
|
updated_files = [target]
|
||||||
|
|
||||||
if len(os.listdir(group_folder)) > 0:
|
|
||||||
updated_files.extend(update_group_keys(flake_dir, group_folder.parent.name))
|
|
||||||
|
|
||||||
if len(os.listdir(group_folder)) == 0:
|
if len(os.listdir(group_folder)) == 0:
|
||||||
group_folder.rmdir()
|
group_folder.rmdir()
|
||||||
|
|
||||||
if len(os.listdir(group_folder.parent)) == 0:
|
if len(os.listdir(group_folder.parent)) == 0:
|
||||||
group_folder.parent.rmdir()
|
group_folder.parent.rmdir()
|
||||||
|
|
||||||
|
updated_files.extend(update_group_keys(flake_dir, group_name))
|
||||||
|
|
||||||
return updated_files
|
return updated_files
|
||||||
|
|
||||||
|
|
||||||
def add_user(flake_dir: Path, group: str, name: str) -> None:
|
def add_user(flake_dir: Path, group: str, name: str) -> None:
|
||||||
updated_files = add_member(
|
updated_files = add_member(
|
||||||
flake_dir, users_folder(flake_dir, group), sops_users_folder(flake_dir), name
|
flake_dir,
|
||||||
|
group,
|
||||||
|
users_folder,
|
||||||
|
sops_users_folder,
|
||||||
|
name,
|
||||||
)
|
)
|
||||||
commit_files(
|
commit_files(
|
||||||
updated_files,
|
updated_files,
|
||||||
@@ -160,7 +177,12 @@ def add_user_command(args: argparse.Namespace) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def remove_user(flake_dir: Path, group: str, name: str) -> None:
|
def remove_user(flake_dir: Path, group: str, name: str) -> None:
|
||||||
updated_files = remove_member(flake_dir, users_folder(flake_dir, group), name)
|
updated_files = remove_member(
|
||||||
|
flake_dir,
|
||||||
|
group,
|
||||||
|
users_folder,
|
||||||
|
name,
|
||||||
|
)
|
||||||
commit_files(
|
commit_files(
|
||||||
updated_files,
|
updated_files,
|
||||||
flake_dir,
|
flake_dir,
|
||||||
@@ -175,8 +197,9 @@ def remove_user_command(args: argparse.Namespace) -> None:
|
|||||||
def add_machine(flake_dir: Path, group: str, name: str) -> None:
|
def add_machine(flake_dir: Path, group: str, name: str) -> None:
|
||||||
updated_files = add_member(
|
updated_files = add_member(
|
||||||
flake_dir,
|
flake_dir,
|
||||||
machines_folder(flake_dir, group),
|
group,
|
||||||
sops_machines_folder(flake_dir),
|
machines_folder,
|
||||||
|
sops_machines_folder,
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
commit_files(
|
commit_files(
|
||||||
@@ -191,7 +214,12 @@ def add_machine_command(args: argparse.Namespace) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def remove_machine(flake_dir: Path, group: str, name: str) -> None:
|
def remove_machine(flake_dir: Path, group: str, name: str) -> None:
|
||||||
updated_files = remove_member(flake_dir, machines_folder(flake_dir, group), name)
|
updated_files = remove_member(
|
||||||
|
flake_dir,
|
||||||
|
group,
|
||||||
|
machines_folder,
|
||||||
|
name,
|
||||||
|
)
|
||||||
commit_files(
|
commit_files(
|
||||||
updated_files,
|
updated_files,
|
||||||
flake_dir,
|
flake_dir,
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ def remove_user(flake_dir: Path, name: str) -> None:
|
|||||||
if not (memberships / name).exists():
|
if not (memberships / name).exists():
|
||||||
continue
|
continue
|
||||||
log.info(f"Removing user {name} from group {group}")
|
log.info(f"Removing user {name} from group {group}")
|
||||||
updated_paths.extend(groups.remove_member(flake_dir, memberships, name))
|
updated_paths.extend(
|
||||||
|
groups.remove_member(flake_dir, group, groups.users_folder, name)
|
||||||
|
)
|
||||||
# Remove the user's key:
|
# Remove the user's key:
|
||||||
updated_paths.extend(remove_object(sops_users_folder(flake_dir), name))
|
updated_paths.extend(remove_object(sops_users_folder(flake_dir), name))
|
||||||
# Remove the user from any secret where it was used:
|
# Remove the user from any secret where it was used:
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ def test_groups(
|
|||||||
groups = os.listdir(test_flake.path / "sops" / "groups")
|
groups = os.listdir(test_flake.path / "sops" / "groups")
|
||||||
assert len(groups) == 0
|
assert len(groups) == 0
|
||||||
|
|
||||||
# Check if the symlink to the group was removed our foo test secret:
|
# Check if the symlink to the group was removed from our foo test secret:
|
||||||
group_symlink = test_flake.path / "sops/secrets/foo/groups/group1"
|
group_symlink = test_flake.path / "sops/secrets/foo/groups/group1"
|
||||||
err_msg = (
|
err_msg = (
|
||||||
"Symlink to group1's key in foo secret "
|
"Symlink to group1's key in foo secret "
|
||||||
|
|||||||
Reference in New Issue
Block a user