using ClawdDotNet.Core.Config;
using ClawdDotNet.Core.Organisation;
using Shouldly;
namespace ClawdDotNet.Core.Tests.Organisation;
///
/// #692: A unit holds credentials for its members — needed once, not six times, and the
/// accounts department never gets the marketplace key.
///
public sealed class UnitCredentialsTests
{
/// shop (holds DirectAPI.apiKey, Mail.password) › buying (holds DirectAPI.apiKey); accounts beside it.
private static OrgChart Org(params AgentConfig[] agents) => new(
[
new UnitConfig
{
Id = "shop", Name = "Shop",
Credentials = new() { ["DirectAPI"] = new() { ["apiKey"] = "shop-key" }, ["Mail"] = new() { ["password"] = "shop-mail" } }
},
new UnitConfig { Id = "buying", Name = "Buying", ParentId = "shop", Credentials = new() { ["directapi"] = new() { ["apiKey"] = "buying-key" } } },
new UnitConfig { Id = "accounts", Name = "Accounts" }
],
agents);
private static AgentConfig Agent(string id, string unit, params (string Tool, Dictionary Settings)[] tools)
=> new() { AgentId = id, UnitId = unit, Tools = tools.ToDictionary(t => t.Tool, t => t.Settings) };
[Fact]
public void A_member_gets_the_nearest_units_credential_for_a_tool_it_has()
{
var buyer = Agent("buyer", "buying", ("DirectAPI", new() { ["baseUrl"] = "https://api.example" }), ("Mail", new()));
var org = Org(buyer);
org.ToolSettingsFor(buyer, "DirectAPI")["apiKey"].ShouldBe("buying-key", "the nearest unit first");
org.ToolSettingsFor(buyer, "DirectAPI")["baseUrl"].ShouldBe("https://api.example");
org.ToolSettingsFor(buyer, "Mail")["password"].ShouldBe("shop-mail", "from the unit above");
}
[Fact]
public void Its_own_value_wins_and_an_empty_one_is_filled()
{
var own = Agent("own", "shop", ("DirectAPI", new() { ["apiKey"] = "own-key" }), ("Mail", new() { ["password"] = "" }));
var org = Org(own);
org.ToolSettingsFor(own, "DirectAPI")["apiKey"].ShouldBe("own-key");
org.ToolSettingsFor(own, "Mail")["password"].ShouldBe("shop-mail");
}
[Fact]
public void No_credential_reaches_another_unit_or_a_tool_the_agent_lacks()
{
var clerk = Agent("clerk", "accounts", ("DirectAPI", new()));
var buyer = Agent("buyer", "buying", ("FileRW", new()));
var org = Org(clerk, buyer);
org.ToolSettingsFor(clerk, "DirectAPI").ContainsKey("apiKey").ShouldBeFalse();
org.ToolSettingsFor(buyer, "DirectAPI").ShouldBeEmpty("a credential grants no tool");
}
[Fact]
public void A_template_never_carries_what_a_unit_holds()
{
var instance = new InstanceConfig();
instance.Units.Add(new UnitConfig { Id = "shop", Name = "Shop", Credentials = new() { ["DirectAPI"] = new() { ["apiKey"] = "shop-key" } } });
var template = OrgTemplates.Export(instance, "Shop", "", _ => null, DateTime.UtcNow);
template.Units[0].Credentials.ShouldBeNull();
template.Credentials.ShouldContain(new CredentialNeed("unit:shop", "DirectAPI", "apiKey"));
template.Units[0].Credentials = new() { ["DirectAPI"] = new() { ["apiKey"] = "smuggled" } };
OrgTemplates.Problems(template).ShouldContain(p => p.Contains("brings credentials"));
}
}