Compare commits
3 Commits
ca586aaa36
...
d7193b6a5f
Author | SHA1 | Date | |
---|---|---|---|
d7193b6a5f | |||
f369e5f6c5 | |||
d3da1c57f8 |
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,14 +1,12 @@
|
|||||||
.gradle
|
.gradle
|
||||||
|
gradlew.bat
|
||||||
build/
|
build/
|
||||||
!gradle/wrapper/gradle-wrapper.jar
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
!**/src/main/**/build/
|
!**/src/main/**/build/
|
||||||
!**/src/test/**/build/
|
!**/src/test/**/build/
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
### IntelliJ IDEA ###
|
||||||
.idea/modules.xml
|
/.idea/
|
||||||
.idea/jarRepositories.xml
|
|
||||||
.idea/compiler.xml
|
|
||||||
.idea/libraries/
|
|
||||||
*.iws
|
*.iws
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
@ -43,5 +41,3 @@ bin/
|
|||||||
|
|
||||||
### Mac OS ###
|
### Mac OS ###
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/app/src/test/resources/debian-images/
|
|
||||||
/app/src/test/resources/squashfs-root/
|
|
||||||
|
8
.idea/artifacts/api_jvm.xml
generated
8
.idea/artifacts/api_jvm.xml
generated
@ -1,8 +0,0 @@
|
|||||||
<component name="ArtifactManager">
|
|
||||||
<artifact type="jar" name="api-jvm">
|
|
||||||
<output-path>$PROJECT_DIR$/api/build/libs</output-path>
|
|
||||||
<root id="archive" name="api-jvm.jar">
|
|
||||||
<element id="module-output" name="planterette.api.jvmMain" />
|
|
||||||
</root>
|
|
||||||
</artifact>
|
|
||||||
</component>
|
|
12
.idea/kotlinc.xml
generated
12
.idea/kotlinc.xml
generated
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Kotlin2JsCompilerArguments">
|
|
||||||
<option name="moduleKind" value="plain" />
|
|
||||||
</component>
|
|
||||||
<component name="Kotlin2JvmCompilerArguments">
|
|
||||||
<option name="jvmTarget" value="1.8" />
|
|
||||||
</component>
|
|
||||||
<component name="KotlinJpsPluginSettings">
|
|
||||||
<option name="version" value="2.2.0" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -3,7 +3,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain(21)
|
jvmToolchain(24)
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Tue Aug 26 23:15:20 CDT 2025
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
@ -1,47 +1,48 @@
|
|||||||
package app.hakurei.planterette.api
|
package app.hakurei.planterette.api
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
object Paths {
|
object Paths {
|
||||||
const val FHSRoot = "/"
|
const val FHS_ROOT = "/"
|
||||||
const val FHSEtc = "/etc/"
|
const val FHS_ETC = "/etc/"
|
||||||
const val FHSTmp = "/tmp/"
|
const val FHS_TMP = "/tmp/"
|
||||||
|
|
||||||
const val FHSRun = "/run/"
|
const val FHS_RUN = "/run/"
|
||||||
const val FHSRunUser = FHSRun + "user/"
|
const val FHS_RUN_USER = FHS_RUN + "user/"
|
||||||
|
|
||||||
const val FHSUsr = "/usr/"
|
const val FHS_USR = "/usr/"
|
||||||
const val FHSUsrBin = FHSUsr + "bin/"
|
const val FHS_USR_BIN = FHS_USR + "bin/"
|
||||||
|
|
||||||
const val FHSVar = "/var/"
|
const val FHS_VAR = "/var/"
|
||||||
const val FHSVarLib = FHSVar + "lib/"
|
const val FHS_VAR_LIB = FHS_VAR + "lib/"
|
||||||
const val FHSVarEmpty = FHSVar + "empty/"
|
const val FHS_VAR_EMPTY = FHS_VAR + "empty/"
|
||||||
|
|
||||||
const val FHSDev = "/dev/"
|
const val FHS_DEV = "/dev/"
|
||||||
const val FHSProc = "/proc/"
|
const val FHS_PROC = "/proc/"
|
||||||
const val FHSProcSys = FHSProc + "sys/"
|
const val FHS_PROC_SYS = FHS_PROC + "sys/"
|
||||||
const val FHSSys = "/sys/"
|
const val FHS_SYS = "/sys/"
|
||||||
|
|
||||||
const val Nonexistent = FHSProc + "nonexistent"
|
const val NONEXISTENT = FHS_PROC + "nonexistent"
|
||||||
const val sysrootDir = "sysroot"
|
const val SYSROOT_DIR = "sysroot"
|
||||||
const val hostDir = "host"
|
const val HOST_DIR = "host"
|
||||||
const val hostPath = FHSRoot + hostDir
|
const val HOST_PATH = FHS_ROOT + HOST_DIR
|
||||||
const val sysrootPath = FHSRoot + sysrootDir
|
const val SYSROOT_PATH = FHS_ROOT + SYSROOT_DIR
|
||||||
|
|
||||||
val AbsFHSRoot = AbsolutePath(FHSRoot)
|
val AbsFHSRoot = AbsolutePath(FHS_ROOT)
|
||||||
val AbsFHSEtc = AbsolutePath(FHSEtc)
|
val AbsFHSEtc = AbsolutePath(FHS_ETC)
|
||||||
val AbsFHSTmp = AbsolutePath(FHSTmp)
|
val AbsFHSTmp = AbsolutePath(FHS_TMP)
|
||||||
|
|
||||||
val AbsFHSRun = AbsolutePath(FHSRun)
|
val AbsFHSRun = AbsolutePath(FHS_RUN)
|
||||||
val AbsFHSRunUser = AbsolutePath(FHSRunUser)
|
val AbsFHSRunUser = AbsolutePath(FHS_RUN_USER)
|
||||||
|
|
||||||
val AbsFHSUsrBin = AbsolutePath(FHSUsrBin)
|
val AbsFHSUsrBin = AbsolutePath(FHS_USR_BIN)
|
||||||
|
|
||||||
val AbsFHSVar = AbsolutePath(FHSVar)
|
val AbsFHSVar = AbsolutePath(FHS_VAR)
|
||||||
val AbsFHSVarLib = AbsolutePath(FHSVarLib)
|
val AbsFHSVarLib = AbsolutePath(FHS_VAR_LIB)
|
||||||
|
|
||||||
val AbsFHSDev = AbsolutePath(FHSDev)
|
val AbsFHSDev = AbsolutePath(FHS_DEV)
|
||||||
val AbsFHSProc = AbsolutePath(FHSProc)
|
val AbsFHSProc = AbsolutePath(FHS_PROC)
|
||||||
val AbsFHSSys = AbsolutePath(FHSSys)
|
val AbsFHSSys = AbsolutePath(FHS_SYS)
|
||||||
|
|
||||||
val AbsNonexistent = AbsolutePath(Nonexistent)
|
val AbsNonexistent = AbsolutePath(NONEXISTENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,5 @@
|
|||||||
package app.hakurei.planterette.api
|
package app.hakurei.planterette.api
|
||||||
|
|
||||||
import kotlinx.io.Buffer
|
|
||||||
import kotlinx.io.buffered
|
|
||||||
import kotlinx.io.files.Path
|
|
||||||
import kotlinx.io.files.SystemFileSystem
|
|
||||||
import kotlinx.io.readString
|
|
||||||
|
|
||||||
object Util {
|
|
||||||
fun readFileToString(path: String): String {
|
|
||||||
val buffer = Buffer()
|
|
||||||
val source = SystemFileSystem.source(Path(path))
|
|
||||||
source.buffered().transferTo(buffer)
|
|
||||||
return buffer.readString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <T> Array<out T>.orOf(selector: (T) -> Int): Int {
|
inline fun <T> Array<out T>.orOf(selector: (T) -> Int): Int {
|
||||||
var sum = 0
|
var sum = 0
|
||||||
for (element in this) {
|
for (element in this) {
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package app.hakurei.planterette.api
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertIs
|
||||||
|
|
||||||
|
class AbsolutePathTest {
|
||||||
|
@Test
|
||||||
|
fun testAbsolutePath() {
|
||||||
|
val path = AbsolutePath("/dev/null")
|
||||||
|
assertIs<AbsolutePath>(path)
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun testRelativePath() {
|
||||||
|
assertFailsWith(AbsolutePathException::class) {
|
||||||
|
AbsolutePath("./test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun testPathJoin() {
|
||||||
|
val want = AbsolutePath("/dev/null")
|
||||||
|
val base = AbsolutePath("/dev/")
|
||||||
|
assertEquals(want, base + "null")
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
package app.hakurei.planterette.api
|
package app.hakurei.planterette.api
|
||||||
|
|
||||||
import app.hakurei.planterette.api.HakureiConfig.Enablement.*
|
import app.hakurei.planterette.api.HakureiConfig.Enablement.*
|
||||||
import app.hakurei.planterette.api.HakureiConfig.RootFlag
|
import app.hakurei.planterette.api.HakureiConfig.SeccompFilterPreset.*
|
||||||
|
import app.hakurei.planterette.api.HakureiConfig.HakureiExportFlag.*
|
||||||
|
import app.hakurei.planterette.api.HakureiConfig.RootFlag.*
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.serializer
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -146,8 +148,6 @@ class HakureiConfigTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@Test
|
|
||||||
fun testHakureiConfigSerialization() {
|
|
||||||
val testConfig = HakureiConfig(
|
val testConfig = HakureiConfig(
|
||||||
id = "org.chromium.Chromium",
|
id = "org.chromium.Chromium",
|
||||||
path = Paths.AbsFHSRun + "current-system/sw/bin/chromium",
|
path = Paths.AbsFHSRun + "current-system/sw/bin/chromium",
|
||||||
@ -160,21 +160,27 @@ class HakureiConfigTest {
|
|||||||
),
|
),
|
||||||
enablements = HakureiConfig.Enablement.enablements(Wayland, DBus, Pulse),
|
enablements = HakureiConfig.Enablement.enablements(Wayland, DBus, Pulse),
|
||||||
sessionBus = HakureiConfig.DbusConfig(
|
sessionBus = HakureiConfig.DbusConfig(
|
||||||
see = null,
|
talk = listOf(
|
||||||
talk = listOf("org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver"),
|
"org.freedesktop.Notifications",
|
||||||
own = listOf("org.chromium.Chromium.*", "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
"org.freedesktop.FileManager1",
|
||||||
"org.mpris.MediaPlayer2.chromium.*"),
|
"org.freedesktop.ScreenSaver",
|
||||||
|
"org.freedesktop.secrets",
|
||||||
|
"org.kde.kwalletd5",
|
||||||
|
"org.kde.kwalletd6",
|
||||||
|
"org.gnome.SessionManager"
|
||||||
|
),
|
||||||
|
own = listOf(
|
||||||
|
"org.chromium.Chromium.*",
|
||||||
|
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||||
|
"org.mpris.MediaPlayer2.chromium.*"
|
||||||
|
),
|
||||||
call = mapOf("org.freedesktop.portal.*" to "*"),
|
call = mapOf("org.freedesktop.portal.*" to "*"),
|
||||||
broadcast = mapOf("org.freedesktop.portal.*" to "@/org/freedesktop/portal/*"),
|
broadcast = mapOf("org.freedesktop.portal.*" to "@/org/freedesktop/portal/*"),
|
||||||
log = false,
|
log = false,
|
||||||
filter = true,
|
filter = true,
|
||||||
),
|
),
|
||||||
systemBus = HakureiConfig.DbusConfig(
|
systemBus = HakureiConfig.DbusConfig(
|
||||||
see = null,
|
|
||||||
talk = listOf("org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"),
|
talk = listOf("org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"),
|
||||||
own = null,
|
|
||||||
call = null,
|
|
||||||
broadcast = null,
|
|
||||||
log = false,
|
log = false,
|
||||||
filter = true,
|
filter = true,
|
||||||
),
|
),
|
||||||
@ -197,8 +203,8 @@ class HakureiConfigTest {
|
|||||||
net = true,
|
net = true,
|
||||||
device = true,
|
device = true,
|
||||||
waitDelay = -1,
|
waitDelay = -1,
|
||||||
seccompFlags = HakureiConfig.HakureiExportFlag.exportFlags(HakureiConfig.HakureiExportFlag.Multiarch),
|
seccompFlags = HakureiConfig.HakureiExportFlag.exportFlags(Multiarch),
|
||||||
seccompPresets = HakureiConfig.SeccompFilterPreset.filterPresets(HakureiConfig.SeccompFilterPreset.Ext),
|
seccompPresets = HakureiConfig.SeccompFilterPreset.filterPresets(Ext),
|
||||||
seccompCompat = true,
|
seccompCompat = true,
|
||||||
tty = true,
|
tty = true,
|
||||||
multiarch = true,
|
multiarch = true,
|
||||||
@ -217,14 +223,111 @@ class HakureiConfigTest {
|
|||||||
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSVarLib + "hakurei/u0/org.chromium.Chromium", dst = AbsolutePath("/data/data/org.chromium.Chromium"), write = true, must = true),
|
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSVarLib + "hakurei/u0/org.chromium.Chromium", dst = AbsolutePath("/data/data/org.chromium.Chromium"), write = true, must = true),
|
||||||
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSDev + "dri", device = true)
|
HakureiConfig.FilesystemConfig(src = Paths.AbsFHSDev + "dri", device = true)
|
||||||
),
|
),
|
||||||
link = listOf(HakureiConfig.LinkConfig(Paths.AbsFHSRunUser + "65534", Paths.FHSRunUser + "150")),
|
link = listOf(HakureiConfig.LinkConfig(Paths.AbsFHSRunUser + "65534", Paths.FHS_RUN_USER + "150")),
|
||||||
autoRoot = Paths.AbsFHSVarLib + "hakurei/base/org.debian",
|
autoRoot = Paths.AbsFHSVarLib + "hakurei/base/org.debian",
|
||||||
rootFlags = RootFlag.rootFlags(RootFlag.Writable),
|
rootFlags = HakureiConfig.RootFlag.rootFlags(Writable),
|
||||||
etc = Paths.AbsFHSEtc,
|
etc = Paths.AbsFHSEtc,
|
||||||
autoEtc = true
|
autoEtc = true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
println("printing for now until a more proper test can be written")
|
|
||||||
println(format.encodeToString(testConfig))
|
internal fun compare(want: HakureiConfig, test: HakureiConfig) {
|
||||||
|
assertEquals(want.id, test.id, "id")
|
||||||
|
|
||||||
|
assertEquals(want.path, test.path, "path")
|
||||||
|
assertEquals(want.args, test.args, "args")
|
||||||
|
|
||||||
|
assertEquals(want.enablements, test.enablements, "enablements")
|
||||||
|
|
||||||
|
assertEquals(want.sessionBus?.see, test.sessionBus?.see, "sessionBus.see")
|
||||||
|
assertEquals(want.sessionBus?.talk, test.sessionBus?.talk, "sessionBus.talk")
|
||||||
|
assertEquals(want.sessionBus?.own, test.sessionBus?.own, "sessionBus.own")
|
||||||
|
assertEquals(want.sessionBus?.broadcast, test.sessionBus?.broadcast, "sessionBus.broadcast")
|
||||||
|
assertEquals(want.sessionBus?.log ?: false, test.sessionBus?.log, "sessionBus.log")
|
||||||
|
assertEquals(want.sessionBus?.filter, test.sessionBus?.filter, "sessionBus.filter")
|
||||||
|
|
||||||
|
assertEquals(want.systemBus?.see, test.systemBus?.see, "systemBus.see")
|
||||||
|
assertEquals(want.systemBus?.talk, test.systemBus?.talk, "systemBus.talk")
|
||||||
|
assertEquals(want.systemBus?.own, test.systemBus?.own, "systemBus.own")
|
||||||
|
assertEquals(want.systemBus?.broadcast, test.systemBus?.broadcast, "systemBus.broadcast")
|
||||||
|
assertEquals(want.systemBus?.log ?: false, test.systemBus?.log, "systemBus.log")
|
||||||
|
assertEquals(want.systemBus?.filter, test.systemBus?.filter, "systemBus.filter")
|
||||||
|
|
||||||
|
assertEquals(want.directWayland ?: false, test.directWayland, "directWayland")
|
||||||
|
assertEquals(want.username, test.username, "username")
|
||||||
|
assertEquals(want.shell, test.shell, "shell")
|
||||||
|
assertEquals(want.data, test.data, "data")
|
||||||
|
assertEquals(want.dir, test.dir, "dir")
|
||||||
|
assertEquals(want.extraPerms, test.extraPerms, "extraPerms")
|
||||||
|
|
||||||
|
assertEquals(want.identity, test.identity, "identity")
|
||||||
|
assertEquals(want.groups, test.groups, "groups")
|
||||||
|
|
||||||
|
assertEquals(want.container.waitDelay, test.container.waitDelay, "waitDelay")
|
||||||
|
assertEquals(want.container.seccompFlags, test.container.seccompFlags, "seccompFlags")
|
||||||
|
assertEquals(want.container.seccompPresets, test.container.seccompPresets, "seccompPresets")
|
||||||
|
assertEquals(want.container.seccompCompat, test.container.seccompCompat, "seccompCompat")
|
||||||
|
|
||||||
|
assertEquals(want.container.devel, test.container.devel, "devel")
|
||||||
|
assertEquals(want.container.userns, test.container.userns, "userns")
|
||||||
|
assertEquals(want.container.net, test.container.net, "net")
|
||||||
|
assertEquals(want.container.tty, test.container.tty, "tty")
|
||||||
|
assertEquals(want.container.multiarch, test.container.multiarch, "multiarch")
|
||||||
|
|
||||||
|
assertEquals(want.container.env, test.container.env, "env")
|
||||||
|
assertEquals(want.container.mapRealUid, test.container.mapRealUid, "mapRealUid")
|
||||||
|
|
||||||
|
assertEquals(want.container.device, test.container.device, "device")
|
||||||
|
assertEquals(want.container.filesystem.size, test.container.filesystem.size, "filesystem.size")
|
||||||
|
for(i in 0 until want.container.filesystem.size) {
|
||||||
|
val w = want.container.filesystem[i]
|
||||||
|
val t = test.container.filesystem[i]
|
||||||
|
|
||||||
|
assertEquals(w.src, t.src, "filesystem[$i].src")
|
||||||
|
assertEquals(w.dst, t.dst, "filesystem[$i].dst")
|
||||||
|
assertEquals(w.write, t.write, "filesystem[$i].write")
|
||||||
|
assertEquals(w.device, t.device, "filesystem[$i].device")
|
||||||
|
assertEquals(w.must, t.must, "filesystem[$i].must")
|
||||||
|
}
|
||||||
|
assertEquals(want.container.link, test.container.link, "link")
|
||||||
|
assertEquals(want.container.autoRoot, test.container.autoRoot, "autoroot")
|
||||||
|
|
||||||
|
assertEquals(want.container.etc, test.container.etc, "etc")
|
||||||
|
|
||||||
|
assertEquals(want.container.autoEtc, test.container.autoEtc, "autoEtc")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testHakureiConfigSerialization() {
|
||||||
|
val json = format.encodeToString(testConfig)
|
||||||
|
val test = format.decodeFromString<HakureiConfig>(json)
|
||||||
|
assertEquals(testConfig, test)
|
||||||
|
val want = format.decodeFromString<HakureiConfig>(want)
|
||||||
|
|
||||||
|
compare(want, test)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEnablements() {
|
||||||
|
val enablement = HakureiConfig.Enablement.enablements(Wayland, X11, DBus, Pulse)
|
||||||
|
assertEquals(enablement, 0b1111)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSeccompFilterPresets() {
|
||||||
|
val presets = HakureiConfig.SeccompFilterPreset.filterPresets(Ext, DenyNS, DenyTTY, DenyDevel, Linux32)
|
||||||
|
assertEquals(presets, 0b11111)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExportFlags() {
|
||||||
|
val flags = HakureiConfig.HakureiExportFlag.exportFlags(Multiarch, CAN, Bluetooth)
|
||||||
|
assertEquals(flags, 0b111)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRootFlags() {
|
||||||
|
val flags = HakureiConfig.RootFlag.rootFlags(Optional, Writable, Device)
|
||||||
|
assertEquals(flags, 0b111)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user