Files
dingtalk-workspace-cli/internal/auth/identity_agentid_test.go
2026-07-01 10:16:59 +08:00

111 lines
3.5 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestDeriveAgentID_Format(t *testing.T) {
id := deriveAgentID("machine-abc", "claudecode")
if !strings.HasPrefix(id, "dwsa_") {
t.Fatalf("want dwsa_ prefix, got %q", id)
}
if len(id) != len("dwsa_")+12 {
t.Fatalf("want 12 base62 chars after prefix, got %q (len %d)", id, len(id))
}
}
func TestDeriveAgentID_Deterministic(t *testing.T) {
a := deriveAgentID("seed", "claudecode")
b := deriveAgentID("seed", "claudecode")
if a != b {
t.Fatalf("derivation must be deterministic: %q != %q", a, b)
}
}
func TestDeriveAgentID_DistinctByChannelAndMachine(t *testing.T) {
m1c1 := deriveAgentID("machine1", "claudecode")
m1c2 := deriveAgentID("machine1", "cursor")
m2c1 := deriveAgentID("machine2", "claudecode")
if m1c1 == m1c2 {
t.Errorf("same machine, different channel must differ: %q", m1c1)
}
if m1c1 == m2c1 {
t.Errorf("different machine, same channel must differ: %q", m1c1)
}
}
func TestResolveAgentID_IdempotentAndPersisted(t *testing.T) {
dir := t.TempDir()
id := EnsureExists(dir)
first := id.ResolveAgentID(dir, "claudecode", "sig:CLAUDECODE")
second := id.ResolveAgentID(dir, "claudecode", "sig:CLAUDECODE")
if first != second {
t.Fatalf("ResolveAgentID must be idempotent: %q != %q", first, second)
}
// Reload from disk — the channel entry must have persisted.
reloaded := Load(dir)
if reloaded == nil {
t.Fatal("expected identity to persist")
}
e, ok := reloaded.Agents["claudecode"]
if !ok || e.AgentID != first {
t.Fatalf("persisted agentId mismatch: %+v", reloaded.Agents)
}
if e.Detect != "sig:CLAUDECODE" {
t.Errorf("want detect signal recorded, got %q", e.Detect)
}
}
func TestResolveAgentID_EmptyAgentCodeReturnsEmpty(t *testing.T) {
dir := t.TempDir()
id := EnsureExists(dir)
got := id.ResolveAgentID(dir, "", "fallback")
if got != "" {
t.Fatalf("empty agent_code must not derive an instance id, got %q", got)
}
}
// A v1 file ({agentId, source}) must migrate: machineId backfilled from the
// legacy agentId, and per-channel derivation keyed off that stable seed.
func TestLoad_MigratesV1(t *testing.T) {
dir := t.TempDir()
v1 := `{"agentId":"504ddd36-3acf-45f6-9c1f-82f99260a419","source":"dws"}`
if err := os.WriteFile(filepath.Join(dir, identityFile), []byte(v1), 0o600); err != nil {
t.Fatal(err)
}
id := Load(dir)
if id == nil {
t.Fatal("v1 file should load")
}
if id.MachineID != "504ddd36-3acf-45f6-9c1f-82f99260a419" {
t.Fatalf("machineId must backfill from legacy agentId, got %q", id.MachineID)
}
if id.machineSeed() != id.MachineID {
t.Fatalf("seed should be machineId, got %q", id.machineSeed())
}
// Derivation is stable against the migrated seed.
want := deriveAgentID(id.MachineID, "claudecode")
if got := id.ResolveAgentID(dir, "claudecode", "sig:CLAUDECODE"); got != want {
t.Fatalf("post-migration derivation mismatch: %q != %q", got, want)
}
}