Drop the legacy-metadata overlay path (runtimeToolSpecAllowingLegacy, assembleSchemaRegistryFromBoundAllowingLegacy, metadata-based agent selection, dry-run seams) so assembly flows exclusively through ContractFinal; gate MCP fixture machinery behind a build flag so it can never enter production assembly. Wire output verified identical before and after; policy tripwire reports 26 products, 847 tools.
349 lines
12 KiB
Go
349 lines
12 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
package cli
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contractfinal"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func TestValidateSchemaRegistryAgainstCommandRegistryChecksFullIdentity(t *testing.T) {
|
|
tool := ToolSpec{Identity: contract.ToolIdentitySpec{
|
|
ProductID: "sample",
|
|
SourceProductID: "implementation_a",
|
|
Name: "run",
|
|
CanonicalPath: "sample.run",
|
|
Path: "sample.run",
|
|
CLIPath: "sample run",
|
|
PrimaryCLIPath: "sample run",
|
|
Source: "contract_identity",
|
|
}}
|
|
registry, err := SchemaRegistryFromRuntime("test", []ProductSpec{{ID: "sample", Tools: []ToolSpec{tool}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
base := CommandSpec{
|
|
CanonicalPath: "sample.run",
|
|
SourceProductID: "implementation_a",
|
|
PrimaryCLIPath: "sample run",
|
|
Visibility: SchemaVisibilityPublic,
|
|
Source: "contract_identity",
|
|
}
|
|
for name, test := range map[string]struct {
|
|
mutate func(*CommandSpec)
|
|
want string
|
|
}{
|
|
"source product": {
|
|
mutate: func(spec *CommandSpec) { spec.SourceProductID = "implementation_b" },
|
|
want: "source product",
|
|
},
|
|
"identity source": {
|
|
mutate: func(spec *CommandSpec) { spec.Source = "stale_identity_source" },
|
|
want: "identity source",
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
expected := cloneCommandSpec(base)
|
|
test.mutate(&expected)
|
|
effective, err := newEffectiveCommandRegistry([]CommandSpec{expected})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = validateSchemaRegistryAgainstCommandRegistry(registry, effective)
|
|
if err == nil || !strings.Contains(err.Error(), test.want) {
|
|
t.Fatalf("validation error = %v, want %q", err, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateSchemaRegistryAgainstCommandRegistryRejectsAliasViewAsCanonical(t *testing.T) {
|
|
baseTool := ToolSpec{Identity: contract.ToolIdentitySpec{
|
|
ProductID: "sample",
|
|
Name: "run",
|
|
CanonicalPath: "sample.run",
|
|
Path: "sample.run",
|
|
CLIPath: "sample run",
|
|
PrimaryCLIPath: "sample run",
|
|
Aliases: []string{"sample execute"},
|
|
Source: "contract_identity",
|
|
}}
|
|
effective, err := newEffectiveCommandRegistry([]CommandSpec{{
|
|
CanonicalPath: "sample.run",
|
|
PrimaryCLIPath: "sample run",
|
|
Aliases: []string{"sample execute"},
|
|
Visibility: SchemaVisibilityPublic,
|
|
Source: "contract_identity",
|
|
}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for name, test := range map[string]struct {
|
|
mutate func(*contract.ToolIdentitySpec)
|
|
want string
|
|
}{
|
|
"alternate cli path": {
|
|
mutate: func(identity *contract.ToolIdentitySpec) { identity.CLIPath = "sample execute" },
|
|
want: "must equal primary_cli_path",
|
|
},
|
|
"alias marker": {
|
|
mutate: func(identity *contract.ToolIdentitySpec) { identity.IsAlias = true },
|
|
want: "must have is_alias=false",
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
tool := baseTool
|
|
test.mutate(&tool.Identity)
|
|
registry := SchemaRegistry{Products: []ProductSpec{{ID: "sample", Tools: []ToolSpec{tool}}}}
|
|
err := validateSchemaRegistryAgainstCommandRegistry(registry, effective)
|
|
if err == nil || !strings.Contains(err.Error(), test.want) {
|
|
t.Fatalf("validation error = %v, want %q", err, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssembleSchemaRegistryFailClosedMissingContractFinal(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
leaf := &cobra.Command{Use: "run", Short: "Run", Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(leaf, "sample", "run", "test")
|
|
product := &cobra.Command{Use: "sample"}
|
|
product.AddCommand(leaf)
|
|
root.AddCommand(product)
|
|
|
|
t.Cleanup(func() { contract.ClearProductDeclForTest("sample") })
|
|
contract.RegisterProductDecl(contract.ProductDecl{
|
|
ID: "sample",
|
|
Selection: contract.ProductSelectionDecl{
|
|
AgentSummary: "Sample product",
|
|
UseWhen: []string{"sample routing"},
|
|
AvoidWhen: []string{"not sample"},
|
|
},
|
|
})
|
|
|
|
_, err := schemaRegistryForTest(root)
|
|
if err == nil || !strings.Contains(err.Error(), "missing RuntimeContractFinal") {
|
|
t.Fatalf("production assembly error = %v, want missing RuntimeContractFinal", err)
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageAssembleSchemaRegistryFailClosedMissingProductDecl(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
leaf := &cobra.Command{Use: "run", Short: "Run", Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(leaf, "orphan", "run", "test")
|
|
contractfinal.RegisterRuntimeContractFinal(leaf, contract.ContractFinalPayload{
|
|
Identity: &contract.ToolIdentitySpec{
|
|
ProductID: "orphan", Name: "run", CanonicalPath: "orphan.run",
|
|
CLIPath: "orphan run", PrimaryCLIPath: "orphan run",
|
|
},
|
|
|
|
Title: "Orphan run",
|
|
Description: "Has ContractFinal but no ProductDecl",
|
|
Selection: &contract.SelectionSpec{AgentSummary: "orphan leaf"},
|
|
})
|
|
t.Cleanup(func() {
|
|
contractfinal.ClearRuntimeContractFinalForTest(leaf)
|
|
contract.ClearProductDeclForTest("orphan")
|
|
})
|
|
product := &cobra.Command{Use: "orphan"}
|
|
product.AddCommand(leaf)
|
|
root.AddCommand(product)
|
|
|
|
_, err := schemaRegistryForTest(root)
|
|
if err == nil || !strings.Contains(err.Error(), "missing ProductDecl") {
|
|
t.Fatalf("production assembly error = %v, want missing ProductDecl", err)
|
|
}
|
|
}
|
|
|
|
func TestAssembleSchemaRegistryRequiresContractFinalAndProductDecl(t *testing.T) {
|
|
root := &cobra.Command{Use: "dws"}
|
|
leaf := &cobra.Command{Use: "run", Short: "Run sample", Long: "Run the sample tool", Run: func(*cobra.Command, []string) {}}
|
|
AttachRuntimeSchema(leaf, "sample", "run", "test")
|
|
contractfinal.RegisterRuntimeContractFinal(leaf, contract.ContractFinalPayload{
|
|
Identity: &contract.ToolIdentitySpec{
|
|
ProductID: "sample", Name: "run", CanonicalPath: "sample.run",
|
|
CLIPath: "sample run", PrimaryCLIPath: "sample run",
|
|
},
|
|
|
|
Title: "Sample run",
|
|
Description: "Declared sample tool",
|
|
Safety: &contract.SafetySpec{
|
|
Effect: "read", Risk: "low", Confirmation: "none", Idempotency: "idempotent",
|
|
},
|
|
Interface: &contract.InterfaceSpec{
|
|
Mode: "local", Availability: "available", Reason: "test local leaf",
|
|
},
|
|
Selection: &contract.SelectionSpec{
|
|
AgentSummary: "Run a sample tool",
|
|
UseWhen: []string{"need sample run"},
|
|
AvoidWhen: []string{"need other product"},
|
|
},
|
|
})
|
|
t.Cleanup(func() {
|
|
contractfinal.ClearRuntimeContractFinalForTest(leaf)
|
|
contract.ClearProductDeclForTest("sample")
|
|
})
|
|
contract.RegisterProductDecl(contract.ProductDecl{
|
|
ID: "sample",
|
|
Selection: contract.ProductSelectionDecl{
|
|
AgentSummary: "Sample product",
|
|
UseWhen: []string{"sample routing"},
|
|
AvoidWhen: []string{"not sample"},
|
|
},
|
|
})
|
|
product := &cobra.Command{Use: "sample"}
|
|
product.AddCommand(leaf)
|
|
root.AddCommand(product)
|
|
|
|
registry, err := schemaRegistryForTest(root)
|
|
if err != nil {
|
|
t.Fatalf("declared production assembly: %v", err)
|
|
}
|
|
if len(registry.Products) != 1 || len(registry.Products[0].Tools) != 1 {
|
|
t.Fatalf("registry = %#v", registry.Products)
|
|
}
|
|
tool := registry.Products[0].Tools[0]
|
|
if tool.MetadataSource != "corecmd.contract" {
|
|
t.Fatalf("metadata_source = %q, want corecmd.contract", tool.MetadataSource)
|
|
}
|
|
if registry.Products[0].Selection.AgentSummary != "Sample product" {
|
|
t.Fatalf("product selection = %#v", registry.Products[0].Selection)
|
|
}
|
|
}
|
|
|
|
func TestAssembleContractFinalDescriptionPrefersCobraLong(t *testing.T) {
|
|
tool := assembleContractFinalTextTool(t, "Run sample", "Cobra Long description wins", "Declared description")
|
|
if tool.Description != "Cobra Long description wins" {
|
|
t.Fatalf("description = %q, want Cobra Long", tool.Description)
|
|
}
|
|
prov := tool.FieldProvenance["description"]
|
|
if prov.Precedence != "cobra_help" {
|
|
t.Fatalf("description precedence = %q, want cobra_help", prov.Precedence)
|
|
}
|
|
if prov.Resolution != "cobra_help_preferred" {
|
|
t.Fatalf("description resolution = %q, want cobra_help_preferred", prov.Resolution)
|
|
}
|
|
if prov.Source != "cobra_help" {
|
|
t.Fatalf("description source = %q, want cobra_help", prov.Source)
|
|
}
|
|
// Title stays declared-first even when Short differs.
|
|
if tool.Title != "Declared title" {
|
|
t.Fatalf("title = %q, want declared title", tool.Title)
|
|
}
|
|
titleProv := tool.FieldProvenance["title"]
|
|
if titleProv.Precedence != "contract_final" {
|
|
t.Fatalf("title precedence = %q, want contract_final", titleProv.Precedence)
|
|
}
|
|
}
|
|
|
|
func TestAssembleContractFinalDescriptionUsesDeclaredWithoutLong(t *testing.T) {
|
|
tool := assembleContractFinalTextTool(t, "Run sample", "", "Declared description without Long")
|
|
if tool.Description != "Declared description without Long" {
|
|
t.Fatalf("description = %q, want declared ContractDecl description", tool.Description)
|
|
}
|
|
prov := tool.FieldProvenance["description"]
|
|
if prov.Precedence != "contract_final" {
|
|
t.Fatalf("description precedence = %q, want contract_final", prov.Precedence)
|
|
}
|
|
if prov.Resolution != "contract_pass_through" {
|
|
t.Fatalf("description resolution = %q, want contract_pass_through", prov.Resolution)
|
|
}
|
|
if prov.Source != "corecmd.contract" {
|
|
t.Fatalf("description source = %q, want corecmd.contract", prov.Source)
|
|
}
|
|
}
|
|
|
|
// Short-only leaves must not leak Cobra Short into delivered description.
|
|
// Description compares only against Long; Short stays a title fallback candidate.
|
|
func TestAssembleContractFinalDescriptionIgnoresShortWhenDeclared(t *testing.T) {
|
|
const (
|
|
short = "Short must not become description"
|
|
declared = "Declared Contract.Description for short-only leaf"
|
|
)
|
|
tool := assembleContractFinalTextTool(t, short, "", declared)
|
|
if tool.Description != declared {
|
|
t.Fatalf("description = %q, want declared %q", tool.Description, declared)
|
|
}
|
|
if tool.Description == short {
|
|
t.Fatalf("description must not equal Short %q", short)
|
|
}
|
|
prov := tool.FieldProvenance["description"]
|
|
if prov.Precedence == "cobra_help" || prov.Source == "cobra_help" {
|
|
t.Fatalf("description provenance = %#v, must not be cobra_help when Long is empty", prov)
|
|
}
|
|
if prov.Precedence != "contract_final" {
|
|
t.Fatalf("description precedence = %q, want contract_final", prov.Precedence)
|
|
}
|
|
if prov.Resolution != "contract_pass_through" {
|
|
t.Fatalf("description resolution = %q, want contract_pass_through", prov.Resolution)
|
|
}
|
|
if prov.Source != "corecmd.contract" {
|
|
t.Fatalf("description source = %q, want corecmd.contract", prov.Source)
|
|
}
|
|
}
|
|
|
|
// assembleContractFinalTextTool builds a one-leaf tree, registers ContractFinal +
|
|
// ProductDecl, and runs the production assembly path (schemaRegistryForTest).
|
|
func assembleContractFinalTextTool(t *testing.T, short, long, declaredDescription string) ToolSpec {
|
|
t.Helper()
|
|
root := &cobra.Command{Use: "dws"}
|
|
leaf := &cobra.Command{
|
|
Use: "run",
|
|
Short: short,
|
|
Long: long,
|
|
Run: func(*cobra.Command, []string) {},
|
|
}
|
|
AttachRuntimeSchema(leaf, "sample", "run", "test")
|
|
contractfinal.RegisterRuntimeContractFinal(leaf, contract.ContractFinalPayload{
|
|
Identity: &contract.ToolIdentitySpec{
|
|
ProductID: "sample", Name: "run", CanonicalPath: "sample.run",
|
|
CLIPath: "sample run", PrimaryCLIPath: "sample run",
|
|
},
|
|
|
|
Title: "Declared title",
|
|
Description: declaredDescription,
|
|
Safety: &contract.SafetySpec{
|
|
Effect: "read", Risk: "low", Confirmation: "none", Idempotency: "idempotent",
|
|
},
|
|
Interface: &contract.InterfaceSpec{
|
|
Mode: "local", Availability: "available",
|
|
},
|
|
Selection: &contract.SelectionSpec{
|
|
AgentSummary: "Run a sample tool",
|
|
UseWhen: []string{"need sample run"},
|
|
AvoidWhen: []string{"need other product"},
|
|
},
|
|
})
|
|
t.Cleanup(func() {
|
|
contractfinal.ClearRuntimeContractFinalForTest(leaf)
|
|
contract.ClearProductDeclForTest("sample")
|
|
})
|
|
contract.RegisterProductDecl(contract.ProductDecl{
|
|
ID: "sample",
|
|
Selection: contract.ProductSelectionDecl{
|
|
AgentSummary: "Sample product",
|
|
UseWhen: []string{"sample routing"},
|
|
AvoidWhen: []string{"not sample"},
|
|
},
|
|
})
|
|
product := &cobra.Command{Use: "sample"}
|
|
product.AddCommand(leaf)
|
|
root.AddCommand(product)
|
|
|
|
registry, err := schemaRegistryForTest(root)
|
|
if err != nil {
|
|
t.Fatalf("assemble schema registry: %v", err)
|
|
}
|
|
if len(registry.Products) != 1 || len(registry.Products[0].Tools) != 1 {
|
|
t.Fatalf("registry = %#v", registry.Products)
|
|
}
|
|
return registry.Products[0].Tools[0]
|
|
}
|