From 034c59a26a871bf7ccae11357651e0ab64bcbbd9 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Wed, 8 Oct 2025 18:26:50 +0900 Subject: [PATCH] internal/app: relocate late sys/params outcome This will end up merged with another op after reordering. For now relocate it into its dedicated op for test instrumentation. Signed-off-by: Ophestra --- internal/app/finalise.go | 57 +++++------------------------------- internal/app/spfinal.go | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 49 deletions(-) create mode 100644 internal/app/spfinal.go diff --git a/internal/app/finalise.go b/internal/app/finalise.go index f544ebe..a4e2d69 100644 --- a/internal/app/finalise.go +++ b/internal/app/finalise.go @@ -10,17 +10,12 @@ import ( "maps" "os" "os/user" - "slices" - "strings" "sync/atomic" - "syscall" "hakurei.app/container" - "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/internal/app/state" "hakurei.app/system" - "hakurei.app/system/acl" ) func newWithMessage(msg string) error { return newWithMessageError(msg, os.ErrInvalid) } @@ -49,10 +44,8 @@ type outcome struct { } func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, config *hst.Config) error { - const ( - // only used for a nil configured env map - envAllocSize = 1 << 6 - ) + // only used for a nil configured env map + const envAllocSize = 1 << 6 var kp finaliseProcess @@ -60,7 +53,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, // unreachable panic("invalid call to finalise") } - if k.ctx != nil || k.proc != nil { + if k.ctx != nil || k.sys != nil || k.proc != nil { // unreachable panic("attempting to finalise twice") } @@ -80,6 +73,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, k.ct = ct } + // hsu expects numerical group ids kp.supp = make([]string, len(config.Groups)) for i, name := range config.Groups { if gid, err := k.lookupGroupId(name); err != nil { @@ -123,7 +117,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, return err } kp.runDirPath, kp.identity, kp.id = s.sc.RunDirPath, s.identity, s.id - k.sys = system.New(k.ctx, msg, s.uid.unwrap()) + sys := system.New(k.ctx, msg, s.uid.unwrap()) { ops := []outcomeOp{ @@ -151,8 +145,9 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, if et&hst.EDBus != 0 { ops = append(ops, &spDBusOp{}) } + ops = append(ops, spFinal{}) - stateSys := outcomeStateSys{sys: k.sys, outcomeState: &s} + stateSys := outcomeStateSys{sys: sys, outcomeState: &s} for _, op := range ops { if err := op.toSystem(&stateSys, config); err != nil { return err @@ -171,45 +166,9 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, return err } } - // flatten and sort env for deterministic behaviour - k.container.Env = make([]string, 0, len(stateParams.env)) - for key, value := range stateParams.env { - if strings.IndexByte(key, '=') != -1 { - return &hst.AppError{Step: "flatten environment", Err: syscall.EINVAL, - Msg: fmt.Sprintf("invalid environment variable %s", key)} - } - k.container.Env = append(k.container.Env, key+"="+value) - } - slices.Sort(k.container.Env) - } - - // mount root read-only as the final setup Op - // TODO(ophestra): move this to spFilesystemOp after #8 and #9 - k.container.Remount(fhs.AbsRoot, syscall.MS_RDONLY) - - // append ExtraPerms last - for _, p := range config.ExtraPerms { - if p == nil || p.Path == nil { - continue - } - - if p.Ensure { - k.sys.Ensure(p.Path, 0700) - } - - perms := make(acl.Perms, 0, 3) - if p.Read { - perms = append(perms, acl.Read) - } - if p.Write { - perms = append(perms, acl.Write) - } - if p.Execute { - perms = append(perms, acl.Execute) - } - k.sys.UpdatePermType(system.User, p.Path, perms...) } + k.sys = sys k.proc = &kp return nil } diff --git a/internal/app/spfinal.go b/internal/app/spfinal.go new file mode 100644 index 0000000..c825508 --- /dev/null +++ b/internal/app/spfinal.go @@ -0,0 +1,63 @@ +package app + +import ( + "fmt" + "slices" + "strings" + "syscall" + + "hakurei.app/container/fhs" + "hakurei.app/hst" + "hakurei.app/system" + "hakurei.app/system/acl" +) + +// 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. +type spFinal struct{} + +func (s spFinal) toSystem(state *outcomeStateSys, config *hst.Config) error { + // append ExtraPerms last + for _, p := range config.ExtraPerms { + if p == nil || p.Path == nil { + continue + } + + if p.Ensure { + state.sys.Ensure(p.Path, 0700) + } + + perms := make(acl.Perms, 0, 3) + if p.Read { + perms = append(perms, acl.Read) + } + if p.Write { + perms = append(perms, acl.Write) + } + if p.Execute { + perms = append(perms, acl.Execute) + } + state.sys.UpdatePermType(system.User, p.Path, perms...) + } + return nil +} + +func (s spFinal) toContainer(state *outcomeStateParams) error { + // TODO(ophestra): move this to spFilesystemOp after #8 and #9 + + // mount root read-only as the final setup Op + state.params.Remount(fhs.AbsRoot, syscall.MS_RDONLY) + + state.params.Env = make([]string, 0, len(state.env)) + for key, value := range state.env { + if strings.IndexByte(key, '=') != -1 { + return &hst.AppError{Step: "flatten environment", Err: syscall.EINVAL, + Msg: fmt.Sprintf("invalid environment variable %s", key)} + } + state.params.Env = append(state.params.Env, key+"="+value) + } + // range over map has randomised order + slices.Sort(state.params.Env) + + return nil +}