def run_sandbox(args: Args, config: Config) -> None:
cmdline = args.cmdline or [os.getenv("SHELL", "bash")]
- options: list[PathString] = ["--same-dir"]
-
- # If we're not using tools tree certificates we don't have to do anything since the relaxed sandbox will
- # already have /etc and /var from the host so we don't need to do anything extra.
- if config.tools_tree_certificates:
- mounts = finalize_crypto_mounts(config)
-
- # Since we reuse almost every top level directory from the host except /usr, the crypto mountpoints
- # have to exist already in these directories or we'll fail with a permission error. Let's check this
- # early and show a better error and a suggestion on how users can fix this issue. We use slice
- # notation to get every 3rd item from the mounts list which is the destination path.
- for dst in mounts[2::3]:
- if not Path(dst).exists():
- die(
- f"Missing mountpoint {dst}",
- hint=f"Create an empty directory at {dst} using 'mkdir -p {dst}' as root and try again",
- )
-
- options += mounts
+ mounts = finalize_crypto_mounts(config, relaxed=True)
+
+ # Since we reuse almost every top level directory from the host except /usr, the crypto mountpoints
+ # have to exist already in these directories or we'll fail with a permission error. Let's check this
+ # early and show a better error and a suggestion on how users can fix this issue. We use slice
+ # notation to get every 3rd item from the mounts list which is the destination path.
+ for dst in mounts[2::3]:
+ if not Path(dst).exists():
+ die(
+ f"Missing mountpoint {dst}",
+ hint=f"Create an empty directory at {dst} using 'mkdir -p {dst}' as root and try again",
+ )
run(
cmdline,
devices=True,
network=True,
relaxed=True,
- options=options,
+ options=["--same-dir", *mounts],
),
)
yield options
-def finalize_crypto_mounts(config: Config) -> list[PathString]:
+def finalize_crypto_mounts(config: Config, relaxed: bool = False) -> list[PathString]:
+ mounts = []
root = config.tools() if config.tools_tree_certificates else Path("/")
- mounts = [
- (root / subdir, Path("/") / subdir)
- for subdir in (
- Path("etc/pki"),
- Path("etc/ssl"),
- Path("etc/ca-certificates"),
- Path("var/lib/ca-certificates"),
- )
- if (root / subdir).exists() and any(p for p in (root / subdir).rglob("*") if not p.is_dir())
- ]
+ if not relaxed or root != Path("/"):
+ mounts += [
+ (root / subdir, Path("/") / subdir)
+ for subdir in (
+ Path("etc/pki"),
+ Path("etc/ssl"),
+ Path("etc/ca-certificates"),
+ Path("var/lib/ca-certificates"),
+ )
+ if (root / subdir).exists() and any(p for p in (root / subdir).rglob("*") if not p.is_dir())
+ ]
- # This contains the Arch Linux keyring, which isn't certificates so ToolsTreeCertificates= doesn't apply.
- if (config.tools() / "etc/pacman.d/gnupg").exists():
- mounts += [(config.tools() / "etc/pacman.d/gnupg", Path("/etc/pacman.d/gnupg"))]
+ if not relaxed or config.tools() != Path("/"):
+ # This contains the Arch Linux keyring, which isn't certificates so ToolsTreeCertificates= doesn't
+ # apply.
+ if (config.tools() / "etc/pacman.d/gnupg").exists():
+ mounts += [(config.tools() / "etc/pacman.d/gnupg", Path("/etc/pacman.d/gnupg"))]
- if (config.tools() / "etc/crypto-policies").exists():
- mounts += [(config.tools() / "etc/crypto-policies", Path("/etc/crypto-policies"))]
+ if (config.tools() / "etc/crypto-policies").exists():
+ mounts += [(config.tools() / "etc/crypto-policies", Path("/etc/crypto-policies"))]
return flatten(("--ro-bind", src, target) for src, target in sorted(set(mounts), key=lambda s: s[1]))