You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by la...@apache.org on 2026/06/03 00:24:54 UTC
(airavata-custos) 02/04: throw an error when the first and last names are empty when building the cluster username
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 <la...@gmail.com>
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