internal/app: check transmitted ops
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Hakurei (push) Successful in 3m13s
Test / Hpkg (push) Successful in 4m5s
Test / Sandbox (race detector) (push) Successful in 4m28s
Test / Hakurei (race detector) (push) Successful in 5m23s
Test / Sandbox (push) Successful in 1m25s
Test / Flake checks (push) Successful in 1m33s
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Hakurei (push) Successful in 3m13s
Test / Hpkg (push) Successful in 4m5s
Test / Sandbox (race detector) (push) Successful in 4m28s
Test / Hakurei (race detector) (push) Successful in 5m23s
Test / Sandbox (push) Successful in 1m25s
Test / Flake checks (push) Successful in 1m33s
This simulates params to shim and this is the last step before params to shim is merged. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
ee6c471fe6
commit
e5baaf416f
@ -2,11 +2,14 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
|
"maps"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -447,21 +450,101 @@ func TestApp(t *testing.T) {
|
|||||||
err := seal.finalise(t.Context(), msg, &tc.id, tc.config)
|
err := seal.finalise(t.Context(), msg, &tc.id, tc.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if s, ok := container.GetErrorMessage(err); !ok {
|
if s, ok := container.GetErrorMessage(err); !ok {
|
||||||
t.Fatalf("Seal: error = %v", err)
|
t.Fatalf("outcome: error = %v", err)
|
||||||
} else {
|
} else {
|
||||||
t.Fatalf("Seal: %s", s)
|
t.Fatalf("outcome: %s", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("sys", func(t *testing.T) {
|
t.Run("sys", func(t *testing.T) {
|
||||||
if !seal.sys.Equal(tc.wantSys) {
|
if !seal.sys.Equal(tc.wantSys) {
|
||||||
t.Errorf("Seal: sys = %#v, want %#v", seal.sys, tc.wantSys)
|
t.Errorf("outcome: sys = %#v, want %#v", seal.sys, tc.wantSys)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("params", func(t *testing.T) {
|
t.Run("params", func(t *testing.T) {
|
||||||
if !reflect.DeepEqual(&seal.container, tc.wantParams) {
|
if !reflect.DeepEqual(&seal.container, tc.wantParams) {
|
||||||
t.Errorf("seal: container =\n%s\n, want\n%s", mustMarshal(&seal.container), mustMarshal(tc.wantParams))
|
t.Errorf("outcome: container =\n%s\n, want\n%s", mustMarshal(&seal.container), mustMarshal(tc.wantParams))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ops", func(t *testing.T) {
|
||||||
|
// copied from shim
|
||||||
|
const envAllocSize = 1 << 6
|
||||||
|
|
||||||
|
gr, gw := io.Pipe()
|
||||||
|
|
||||||
|
var gotSys *system.I
|
||||||
|
{
|
||||||
|
sPriv := outcomeState{
|
||||||
|
ID: &tc.id,
|
||||||
|
Identity: tc.config.Identity,
|
||||||
|
UserID: (&Hsu{k: tc.k}).MustIDMsg(msg),
|
||||||
|
EnvPaths: copyPaths(tc.k),
|
||||||
|
Container: tc.config.Container,
|
||||||
|
}
|
||||||
|
|
||||||
|
sPriv.populateEarly(tc.k, msg)
|
||||||
|
if err := sPriv.populateLocal(tc.k, msg); err != nil {
|
||||||
|
t.Fatalf("populateLocal: error = %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotSys = system.New(t.Context(), msg, sPriv.uid.unwrap())
|
||||||
|
opsPriv := fromConfig(tc.config)
|
||||||
|
stateSys := outcomeStateSys{sys: gotSys, outcomeState: &sPriv}
|
||||||
|
for _, op := range opsPriv {
|
||||||
|
if err := op.toSystem(&stateSys, tc.config); err != nil {
|
||||||
|
t.Fatalf("toSystem: error = %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
e := gob.NewEncoder(gw)
|
||||||
|
if err := errors.Join(e.Encode(&sPriv), e.Encode(&opsPriv)); err != nil {
|
||||||
|
t.Errorf("Encode: error = %v", err)
|
||||||
|
panic("unexpected encode fault")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var gotParams container.Params
|
||||||
|
{
|
||||||
|
var (
|
||||||
|
sShim outcomeState
|
||||||
|
opsShim []outcomeOp
|
||||||
|
)
|
||||||
|
|
||||||
|
d := gob.NewDecoder(gr)
|
||||||
|
if err := errors.Join(d.Decode(&sShim), d.Decode(&opsShim)); err != nil {
|
||||||
|
t.Fatalf("Decode: error = %v", err)
|
||||||
|
}
|
||||||
|
if err := sShim.populateLocal(tc.k, msg); err != nil {
|
||||||
|
t.Fatalf("populateLocal: error = %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stateParams := outcomeStateParams{params: &gotParams, outcomeState: &sShim}
|
||||||
|
if sShim.Container.Env == nil {
|
||||||
|
stateParams.env = make(map[string]string, envAllocSize)
|
||||||
|
} else {
|
||||||
|
stateParams.env = maps.Clone(sShim.Container.Env)
|
||||||
|
}
|
||||||
|
for _, op := range opsShim {
|
||||||
|
if err := op.toContainer(&stateParams); err != nil {
|
||||||
|
t.Fatalf("toContainer: error = %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("sys", func(t *testing.T) {
|
||||||
|
if !gotSys.Equal(tc.wantSys) {
|
||||||
|
t.Errorf("toSystem: sys = %#v, want %#v", gotSys, tc.wantSys)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("params", func(t *testing.T) {
|
||||||
|
if !reflect.DeepEqual(&gotParams, tc.wantParams) {
|
||||||
|
t.Errorf("toContainer: params =\n%s\n, want\n%s", mustMarshal(&gotParams), mustMarshal(tc.wantParams))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -194,8 +194,6 @@ type outcomeStateParams struct {
|
|||||||
*outcomeState
|
*outcomeState
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ophestra): register outcomeOp implementations (params to shim)
|
|
||||||
|
|
||||||
// An outcomeOp inflicts an outcome on [system.I] and contains enough information to
|
// An outcomeOp inflicts an outcome on [system.I] and contains enough information to
|
||||||
// inflict it on [container.Params] in a separate process.
|
// inflict it on [container.Params] in a separate process.
|
||||||
// An implementation of outcomeOp must store cross-process states in exported fields only.
|
// An implementation of outcomeOp must store cross-process states in exported fields only.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@ -8,6 +9,8 @@ import (
|
|||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() { gob.Register(spAccountOp{}) }
|
||||||
|
|
||||||
// spAccountOp sets up user account emulation inside the container.
|
// spAccountOp sets up user account emulation inside the container.
|
||||||
type spAccountOp struct{}
|
type spAccountOp struct{}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
@ -19,6 +20,8 @@ import (
|
|||||||
|
|
||||||
const varRunNscd = fhs.Var + "run/nscd"
|
const varRunNscd = fhs.Var + "run/nscd"
|
||||||
|
|
||||||
|
func init() { gob.Register(new(spParamsOp)) }
|
||||||
|
|
||||||
// spParamsOp initialises unordered fields of [container.Params] and the optional root filesystem.
|
// spParamsOp initialises unordered fields of [container.Params] and the optional root filesystem.
|
||||||
// This outcomeOp is hardcoded to always run first.
|
// This outcomeOp is hardcoded to always run first.
|
||||||
type spParamsOp struct {
|
type spParamsOp struct {
|
||||||
@ -113,6 +116,8 @@ func (s *spParamsOp) toContainer(state *outcomeStateParams) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() { gob.Register(spFilesystemOp{}) }
|
||||||
|
|
||||||
// spFilesystemOp applies configured filesystems to [container.Params], excluding the optional root filesystem.
|
// spFilesystemOp applies configured filesystems to [container.Params], excluding the optional root filesystem.
|
||||||
type spFilesystemOp struct{}
|
type spFilesystemOp struct{}
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() { gob.Register(new(spDBusOp)) }
|
||||||
|
|
||||||
// spDBusOp maintains an xdg-dbus-proxy instance for the container.
|
// spDBusOp maintains an xdg-dbus-proxy instance for the container.
|
||||||
type spDBusOp struct {
|
type spDBusOp struct {
|
||||||
// Whether to bind the system bus socket.
|
// Whether to bind the system bus socket.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
@ -12,6 +13,8 @@ import (
|
|||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() { gob.Register(spFinal{}) }
|
||||||
|
|
||||||
// spFinal is a transitional op destined for removal after #3, #8, #9 has been resolved.
|
// spFinal is a transitional op destined for removal after #3, #8, #9 has been resolved.
|
||||||
// It exists to avoid reordering the expected entries in test cases.
|
// It exists to avoid reordering the expected entries in test cases.
|
||||||
type spFinal struct{}
|
type spFinal struct{}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -14,6 +15,8 @@ import (
|
|||||||
|
|
||||||
const pulseCookieSizeMax = 1 << 8
|
const pulseCookieSizeMax = 1 << 8
|
||||||
|
|
||||||
|
func init() { gob.Register(new(spPulseOp)) }
|
||||||
|
|
||||||
// spPulseOp exports the PulseAudio server to the container.
|
// spPulseOp exports the PulseAudio server to the container.
|
||||||
type spPulseOp struct {
|
type spPulseOp struct {
|
||||||
// PulseAudio cookie data, populated during toSystem if a cookie is present.
|
// PulseAudio cookie data, populated during toSystem if a cookie is present.
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
|
||||||
"hakurei.app/container/bits"
|
"hakurei.app/container/bits"
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
@ -9,6 +11,8 @@ import (
|
|||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() { gob.Register(spRuntimeOp{}) }
|
||||||
|
|
||||||
// spRuntimeOp sets up XDG_RUNTIME_DIR inside the container.
|
// spRuntimeOp sets up XDG_RUNTIME_DIR inside the container.
|
||||||
type spRuntimeOp struct{}
|
type spRuntimeOp struct{}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
|
||||||
"hakurei.app/container/bits"
|
"hakurei.app/container/bits"
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
@ -9,6 +11,8 @@ import (
|
|||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() { gob.Register(spTmpdirOp{}) }
|
||||||
|
|
||||||
// spTmpdirOp sets up TMPDIR inside the container.
|
// spTmpdirOp sets up TMPDIR inside the container.
|
||||||
type spTmpdirOp struct{}
|
type spTmpdirOp struct{}
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
"hakurei.app/system/wayland"
|
"hakurei.app/system/wayland"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() { gob.Register(new(spWaylandOp)) }
|
||||||
|
|
||||||
// spWaylandOp exports the Wayland display server to the container.
|
// spWaylandOp exports the Wayland display server to the container.
|
||||||
type spWaylandOp struct {
|
type spWaylandOp struct {
|
||||||
// Path to host wayland socket. Populated during toSystem if DirectWayland is true.
|
// Path to host wayland socket. Populated during toSystem if DirectWayland is true.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
@ -15,6 +16,8 @@ import (
|
|||||||
|
|
||||||
var absX11SocketDir = fhs.AbsTmp.Append(".X11-unix")
|
var absX11SocketDir = fhs.AbsTmp.Append(".X11-unix")
|
||||||
|
|
||||||
|
func init() { gob.Register(new(spX11Op)) }
|
||||||
|
|
||||||
// spX11Op exports the X11 display server to the container.
|
// spX11Op exports the X11 display server to the container.
|
||||||
type spX11Op struct {
|
type spX11Op struct {
|
||||||
// Value of $DISPLAY, stored during toSystem
|
// Value of $DISPLAY, stored during toSystem
|
||||||
|
Loading…
x
Reference in New Issue
Block a user