120 lines
5.3 KiB
Go
120 lines
5.3 KiB
Go
package instance_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
catalogdata "git.zaynet.fr/DoGaMa/DoGaMa-serv/catalog"
|
|
"git.zaynet.fr/DoGaMa/DoGaMa-serv/internal/catalog"
|
|
"git.zaynet.fr/DoGaMa/DoGaMa-serv/internal/instance"
|
|
)
|
|
|
|
func TestResolveConfigurationTargets(t *testing.T) {
|
|
template := catalog.Template{}
|
|
template.Container.Environment = map[string]string{"STATIC": "kept"}
|
|
template.Configuration.Fields = []catalog.ConfigField{
|
|
{ID: "name", Type: "string", Target: catalog.ConfigTarget{Kind: "environment", Name: "SERVER_NAME"}},
|
|
{ID: "count", Type: "integer", Target: catalog.ConfigTarget{Kind: "argument", Name: "--count"}},
|
|
{ID: "public", Type: "boolean", Target: catalog.ConfigTarget{Kind: "argument", Name: "--public"}},
|
|
{ID: "private", Type: "boolean", Target: catalog.ConfigTarget{Kind: "argument", Name: "--private={{value}}"}},
|
|
{ID: "password", Type: "secret", Target: catalog.ConfigTarget{Kind: "ini", Mount: "saved", File: "Config/server.ini", Section: "server", Key: "password"}},
|
|
}
|
|
resolved, err := instance.ResolveConfiguration(template, map[string]string{"name": "My server", "count": "4", "public": "true", "private": "false", "password": "secret"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resolved.Environment["STATIC"] != "kept" || resolved.Environment["SERVER_NAME"] != "My server" {
|
|
t.Fatalf("environment = %#v", resolved.Environment)
|
|
}
|
|
if got := strings.Join(resolved.Arguments, " "); got != "--count=4 --public --private=false" {
|
|
t.Fatalf("arguments = %q", got)
|
|
}
|
|
if len(resolved.INI) != 1 || resolved.INI[0].Value != "" || resolved.INI[0].SecretID != "password" {
|
|
t.Fatalf("secret leaked in resolved config: %#v", resolved.INI)
|
|
}
|
|
template.Configuration.Fields[0].Target.Kind = "unknown"
|
|
if _, err := instance.ResolveConfiguration(template, map[string]string{"name": "x"}); err == nil {
|
|
t.Fatal("unknown target accepted")
|
|
}
|
|
}
|
|
|
|
func TestEnvironmentValuesRemainExactAndOptionalValuesAreOmitted(t *testing.T) {
|
|
template := catalog.Template{}
|
|
template.Configuration.Fields = []catalog.ConfigField{
|
|
{ID: "port", Type: "integer", Target: catalog.ConfigTarget{Kind: "environment", Name: "GAME_PORT"}},
|
|
{ID: "enabled", Type: "boolean", Target: catalog.ConfigTarget{Kind: "environment", Name: "ENABLED"}},
|
|
{ID: "optional", Type: "string", Target: catalog.ConfigTarget{Kind: "environment", Name: "OPTIONAL"}},
|
|
}
|
|
resolved, err := instance.ResolveConfiguration(template, map[string]string{"port": "9876", "enabled": "true", "optional": ""})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resolved.Environment["GAME_PORT"] != "9876" || resolved.Environment["ENABLED"] != "true" {
|
|
t.Fatalf("environment values were rewritten: %#v", resolved.Environment)
|
|
}
|
|
if _, ok := resolved.Environment["OPTIONAL"]; ok {
|
|
t.Fatalf("empty optional environment was emitted: %#v", resolved.Environment)
|
|
}
|
|
for key, value := range resolved.Environment {
|
|
if strings.HasPrefix(value, "= ") || strings.HasPrefix(value, "=") {
|
|
t.Fatalf("synthetic environment prefix for %s: %q", key, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPalworldServerNameIsWrittenBeforeStart(t *testing.T) {
|
|
snapshots, err := catalog.LoadFS(catalogdata.Files, ".")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
snapshot := snapshotByID(t, snapshots, "palworld-official")
|
|
values, err := instance.ValidateConfiguration(snapshot.Template.Configuration.Fields, map[string]string{"server_name": "Mon serveur", "server_description": "x", "max_players": "8", "rest_api_enabled": "true", "rest_api_port": "8212"}, map[string]string{"admin_password": "secret"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
values["admin_password"] = "secret" // marker only; resolver does not retain it.
|
|
resolved, err := instance.ResolveConfiguration(snapshot.Template, values)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := t.TempDir()
|
|
if err := instance.ApplyINI([]instance.MountBinding{{ID: "saved", HostPath: root}}, resolved.INI, map[string]string{"admin_password": "secret"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body, err := os.ReadFile(filepath.Join(root, "Config", "LinuxServer", "PalWorldSettings.ini"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(body), "ServerName=Mon serveur") {
|
|
t.Fatalf("Palworld configuration not effective: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestApplyINIPreservesContentAndRejectsTraversal(t *testing.T) {
|
|
root := t.TempDir()
|
|
path := filepath.Join(root, "Config", "server.ini")
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o770); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(path, []byte("[other]\nkeep=yes\n\n[server]\nold=value\n"), 0o660); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mounts := []instance.MountBinding{{ID: "saved", HostPath: root}}
|
|
mutations := []instance.INIMutation{{Mount: "saved", File: "Config/server.ini", Section: "server", Key: "name", Value: "Mon serveur"}, {Mount: "saved", File: "Config/server.ini", Section: "server", Key: "old", Value: "new"}}
|
|
if err := instance.ApplyINI(mounts, mutations, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body, _ := os.ReadFile(path)
|
|
got := string(body)
|
|
for _, want := range []string{"[other]", "keep=yes", "old=new", "name=Mon serveur"} {
|
|
if !strings.Contains(got, want) {
|
|
t.Fatalf("INI missing %q: %s", want, got)
|
|
}
|
|
}
|
|
if err := instance.ApplyINI(mounts, []instance.INIMutation{{Mount: "saved", File: "../escape.ini", Section: "x", Key: "x", Value: "x"}}, nil); err == nil {
|
|
t.Fatal("path traversal accepted")
|
|
}
|
|
}
|