This is an automated email from the ASF dual-hosted git repository.

lahirujayathilake pushed a commit to branch provisioner-integration
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git

commit 14d9e76b64ffe92b54306c9763746f6b9db6df89
Author: lahiruj <[email protected]>
AuthorDate: Tue Jun 2 17:58:45 2026 -0400

    throw an error when the first and last names are empty when building the 
cluster username
---
 .../ACCESS/AMIE-Processor/config.yaml.example      |  3 --
 connectors/ACCESS/AMIE-Processor/config/config.go  | 16 +++--------
 pkg/posix/username.go                              | 16 +++++++----
 pkg/posix/username_test.go                         | 33 ++++++++++++++++++++--
 4 files changed, 44 insertions(+), 24 deletions(-)

diff --git a/connectors/ACCESS/AMIE-Processor/config.yaml.example 
b/connectors/ACCESS/AMIE-Processor/config.yaml.example
index af0149ffd..528c9039f 100644
--- a/connectors/ACCESS/AMIE-Processor/config.yaml.example
+++ b/connectors/ACCESS/AMIE-Processor/config.yaml.example
@@ -19,6 +19,3 @@ amie:
 log:
   level: "info"
   format: "text"
-
-provisioner:
-  type: "noop"
diff --git a/connectors/ACCESS/AMIE-Processor/config/config.go 
b/connectors/ACCESS/AMIE-Processor/config/config.go
index 7daa093c7..a365aae1e 100644
--- a/connectors/ACCESS/AMIE-Processor/config/config.go
+++ b/connectors/ACCESS/AMIE-Processor/config/config.go
@@ -27,11 +27,10 @@ import (
 )
 
 type Config struct {
-       Server      ServerConfig      `yaml:"server"`
-       Database    DatabaseConfig    `yaml:"database"`
-       AMIE        AMIEConfig        `yaml:"amie"`
-       Log         LogConfig         `yaml:"log"`
-       Provisioner ProvisionerConfig `yaml:"provisioner"`
+       Server   ServerConfig   `yaml:"server"`
+       Database DatabaseConfig `yaml:"database"`
+       AMIE     AMIEConfig     `yaml:"amie"`
+       Log      LogConfig      `yaml:"log"`
 }
 
 type ServerConfig struct {
@@ -60,10 +59,6 @@ type LogConfig struct {
        Format string `yaml:"format"` // "text" or "json"
 }
 
-type ProvisionerConfig struct {
-       Type string `yaml:"type"` // "noop" or "slurm"
-}
-
 // Load reads config from a YAML file and applies environment variable 
overrides.
 func Load(path string) (*Config, error) {
        data, err := os.ReadFile(path)
@@ -113,9 +108,6 @@ func applyDefaults(cfg *Config) {
        if cfg.Log.Format == "" {
                cfg.Log.Format = "text"
        }
-       if cfg.Provisioner.Type == "" {
-               cfg.Provisioner.Type = "noop"
-       }
 }
 
 func applyEnvOverrides(cfg *Config) {
diff --git a/pkg/posix/username.go b/pkg/posix/username.go
index 64b00b5b8..e5fbd34c9 100644
--- a/pkg/posix/username.go
+++ b/pkg/posix/username.go
@@ -20,6 +20,8 @@
 package posix
 
 import (
+       "errors"
+       "fmt"
        "os"
        "strings"
        "unicode"
@@ -29,9 +31,11 @@ import (
 
 const MaxCollisionSuffix = 999
 
-// BuildBase returns the unsuffixed username and a flag set when the name
-// portion was truncated to fit the 32-char Unix login limit.
-func BuildBase(u *models.User, prefix string) (string, bool) {
+var ErrUnbuildableUsername = errors.New("posix: cannot build username from 
empty first and last name")
+
+// BuildBase returns the unsuffixed username. 'truncated' is set when the name
+// portion was shortened to fit the 32-char POSIX login cap.
+func BuildBase(u *models.User, prefix string) (string, bool, error) {
        first := Normalize(u.FirstName)
        last := Normalize(u.LastName)
 
@@ -44,17 +48,17 @@ func BuildBase(u *models.User, prefix string) (string, 
bool) {
        case first != "":
                local = first
        default:
-               local = "user"
+               return "", false, fmt.Errorf("%w: user %q (first=%q last=%q)", 
ErrUnbuildableUsername, u.ID, u.FirstName, u.LastName)
        }
 
-       // Reserve 3 chars for a numeric collision suffix (up to "999").
+       // 32 = POSIX login cap; -1 separator, -3 reserved for collision suffix 
(up to "999").
        maxLocal := 32 - len(prefix) - 1 - 3
        truncated := false
        if len(local) > maxLocal {
                local = local[:maxLocal]
                truncated = true
        }
-       return prefix + "-" + local, truncated
+       return prefix + "-" + local, truncated, nil
 }
 
 func Normalize(s string) string {
diff --git a/pkg/posix/username_test.go b/pkg/posix/username_test.go
index a8601dad2..57b4f28f4 100644
--- a/pkg/posix/username_test.go
+++ b/pkg/posix/username_test.go
@@ -18,6 +18,7 @@
 package posix
 
 import (
+       "errors"
        "strings"
        "testing"
 
@@ -55,8 +56,7 @@ func TestBuildBase(t *testing.T) {
                        wantBase: "custos-alice", wantTrunc: false,
                },
                {
-                       name: "non-ASCII stripped",
-                       // "Aña" normalizes to "aa"; first letter 'a' + "kili" 
(from "Şəkili")
+                       name:  "non-ASCII stripped",
                        first: "Aña", last: "Şəkili", prefix: "custos",
                        wantBase: "custos-akili", wantTrunc: false,
                },
@@ -75,7 +75,10 @@ func TestBuildBase(t *testing.T) {
        for _, tc := range tests {
                t.Run(tc.name, func(t *testing.T) {
                        u := &models.User{FirstName: tc.first, MiddleName: 
tc.middle, LastName: tc.last}
-                       got, trunc := BuildBase(u, tc.prefix)
+                       got, trunc, err := BuildBase(u, tc.prefix)
+                       if err != nil {
+                               t.Fatalf("BuildBase: %v", err)
+                       }
 
                        if trunc != tc.wantTrunc {
                                t.Errorf("truncated = %v, want %v", trunc, 
tc.wantTrunc)
@@ -93,6 +96,30 @@ func TestBuildBase(t *testing.T) {
        }
 }
 
+func TestBuildBase_UnbuildableReturnsError(t *testing.T) {
+       cases := []struct {
+               name  string
+               first string
+               last  string
+       }{
+               {"both empty", "", ""},
+               {"both non-ASCII only", "李", "王"},
+               {"both punctuation only", "...", "---"},
+       }
+       for _, tc := range cases {
+               t.Run(tc.name, func(t *testing.T) {
+                       u := &models.User{ID: "u-1", FirstName: tc.first, 
LastName: tc.last}
+                       got, _, err := BuildBase(u, "custos")
+                       if !errors.Is(err, ErrUnbuildableUsername) {
+                               t.Fatalf("err = %v, want 
ErrUnbuildableUsername", err)
+                       }
+                       if got != "" {
+                               t.Errorf("expected empty username on error, got 
%q", got)
+                       }
+               })
+       }
+}
+
 func TestNormalize(t *testing.T) {
        tests := []struct {
                in   string

Reply via email to