From 2489766efe7b94873a04339009c3609c55e3856f Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 7 Oct 2025 17:58:28 +0900 Subject: [PATCH] hst/config: identity bounds check early This makes sense to do here instead of in internal/app. Signed-off-by: Ophestra --- hst/config.go | 20 +++++++++++++++++--- hst/config_test.go | 4 ++++ internal/app/finalise.go | 7 +------ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/hst/config.go b/hst/config.go index 8581bbc..4629d3d 100644 --- a/hst/config.go +++ b/hst/config.go @@ -2,6 +2,7 @@ package hst import ( "errors" + "strconv" "time" "hakurei.app/container" @@ -118,15 +119,28 @@ type ( } ) -// ErrConfigNull is returned by [Config.Validate] for an invalid configuration that contains a null value for any -// field that must not be null. -var ErrConfigNull = errors.New("unexpected null in config") +var ( + // ErrConfigNull is returned by [Config.Validate] for an invalid configuration that contains a null value for any + // field that must not be null. + ErrConfigNull = errors.New("unexpected null in config") + // ErrIdentityBounds is returned by [Config.Validate] for an out of bounds [Config.Identity] value. + ErrIdentityBounds = errors.New("identity out of bounds") +) + +// Validate checks [Config] and returns [AppError] if an invalid value is encountered. func (config *Config) Validate() error { if config == nil { return &AppError{Step: "validate configuration", Err: ErrConfigNull, Msg: "invalid configuration"} } + + // this is checked again in hsu + if config.Identity < IdentityMin || config.Identity > IdentityMax { + return &AppError{Step: "validate configuration", Err: ErrIdentityBounds, + Msg: "identity " + strconv.Itoa(config.Identity) + " out of range"} + } + if config.Container == nil { return &AppError{Step: "validate configuration", Err: ErrConfigNull, Msg: "configuration missing container state"} diff --git a/hst/config_test.go b/hst/config_test.go index 98321c7..f57be3d 100644 --- a/hst/config_test.go +++ b/hst/config_test.go @@ -16,6 +16,10 @@ func TestConfigValidate(t *testing.T) { }{ {"nil", nil, &hst.AppError{Step: "validate configuration", Err: hst.ErrConfigNull, Msg: "invalid configuration"}}, + {"identity lower", &hst.Config{Identity: -1}, &hst.AppError{Step: "validate configuration", Err: hst.ErrIdentityBounds, + Msg: "identity -1 out of range"}}, + {"identity upper", &hst.Config{Identity: 10000}, &hst.AppError{Step: "validate configuration", Err: hst.ErrIdentityBounds, + Msg: "identity 10000 out of range"}}, {"container", &hst.Config{}, &hst.AppError{Step: "validate configuration", Err: hst.ErrConfigNull, Msg: "configuration missing container state"}}, {"home", &hst.Config{Container: &hst.ContainerConfig{}}, &hst.AppError{Step: "validate configuration", Err: hst.ErrConfigNull, diff --git a/internal/app/finalise.go b/internal/app/finalise.go index 55554eb..2fa4ca0 100644 --- a/internal/app/finalise.go +++ b/internal/app/finalise.go @@ -79,11 +79,6 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, k.ct = ct } - // this is checked again in hsu - if config.Identity < hst.IdentityMin || config.Identity > hst.IdentityMax { - return newWithMessage(fmt.Sprintf("identity %d out of range", config.Identity)) - } - kp.supp = make([]string, len(config.Groups)) for i, name := range config.Groups { if gid, err := k.lookupGroupId(name); err != nil { @@ -98,7 +93,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, } } - // validation complete at this point + // early validation complete at this point s := outcomeState{ ID: id, Identity: config.Identity,