internal/outcome: populate instance metadata for PipeWire
All checks were successful
Test / Create distribution (push) Successful in 1m10s
Test / Hakurei (push) Successful in 12m25s
Test / Sandbox (push) Successful in 1m40s
Test / Sandbox (race detector) (push) Successful in 2m29s
Test / Hakurei (race detector) (push) Successful in 4m54s
Test / Hpkg (push) Successful in 3m56s
Test / Flake checks (push) Successful in 2m42s

These have similar semantics to equivalent Wayland security-context-v1 fields.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-12-10 03:01:30 +09:00
parent f8b3db3f66
commit b72d502f1c
5 changed files with 89 additions and 14 deletions

View File

@@ -68,7 +68,11 @@ func TestOutcomeRun(t *testing.T) {
). ).
// spPipeWireOp // spPipeWireOp
PipeWire(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pipewire")). PipeWire(
m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pipewire"),
"org.chromium.Chromium",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
).
// spDBusOp // spDBusOp
MustProxyDBus( MustProxyDBus(
@@ -335,7 +339,7 @@ func TestOutcomeRun(t *testing.T) {
Ensure(m("/tmp/hakurei.0/tmpdir/9"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read, acl.Write, acl.Execute). Ensure(m("/tmp/hakurei.0/tmpdir/9"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read, acl.Write, acl.Execute).
Ephemeral(system.Process, m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c"), 0711). Ephemeral(system.Process, m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c"), 0711).
Wayland(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/1971/wayland-0"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c"). Wayland(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/1971/wayland-0"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
PipeWire(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/pipewire")). PipeWire(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/pipewire"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
MustProxyDBus(&hst.BusConfig{ MustProxyDBus(&hst.BusConfig{
Talk: []string{ Talk: []string{
"org.freedesktop.Notifications", "org.freedesktop.Notifications",
@@ -486,7 +490,7 @@ func TestOutcomeRun(t *testing.T) {
Ensure(m("/run/user/1971/hakurei"), 0700).UpdatePermType(system.User, m("/run/user/1971/hakurei"), acl.Execute). Ensure(m("/run/user/1971/hakurei"), 0700).UpdatePermType(system.User, m("/run/user/1971/hakurei"), acl.Execute).
UpdatePermType(hst.EWayland, m("/run/user/1971/wayland-0"), acl.Read, acl.Write, acl.Execute). UpdatePermType(hst.EWayland, m("/run/user/1971/wayland-0"), acl.Read, acl.Write, acl.Execute).
Ephemeral(system.Process, m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1"), 0711). Ephemeral(system.Process, m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1"), 0711).
PipeWire(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire")). PipeWire(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire"), "org.chromium.Chromium", "8e2c76b066dabe574cf073bdb46eb5c1").
MustProxyDBus(&hst.BusConfig{ MustProxyDBus(&hst.BusConfig{
Talk: []string{ Talk: []string{
"org.freedesktop.FileManager1", "org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.Notifications",

View File

@@ -18,7 +18,12 @@ func (s spPipeWireOp) toSystem(state *outcomeStateSys) error {
return errNotEnabled return errNotEnabled
} }
state.sys.PipeWire(state.instance().Append("pipewire")) appId := state.appId
if appId == "" {
// use instance ID in case app id is not set
appId = "app.hakurei." + state.id.String()
}
state.sys.PipeWire(state.instance().Append("pipewire"), appId, state.id.String())
return nil return nil
} }

View File

@@ -30,7 +30,9 @@ func TestSpPipeWireOp(t *testing.T) {
Ephemeral(system.Process, m(wantInstancePrefix), 0711). Ephemeral(system.Process, m(wantInstancePrefix), 0711).
// toSystem // toSystem
PipeWire( PipeWire(
m(wantInstancePrefix + "/pipewire"), m(wantInstancePrefix+"/pipewire"),
"org.chromium.Chromium",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
), sysUsesInstance(nil), nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ ), sysUsesInstance(nil), nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{
// this op configures the container state and does not make calls during toContainer // this op configures the container state and does not make calls during toContainer
}, &container.Params{ }, &container.Params{

View File

@@ -14,8 +14,8 @@ import (
// PipeWire maintains a pipewire socket with SecurityContext attached via [pipewire]. // PipeWire maintains a pipewire socket with SecurityContext attached via [pipewire].
// The socket stops accepting connections once the pipe referred to by sync is closed. // The socket stops accepting connections once the pipe referred to by sync is closed.
// The socket is pathname only and is destroyed on revert. // The socket is pathname only and is destroyed on revert.
func (sys *I) PipeWire(dst *check.Absolute) *I { func (sys *I) PipeWire(dst *check.Absolute, appID, instanceID string) *I {
sys.ops = append(sys.ops, &pipewireOp{nil, dst}) sys.ops = append(sys.ops, &pipewireOp{nil, dst, appID, instanceID})
return sys return sys
} }
@@ -23,6 +23,8 @@ func (sys *I) PipeWire(dst *check.Absolute) *I {
type pipewireOp struct { type pipewireOp struct {
scc io.Closer scc io.Closer
dst *check.Absolute dst *check.Absolute
appID, instanceID string
} }
func (p *pipewireOp) Type() hst.Enablement { return Process } func (p *pipewireOp) Type() hst.Enablement { return Process }
@@ -56,6 +58,8 @@ func (p *pipewireOp) apply(sys *I) (err error) {
if p.scc, err = securityContext.BindAndCreate(p.dst.String(), pipewire.SPADict{ if p.scc, err = securityContext.BindAndCreate(p.dst.String(), pipewire.SPADict{
{Key: pipewire.PW_KEY_SEC_ENGINE, Value: "app.hakurei"}, {Key: pipewire.PW_KEY_SEC_ENGINE, Value: "app.hakurei"},
{Key: pipewire.PW_KEY_SEC_APP_ID, Value: p.appID},
{Key: pipewire.PW_KEY_SEC_INSTANCE_ID, Value: p.instanceID},
{Key: pipewire.PW_KEY_ACCESS, Value: "restricted"}, {Key: pipewire.PW_KEY_ACCESS, Value: "restricted"},
}); err != nil { }); err != nil {
return newOpError("pipewire", err, false) return newOpError("pipewire", err, false)
@@ -92,7 +96,9 @@ func (p *pipewireOp) revert(sys *I, _ *Criteria) error {
func (p *pipewireOp) Is(o Op) bool { func (p *pipewireOp) Is(o Op) bool {
target, ok := o.(*pipewireOp) target, ok := o.(*pipewireOp)
return ok && p != nil && target != nil && return ok && p != nil && target != nil &&
p.dst.Is(target.dst) p.dst.Is(target.dst) &&
p.appID == target.appID &&
p.instanceID == target.instanceID
} }
func (p *pipewireOp) Path() string { return p.dst.String() } func (p *pipewireOp) Path() string { return p.dst.String() }

View File

@@ -18,6 +18,8 @@ func TestPipeWireOp(t *testing.T) {
checkOpBehaviour(t, checkNoParallel, []opBehaviourTestCase{ checkOpBehaviour(t, checkNoParallel, []opBehaviourTestCase{
{"success", 0xbeef, 0xff, &pipewireOp{nil, {"success", 0xbeef, 0xff, &pipewireOp{nil,
m(path.Join(t.TempDir(), "pipewire")), m(path.Join(t.TempDir(), "pipewire")),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c",
}, []stub.Call{ }, []stub.Call{
call("pipewireConnect", stub.ExpectArgs{}, func() *pipewire.Context { call("pipewireConnect", stub.ExpectArgs{}, func() *pipewire.Context {
if ctx, err := pipewire.New(&stubPipeWireConn{sendmsg: []string{ if ctx, err := pipewire.New(&stubPipeWireConn{sendmsg: []string{
@@ -154,11 +156,11 @@ func TestPipeWireOp(t *testing.T) {
string([]byte{ string([]byte{
// header: SecurityContext::Create // header: SecurityContext::Create
3, 0, 0, 0, 3, 0, 0, 0,
0xa8, 0, 0, 1, 0x40, 1, 0, 1,
5, 0, 0, 0, 5, 0, 0, 0,
2, 0, 0, 0, 2, 0, 0, 0,
// Struct // Struct
0xa0, 0, 0, 0, 0x38, 1, 0, 0,
0xe, 0, 0, 0, 0xe, 0, 0, 0,
// Fd: listen_fd = 1 // Fd: listen_fd = 1
8, 0, 0, 0, 8, 0, 0, 0,
@@ -171,12 +173,12 @@ func TestPipeWireOp(t *testing.T) {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// Struct: spa_dict // Struct: spa_dict
0x78, 0, 0, 0, 0x10, 1, 0, 0,
0xe, 0, 0, 0, 0xe, 0, 0, 0,
// Int: n_items = 2 // Int: n_items = 4
4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0,
2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// String: key = "pipewire.sec.engine" // String: key = "pipewire.sec.engine"
0x14, 0, 0, 0, 0x14, 0, 0, 0,
@@ -194,6 +196,48 @@ func TestPipeWireOp(t *testing.T) {
0x68, 0x61, 0x6b, 0x75, 0x68, 0x61, 0x6b, 0x75,
0x72, 0x65, 0x69, 0, 0x72, 0x65, 0x69, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// String: key = "pipewire.sec.app-id"
0x14, 0, 0, 0,
8, 0, 0, 0,
0x70, 0x69, 0x70, 0x65,
0x77, 0x69, 0x72, 0x65,
0x2e, 0x73, 0x65, 0x63,
0x2e, 0x61, 0x70, 0x70,
0x2d, 0x69, 0x64, 0,
0, 0, 0, 0,
// String: value = "org.chromium.Chromium"
0x16, 0, 0, 0,
8, 0, 0, 0,
0x6f, 0x72, 0x67, 0x2e,
0x63, 0x68, 0x72, 0x6f,
0x6d, 0x69, 0x75, 0x6d,
0x2e, 0x43, 0x68, 0x72,
0x6f, 0x6d, 0x69, 0x75,
// String: key = "pipewire.sec.instance-id"
0x6d, 0, 0, 0,
0x19, 0, 0, 0,
8, 0, 0, 0,
0x70, 0x69, 0x70, 0x65,
0x77, 0x69, 0x72, 0x65,
0x2e, 0x73, 0x65, 0x63,
0x2e, 0x69, 0x6e, 0x73,
0x74, 0x61, 0x6e, 0x63,
0x65, 0x2d, 0x69, 0x64,
0, 0, 0, 0,
0, 0, 0, 0,
// String: value = "ebf083d1b175911782d413369b64ce7c"
0x21, 0, 0, 0,
8, 0, 0, 0,
0x65, 0x62, 0x66, 0x30,
0x38, 0x33, 0x64, 0x31,
0x62, 0x31, 0x37, 0x35,
0x39, 0x31, 0x31, 0x37,
0x38, 0x32, 0x64, 0x34,
0x31, 0x33, 0x33, 0x36,
0x39, 0x62, 0x36, 0x34,
0x63, 0x65, 0x37, 0x63,
0, 0, 0, 0,
0, 0, 0, 0,
// String: key = "pipewire.access" // String: key = "pipewire.access"
0x10, 0, 0, 0, 0x10, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0,
@@ -386,29 +430,43 @@ func TestPipeWireOp(t *testing.T) {
checkOpsBuilder(t, "PipeWire", []opsBuilderTestCase{ checkOpsBuilder(t, "PipeWire", []opsBuilderTestCase{
{"sample", 0xcafe, func(_ *testing.T, sys *I) { {"sample", 0xcafe, func(_ *testing.T, sys *I) {
sys.PipeWire(m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire")) sys.PipeWire(m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c")
}, []Op{&pipewireOp{nil, }, []Op{&pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c",
}}, stub.Expect{}}, }}, stub.Expect{}},
}) })
checkOpIs(t, []opIsTestCase{ checkOpIs(t, []opIsTestCase{
{"dst differs", &pipewireOp{nil, {"dst differs", &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7d/pipewire"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7d/pipewire"),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c",
}, &pipewireOp{nil, }, &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c",
}, false}, }, false},
{"equals", &pipewireOp{nil, {"equals", &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c",
}, &pipewireOp{nil, }, &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c",
}, true}, }, true},
}) })
checkOpMeta(t, []opMetaTestCase{ checkOpMeta(t, []opMetaTestCase{
{"sample", &pipewireOp{nil, {"sample", &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
"org.chromium.Chromium",
"ebf083d1b175911782d413369b64ce7c",
}, Process, "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire", }, Process, "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire",
`pipewire socket at "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"`}, `pipewire socket at "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"`},
}) })