bump hakurei version, add comments to api
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
package moe.rosa.planterette
|
||||
|
||||
@@ -2,4 +2,8 @@ package moe.rosa.planterette
|
||||
|
||||
import moe.rosa.planterette.hakurei.HakureiConfig
|
||||
|
||||
/**
|
||||
* Represents a Planterette build configuration.
|
||||
* @param hakurei Hakurei container configuration for the application.
|
||||
*/
|
||||
data class PlanteretteConfig(var hakurei: HakureiConfig?)
|
||||
@@ -44,11 +44,7 @@ annotation class FSOverlayDSL
|
||||
fun PlanteretteConfig.hakurei(id: String, init: @HakureiDSL HakureiConfig.() -> Unit) {
|
||||
this.hakurei = HakureiConfig(id).apply(init)
|
||||
}
|
||||
@HakureiDSL
|
||||
fun HakureiConfig.executable(path: String, vararg args: String) {
|
||||
this.path = AbsolutePath(path)
|
||||
this.args = args.toList()
|
||||
}
|
||||
|
||||
@HakureiDSL
|
||||
enum class DSLEnablements {
|
||||
Wayland,
|
||||
@@ -73,18 +69,7 @@ fun HakureiConfig.enable(vararg enablements: DSLEnablements) {
|
||||
fun HakureiConfig.directWayland(directWayland: Boolean = true) {
|
||||
this.directWayland = directWayland
|
||||
}
|
||||
@HakureiDSL
|
||||
fun HakureiConfig.username(username: String) {
|
||||
this.username = username
|
||||
}
|
||||
@HakureiDSL
|
||||
fun HakureiConfig.shell(shell: String) {
|
||||
this.shell = AbsolutePath(shell)
|
||||
}
|
||||
@HakureiDSL
|
||||
fun HakureiConfig.home(home: String) {
|
||||
this.home = AbsolutePath(home)
|
||||
}
|
||||
|
||||
//TODO(mae) automatic identity?
|
||||
@HakureiDSL
|
||||
fun HakureiConfig.identity(identity: Int? = null) {
|
||||
@@ -237,7 +222,23 @@ fun ContainerConfig.mapRealUid(mapRealUid: Boolean = true) {
|
||||
fun ContainerConfig.device(device: Boolean = true) {
|
||||
this.device = device
|
||||
}
|
||||
|
||||
@ContainerDSL
|
||||
fun ContainerConfig.username(username: String) {
|
||||
this.username = username
|
||||
}
|
||||
@ContainerDSL
|
||||
fun ContainerConfig.shell(shell: String) {
|
||||
this.shell = AbsolutePath(shell)
|
||||
}
|
||||
@ContainerDSL
|
||||
fun ContainerConfig.home(home: String) {
|
||||
this.home = AbsolutePath(home)
|
||||
}
|
||||
@ContainerDSL
|
||||
fun ContainerConfig.executable(path: String, vararg args: String) {
|
||||
this.path = AbsolutePath(path)
|
||||
this.args = args.toList()
|
||||
}
|
||||
@FilesystemDSL
|
||||
data class FilesystemConfigs(val configs: MutableList<FilesystemConfig> = mutableListOf())
|
||||
|
||||
|
||||
@@ -6,9 +6,70 @@ import kotlinx.serialization.encoding.*
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
/**
|
||||
* AbsolutePath holds a pathname checked to be absolute.
|
||||
* @constructor checks pathname and returns a new AbsolutePath if pathname is absolute.
|
||||
* Points to the file system root.
|
||||
*/
|
||||
val ROOT = AbsolutePath("/")
|
||||
|
||||
/**
|
||||
* Points to the directory for system-specific configuration.
|
||||
*/
|
||||
val ETC = AbsolutePath("/etc")
|
||||
|
||||
/**
|
||||
* Points to the place for small temporary files.
|
||||
*/
|
||||
val TMP = AbsolutePath("/tmp")
|
||||
|
||||
/**
|
||||
* Points to a "tmpfs" file system for system packages to place runtime data, socket files, and similar.
|
||||
*/
|
||||
val RUN = AbsolutePath("/run")
|
||||
|
||||
/**
|
||||
* Points to a directory containing per-user runtime directories,
|
||||
* each usually individually mounted "tmpfs" instances.
|
||||
*/
|
||||
val RUN_USER: AbsolutePath = RUN + "user/"
|
||||
|
||||
/**
|
||||
* Points to persistent, variable system data. Writable during normal system operation.
|
||||
*/
|
||||
val VAR = AbsolutePath("/var/")
|
||||
|
||||
/**
|
||||
* Points to persistent system data.
|
||||
*/
|
||||
val VAR_LIB: AbsolutePath = VAR + "lib/"
|
||||
|
||||
/**
|
||||
* Points to a nonstandard directory that is usually empty.
|
||||
*/
|
||||
val VAR_EMPTY: AbsolutePath = VAR + "empty/"
|
||||
|
||||
/**
|
||||
* Points to the root directory for device nodes.
|
||||
*/
|
||||
val DEV = AbsolutePath("/dev/")
|
||||
|
||||
/**
|
||||
* Points to a virtual kernel file system exposing the process list and other functionality.
|
||||
*/
|
||||
val PROC = AbsolutePath("/proc/")
|
||||
|
||||
/**
|
||||
* Points to a hierarchy below `/proc/` that exposes a number of kernel tunables.
|
||||
*/
|
||||
val PROC_SYS: AbsolutePath = PROC + "sys/"
|
||||
|
||||
/**
|
||||
* Points to a virtual kernel file system exposing discovered devices and other functionality.
|
||||
*/
|
||||
val SYS = AbsolutePath("/sys")
|
||||
/**
|
||||
* Holds a pathname checked to be absolute.
|
||||
* @constructor checks pathname and returns a new [AbsolutePath] if pathname is absolute.
|
||||
*/
|
||||
@Serializable(with = AbsolutePathSerializer::class)
|
||||
data class AbsolutePath(val pathname: String, @Transient val path: Path = Path.of(pathname)) {
|
||||
@@ -17,16 +78,19 @@ data class AbsolutePath(val pathname: String, @Transient val path: Path = Path.o
|
||||
throw AbsolutePathException(pathname)
|
||||
}
|
||||
}
|
||||
//TODO discuss if we should keep this operator overloading around, i think it makes things cleaner but ik ozy doesn't like operator overloading
|
||||
operator fun plus(other: String): AbsolutePath {
|
||||
return AbsolutePath(pathname + other)
|
||||
}
|
||||
operator fun plus(other: AbsolutePath): AbsolutePath {
|
||||
return AbsolutePath(pathname + other.pathname)
|
||||
}
|
||||
companion object {
|
||||
fun isAbsolute(pathname: String): Boolean {
|
||||
return Path.of(pathname).isAbsolute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object AbsolutePathSerializer : KSerializer<AbsolutePath> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(this::class.qualifiedName!!, PrimitiveKind.STRING)
|
||||
override fun serialize(encoder: Encoder, value: AbsolutePath) {
|
||||
@@ -40,12 +104,24 @@ object AbsolutePathSerializer : KSerializer<AbsolutePath> {
|
||||
}
|
||||
|
||||
/**
|
||||
* AbsolutePathException is returned by @see AbsolutePath() and holds the invalid pathname.
|
||||
* Returned by [AbsolutePath()] and holds the invalid pathname.
|
||||
*/
|
||||
data class AbsolutePathException(val pathname: String) : IllegalArgumentException("Path $pathname is not absolute")
|
||||
|
||||
@Serializable sealed interface FilesystemConfig
|
||||
|
||||
/**
|
||||
* Represents a host to container bind mount.
|
||||
* @param target mount point in container, same as source if empty
|
||||
* @param source host filesystem path to make available to the container
|
||||
* @param write do not mount target read only
|
||||
* @param device do not disable device files on target, implies write
|
||||
* @param ensure create source as a directory if it does not exist
|
||||
* @param optional skip this mount point if source does not exist
|
||||
* @param special enable special behavior:
|
||||
* for autoroot, target must be set to [Filesystem.ROOT];
|
||||
* for autoetc, target must be set to [Filesystem.ETC]
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("bind")
|
||||
data class FSBind(
|
||||
@@ -58,6 +134,13 @@ data class FSBind(
|
||||
val special: Boolean? = null,
|
||||
) : FilesystemConfig
|
||||
|
||||
/**
|
||||
* Represents an ephemeral (temporary) container mount point.
|
||||
* @param target mount point in container
|
||||
* @param write do not mount filesystem read-only
|
||||
* @param size upper limit on the size of the filesystem
|
||||
* @param perm initial permission bits of the new filesystem
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("ephemeral")
|
||||
data class FSEphemeral(
|
||||
@@ -67,6 +150,12 @@ data class FSEphemeral(
|
||||
val perm: Int,
|
||||
) : FilesystemConfig
|
||||
|
||||
/**
|
||||
* Represents a symlink in the container filesystem.
|
||||
* @param target link path in container
|
||||
* @param linkname linkname the symlink points to
|
||||
* @param dereference whether to dereference linkname before creating the link
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("link")
|
||||
data class FSLink(
|
||||
@@ -75,11 +164,18 @@ data class FSLink(
|
||||
val dereference: Boolean,
|
||||
) : FilesystemConfig
|
||||
|
||||
/**
|
||||
* Represents an overlay mount point.
|
||||
* @param target mount point in container
|
||||
* @param lower any filesystem, does not need to be on a writable filesystem
|
||||
* @param upper the upperdir is normally on a writable filesystem, leave as null to mount Lower readonly
|
||||
* @param work the workdir needs to be an empty directory on the same filesystem as `upper`, must not be null if `upper` is populated
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("overlay")
|
||||
data class FSOverlay(
|
||||
@SerialName("dst") val target: AbsolutePath,
|
||||
val lower: List<AbsolutePath>,
|
||||
val upper: AbsolutePath,
|
||||
val work: AbsolutePath,
|
||||
val upper: AbsolutePath? = null,
|
||||
val work: AbsolutePath? = null,
|
||||
) : FilesystemConfig
|
||||
@@ -1,19 +1,38 @@
|
||||
package moe.rosa.planterette.hakurei
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import java.time.Duration
|
||||
|
||||
val WAIT_DELAY_DEFAULT = Duration.ofSeconds(1)!!
|
||||
val WAIT_DELAY_MAX = Duration.ofSeconds(30)!!
|
||||
|
||||
const val IDENTITY_MIN = 0
|
||||
const val IDENTITY_MAX = 9999
|
||||
|
||||
/**
|
||||
* [HakureiConfig] configures an application container.
|
||||
* @param id Reverse-DNS style configured arbitrary identifier string.
|
||||
* Passed to wayland security-context-v1 and used as part of defaults in dbus session proxy.
|
||||
* @param enablements System services to make available in the container.
|
||||
* @param sessionBus Session D-Bus proxy configuration.
|
||||
* If set to null, session bus proxy assume built-in defaults.
|
||||
* @param systemBus System D-Bus proxy configuration.
|
||||
* If set to nil, system bus proxy is disabled.
|
||||
* @param directWayland Direct access to wayland socket, no attempt is made to attach security-context-v1
|
||||
* and the bare socket is made available to the container.
|
||||
* @param extraPerms Extra acl update ops to perform before setuid.
|
||||
* @param identity Numerical application id, passed to hsu, used to derive init user namespace credentials.
|
||||
* @param groups Init user namespace supplementary groups inherited by all container processes.
|
||||
* @param container High level container configuration.
|
||||
*/
|
||||
@Serializable
|
||||
data class HakureiConfig(
|
||||
var id: String? = null,
|
||||
var path: AbsolutePath? = null,
|
||||
var args: List<String>? = null,
|
||||
|
||||
var enablements: Enablements? = null,
|
||||
@SerialName("session_bus") var sessionBus: DBusConfig? = null,
|
||||
@SerialName("system_bus") var systemBus: DBusConfig? = null,
|
||||
@SerialName("direct_wayland") var directWayland: Boolean? = null,
|
||||
var username: String? = null,
|
||||
var shell: AbsolutePath? = null,
|
||||
var home: AbsolutePath? = null,
|
||||
|
||||
@SerialName("extra_perms") var extraPerms: List<ExtraPermsConfig>? = null,
|
||||
var identity: Int? = null,
|
||||
@@ -22,6 +41,36 @@ data class HakureiConfig(
|
||||
var container: ContainerConfig? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* Describes the container configuration to be applied to the container.
|
||||
* @param hostname Container UTS namespace hostname.
|
||||
* @param waitDelay Duration in nanoseconds to wait for after interrupting the initial process.
|
||||
* Defaults to [WAIT_DELAY_DEFAULT] if less than or equals to zero,
|
||||
* or [WAIT_DELAY_MAX] if greater than [WAIT_DELAY_MAX].
|
||||
*
|
||||
* @param seccompCompat Emit Flatpak-compatible seccomp filter programs.
|
||||
* @param devel Allow ptrace and friends.
|
||||
* @param userns Allow userns creation and container setup syscalls.
|
||||
* @param hostNet Share host net namespace.
|
||||
* @param hostAbstract Share abstract unix socket scope.
|
||||
* @param tty Allow dangerous terminal I/O (faking input).
|
||||
* @param multiarch Allow multiarch.
|
||||
*
|
||||
* @param env Initial process environment variables.
|
||||
*
|
||||
* @param mapRealUid Map target user uid to privileged user uid in the container user namespace.
|
||||
* Some programs fail to connect to dbus session running as a different uid,
|
||||
* this option works around it by mapping priv-side caller uid in container.
|
||||
*
|
||||
* @param device Mount `/dev/` from the init mount namespace as-is in the container mount namespace.
|
||||
* @param filesystem Container mount points.
|
||||
* If the first element targets /, it is inserted early and excluded from path hiding.
|
||||
* @param username String used as the username of the emulated user, validated against the default `NAME_REGEX` from adduser.
|
||||
* @param shell Pathname of shell in the container filesystem to use for the emulated user.
|
||||
* @param home Directory in the container filesystem to enter and use as the home directory of the emulated user.
|
||||
* @param path Pathname to executable file in the container filesystem.
|
||||
* @param args Final args passed to the initial program.
|
||||
*/
|
||||
@Serializable
|
||||
data class ContainerConfig(
|
||||
var hostname: String? = null,
|
||||
@@ -40,8 +89,17 @@ data class ContainerConfig(
|
||||
var device: Boolean? = null,
|
||||
|
||||
var filesystem: List<FilesystemConfig>? = null,
|
||||
|
||||
var username: String? = "chronos",
|
||||
var shell: AbsolutePath? = null,
|
||||
var home: AbsolutePath? = null,
|
||||
var path: AbsolutePath? = null,
|
||||
var args: List<String>? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* Describes an acl update op.
|
||||
*/
|
||||
@Serializable
|
||||
data class ExtraPermsConfig(
|
||||
var ensure: Boolean? = null,
|
||||
@@ -71,6 +129,16 @@ data class ExtraPermsConfig(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the `xdg-dbus-proxy` process.
|
||||
* @param see Set `see` policy for `NAME` (`--see=NAME`)
|
||||
* @param talk Set `talk` policy for `NAME` (`--talk=NAME`)
|
||||
* @param own Set `own` policy for `NAME` (`--own=NAME)
|
||||
* @param call Set `RULE` for calls on `NAME` (`--call=NAME=RULE`)
|
||||
* @param broadcast Set `RULE` for broadcasts from `NAME` (`--broadcast=NAME=RULE`)
|
||||
* @param log Turn on logging (`--log`)
|
||||
* @param filter Enable filtering (`--filter`)
|
||||
*/
|
||||
@Serializable
|
||||
data class DBusConfig(
|
||||
var see: List<String>? = null,
|
||||
@@ -82,6 +150,9 @@ data class DBusConfig(
|
||||
var filter: Boolean? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* Represents an optional host service to export to the target user.
|
||||
*/
|
||||
@Serializable
|
||||
data class Enablements(
|
||||
var wayland: Boolean? = null,
|
||||
|
||||
@@ -7,13 +7,7 @@ class DSLTest {
|
||||
companion object {
|
||||
val HAKUREI_DSL_TEST = planterette {
|
||||
hakurei("org.chromium.Chromium") {
|
||||
executable("/run/current-system/sw/bin/chromium",
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
)
|
||||
|
||||
enable(Wayland, DBus, Pulse)
|
||||
dbus {
|
||||
session {
|
||||
@@ -38,9 +32,7 @@ class DSLTest {
|
||||
filter()
|
||||
}
|
||||
}
|
||||
username("chronos")
|
||||
shell("/run/current-system/sw/bin/zsh")
|
||||
home("/data/data/org.chromium.Chromium")
|
||||
|
||||
extraPerms(
|
||||
perm("/var/lib/hakurei/u0") {
|
||||
ensure()
|
||||
@@ -67,6 +59,16 @@ class DSLTest {
|
||||
"GOOGLE_DEFAULT_CLIENT_SECRET" to "OTJgUOQcT7lO7GsGZq2G4IlT")
|
||||
mapRealUid()
|
||||
device()
|
||||
executable("/run/current-system/sw/bin/chromium",
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
)
|
||||
username("chronos")
|
||||
shell("/run/current-system/sw/bin/zsh")
|
||||
home("/data/data/org.chromium.Chromium")
|
||||
filesystem {
|
||||
bind("/var/lib/hakurei/base/org.debian" to "/") {
|
||||
write()
|
||||
@@ -80,11 +82,10 @@ class DSLTest {
|
||||
perm(493)
|
||||
}
|
||||
overlay("/nix/store") {
|
||||
lower("/mnt-root/nix/.ro-store")
|
||||
upper("/mnt-root/nix/.rw-store/upper")
|
||||
work("/mnt-root/nix/.rw-store/work")
|
||||
lower("/var/lib/hakurei/base/org.nixos/ro-store")
|
||||
upper("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper")
|
||||
work("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work")
|
||||
}
|
||||
bind("/nix/store")
|
||||
link("/run/current-system") {
|
||||
dereference()
|
||||
}
|
||||
|
||||
@@ -8,14 +8,7 @@ class HakureiTest {
|
||||
companion object {
|
||||
val TEMPLATE_DATA = HakureiConfig(
|
||||
id = "org.chromium.Chromium",
|
||||
path = AbsolutePath("/run/current-system/sw/bin/chromium"),
|
||||
args = listOf(
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
),
|
||||
|
||||
enablements = Enablements(
|
||||
wayland = true,
|
||||
dbus = true,
|
||||
@@ -57,9 +50,7 @@ class HakureiTest {
|
||||
broadcast = null,
|
||||
filter = true
|
||||
),
|
||||
username = "chronos",
|
||||
shell = AbsolutePath("/run/current-system/sw/bin/zsh"),
|
||||
home = AbsolutePath("/data/data/org.chromium.Chromium"),
|
||||
|
||||
extraPerms = listOf(
|
||||
ExtraPermsConfig(
|
||||
ensure = true,
|
||||
@@ -119,13 +110,10 @@ class HakureiTest {
|
||||
FSOverlay(
|
||||
target = AbsolutePath("/nix/store"),
|
||||
lower = listOf(
|
||||
AbsolutePath("/mnt-root/nix/.ro-store")
|
||||
AbsolutePath("/var/lib/hakurei/base/org.nixos/ro-store")
|
||||
),
|
||||
upper = AbsolutePath("/mnt-root/nix/.rw-store/upper"),
|
||||
work = AbsolutePath("/mnt-root/nix/.rw-store/work")
|
||||
),
|
||||
FSBind(
|
||||
source = AbsolutePath("/nix/store")
|
||||
upper = AbsolutePath("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
|
||||
work = AbsolutePath("/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work")
|
||||
),
|
||||
FSLink(
|
||||
target = AbsolutePath("/run/current-system"),
|
||||
@@ -148,7 +136,19 @@ class HakureiTest {
|
||||
device = true,
|
||||
optional = true
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
username = "chronos",
|
||||
shell = AbsolutePath("/run/current-system/sw/bin/zsh"),
|
||||
home = AbsolutePath("/data/data/org.chromium.Chromium"),
|
||||
path = AbsolutePath("/run/current-system/sw/bin/chromium"),
|
||||
args = listOf(
|
||||
"chromium",
|
||||
"--ignore-gpu-blocklist",
|
||||
"--disable-smooth-scrolling",
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
),
|
||||
)
|
||||
)
|
||||
val TEMPLATE_JSON = ProcessBuilder("hakurei", "template")
|
||||
|
||||
Reference in New Issue
Block a user