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.
505 lines
20 KiB
Go
505 lines
20 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
package cli
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// RuntimeSchemaExclusion records a reviewed reason why a public executable
|
|
// command is intentionally not advertised as an Agent tool.
|
|
type RuntimeSchemaExclusion struct {
|
|
CLIPath string
|
|
Reason string
|
|
Reviewed bool
|
|
}
|
|
|
|
type runtimeSchemaExclusionGroup struct {
|
|
ID string
|
|
Reason string
|
|
Reviewed bool
|
|
Commands []string
|
|
}
|
|
|
|
var (
|
|
completenessLoadExclusions = ReviewedRuntimeSchemaExclusions
|
|
completenessBuildEffective = BuildEffectiveCommandRegistry
|
|
completenessBindEffective = BindEffectiveCommandRegistry
|
|
completenessRuntimeReport = runtimeSchemaCompletenessFromBound
|
|
completenessDeliveryReport = schemaCatalogDeliveryCompletenessAgainstLoadedAndBound
|
|
completenessCollectEntries = collectRuntimeSchemaEntries
|
|
)
|
|
|
|
// RuntimeSchemaCompletenessReport compares the public executable Cobra leaves
|
|
// with a reviewed Schema command set, such as runtime annotations or the final
|
|
// generated Catalog.
|
|
type RuntimeSchemaCompletenessReport struct {
|
|
Covered []string
|
|
Excluded []string
|
|
Missing []string
|
|
InvalidExclusions []string
|
|
StaleExclusions []string
|
|
DeliveryErrors []string
|
|
}
|
|
|
|
// ReviewedRuntimeSchemaExclusions returns the exact, reviewed list of public
|
|
// CLI leaves intentionally kept outside the stable Agent command contract.
|
|
// Authority is the reviewed Go registry in schema_command_exclusions.go
|
|
// (central groups + non-empty reason); there is no JSON completeness input.
|
|
func ReviewedRuntimeSchemaExclusions() ([]RuntimeSchemaExclusion, error) {
|
|
var exclusions []RuntimeSchemaExclusion
|
|
seen := map[string]bool{}
|
|
for _, group := range reviewedRuntimeSchemaExclusionGroups {
|
|
if strings.TrimSpace(group.ID) == "" || strings.TrimSpace(group.Reason) == "" || !group.Reviewed {
|
|
return nil, fmt.Errorf("runtime schema exclusion group %q is not reviewed or has no reason", group.ID)
|
|
}
|
|
for _, rawPath := range group.Commands {
|
|
path := normalizeSchemaCLIPath(rawPath)
|
|
if path == "" {
|
|
return nil, fmt.Errorf("runtime schema exclusion group %q contains an empty command", group.ID)
|
|
}
|
|
if seen[path] {
|
|
return nil, fmt.Errorf("duplicate runtime schema exclusion %q", path)
|
|
}
|
|
seen[path] = true
|
|
exclusions = append(exclusions, RuntimeSchemaExclusion{CLIPath: path, Reason: group.Reason, Reviewed: true})
|
|
}
|
|
}
|
|
return exclusions, nil
|
|
}
|
|
|
|
// ValidateRuntimeSchemaCompleteness enforces the reviewed reverse
|
|
// command-tree contract used by generation and CI.
|
|
func ValidateRuntimeSchemaCompleteness(root *cobra.Command) error {
|
|
effective, err := completenessBuildEffective(root)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bound, err := completenessBindEffective(root, effective)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return validateResolvedRuntimeSchemaCompleteness(root, bound)
|
|
}
|
|
|
|
// validateResolvedRuntimeSchemaCompleteness checks the executable tree against
|
|
// the exact BoundCommandRegistry produced by the active resolution pass. It
|
|
// must not discover or bind commands again: Catalog generation uses this gate
|
|
// to ensure every pre-delivery check observes the same identity candidate.
|
|
func validateResolvedRuntimeSchemaCompleteness(root *cobra.Command, bound BoundCommandRegistry) error {
|
|
exclusions, err := completenessLoadExclusions()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
report := completenessRuntimeReport(root, exclusions, bound)
|
|
if len(report.DeliveryErrors) > 0 {
|
|
return fmt.Errorf("invalid effective Schema command registry: %s", strings.Join(report.DeliveryErrors, "; "))
|
|
}
|
|
if len(report.Missing) > 0 {
|
|
return fmt.Errorf("public Cobra leaves missing from Schema or reviewed exclusions: %s", strings.Join(report.Missing, ", "))
|
|
}
|
|
if len(report.InvalidExclusions) > 0 {
|
|
return fmt.Errorf("invalid runtime schema exclusions: %s", strings.Join(report.InvalidExclusions, ", "))
|
|
}
|
|
if len(report.StaleExclusions) > 0 {
|
|
return fmt.Errorf("stale runtime schema exclusions: %s", strings.Join(report.StaleExclusions, ", "))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validateResolvedSchemaCatalogDeliveryCompleteness compares the serialized
|
|
// delivery with the exact bound registry that produced its SchemaRegistry.
|
|
// This closes the final path where completeness used to rebuild identity from
|
|
// Cobra after the source registry had already passed generation gates.
|
|
func validateResolvedSchemaCatalogDeliveryCompleteness(root *cobra.Command, bound BoundCommandRegistry, snapshot SchemaCatalogSnapshot) error {
|
|
exclusions, err := completenessLoadExclusions()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return validateSchemaCatalogDeliveryCompletenessFromBound(root, bound, snapshot, exclusions)
|
|
}
|
|
|
|
func validateSchemaCatalogDeliveryCompletenessFromBound(root *cobra.Command, bound BoundCommandRegistry, snapshot SchemaCatalogSnapshot, exclusions []RuntimeSchemaExclusion) error {
|
|
encoded, err := json.Marshal(snapshot)
|
|
if err != nil {
|
|
return fmt.Errorf("encode final Schema Catalog for delivery validation: %w", err)
|
|
}
|
|
loaded, err := decodeSchemaCatalogSnapshot(encoded)
|
|
if err != nil {
|
|
return fmt.Errorf("load final Schema Catalog through production loader: %w", err)
|
|
}
|
|
report := completenessDeliveryReport(root, loaded, exclusions, bound)
|
|
if len(report.DeliveryErrors) > 0 {
|
|
return fmt.Errorf("invalid final Schema Catalog delivery: %s", strings.Join(report.DeliveryErrors, "; "))
|
|
}
|
|
if len(report.Missing) > 0 {
|
|
return fmt.Errorf("public Cobra leaves missing from final Schema Catalog or reviewed exclusions: %s", strings.Join(report.Missing, ", "))
|
|
}
|
|
if len(report.InvalidExclusions) > 0 {
|
|
return fmt.Errorf("invalid runtime schema exclusions: %s", strings.Join(report.InvalidExclusions, ", "))
|
|
}
|
|
if len(report.StaleExclusions) > 0 {
|
|
return fmt.Errorf("stale runtime schema exclusions: %s", strings.Join(report.StaleExclusions, ", "))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RuntimeSchemaCompleteness scans the real command tree in the reverse
|
|
// direction: every public executable leaf must either belong to the effective
|
|
// reviewed CommandRegistry or have a reviewed exclusion with a non-empty
|
|
// reason.
|
|
func RuntimeSchemaCompleteness(root *cobra.Command, exclusions []RuntimeSchemaExclusion) RuntimeSchemaCompletenessReport {
|
|
entries, err := completenessCollectEntries(root)
|
|
if err != nil {
|
|
return RuntimeSchemaCompletenessReport{DeliveryErrors: []string{err.Error()}}
|
|
}
|
|
coveredPaths := map[string]bool{}
|
|
for _, entry := range entries {
|
|
addSchemaCoveredPath(coveredPaths, entry.CLIPath)
|
|
addSchemaCoveredPath(coveredPaths, entry.PrimaryCLIPath)
|
|
for _, alias := range entry.Aliases {
|
|
addSchemaCoveredPath(coveredPaths, alias)
|
|
}
|
|
}
|
|
return runtimeSchemaCompletenessAgainstPaths(root, exclusions, coveredPaths)
|
|
}
|
|
|
|
func runtimeSchemaCompletenessFromBound(root *cobra.Command, exclusions []RuntimeSchemaExclusion, bound BoundCommandRegistry) RuntimeSchemaCompletenessReport {
|
|
coveredPaths := map[string]bool{}
|
|
for _, command := range bound.Commands {
|
|
if command.Visibility != SchemaVisibilityPublic {
|
|
continue
|
|
}
|
|
addSchemaCoveredPath(coveredPaths, command.PrimaryCLIPath)
|
|
for _, alias := range command.Aliases {
|
|
addSchemaCoveredPath(coveredPaths, alias)
|
|
}
|
|
}
|
|
return runtimeSchemaCompletenessAgainstPaths(root, exclusions, coveredPaths)
|
|
}
|
|
|
|
func schemaCatalogDeliveryCompletenessAgainstLoadedAndBound(root *cobra.Command, loaded loadedSchemaCatalog, exclusions []RuntimeSchemaExclusion, bound BoundCommandRegistry) RuntimeSchemaCompletenessReport {
|
|
expectedByPath, mappingErrors := runtimeSchemaIdentityByBound(bound)
|
|
return schemaCatalogDeliveryCompletenessAgainstLoadedAndIdentity(root, loaded, exclusions, expectedByPath, mappingErrors)
|
|
}
|
|
|
|
func schemaCatalogDeliveryCompletenessAgainstLoadedAndIdentity(
|
|
root *cobra.Command,
|
|
loaded loadedSchemaCatalog,
|
|
exclusions []RuntimeSchemaExclusion,
|
|
expectedByPath map[string]runtimeSchemaResolvedIdentity,
|
|
mappingErrors []string,
|
|
) RuntimeSchemaCompletenessReport {
|
|
coveredPaths := map[string]bool{}
|
|
deliveryErrors := append([]string(nil), mappingErrors...)
|
|
deliveryErrors = append(deliveryErrors, schemaDeliveryInvariantErrors(loaded)...)
|
|
|
|
// Public completeness is intentionally limited to visible runnable leaves.
|
|
// A hidden compatibility leaf may still be a valid primary path or alias and
|
|
// is checked separately against all resolved runtime Schema entries below.
|
|
walkPublicRunnableLeaves(root, func(leaf *cobra.Command) {
|
|
path := normalizeSchemaCLIPath(strings.Join(commandPathParts(leaf), " "))
|
|
expected := expectedByPath[path]
|
|
if expected.CanonicalPath == "" {
|
|
return
|
|
}
|
|
payload, err := deliverySchemaPayload(loaded, []string{path})
|
|
if err != nil {
|
|
return
|
|
}
|
|
if got := strings.TrimSpace(schemaString(payload["canonical_path"])); got == expected.CanonicalPath {
|
|
coveredPaths[path] = true
|
|
} else {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("public CLI path %q resolves to %q, want %q", path, got, expected.CanonicalPath))
|
|
}
|
|
})
|
|
|
|
canonicals := loaded.Index.CanonicalPaths()
|
|
for _, canonical := range canonicals {
|
|
tool, ok := deliveryIndexResolve(loaded.Index, canonical)
|
|
if !ok {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("typed Schema index lost canonical %q", canonical))
|
|
continue
|
|
}
|
|
primaryPath := normalizeSchemaCLIPath(tool.Identity.PrimaryCLIPath)
|
|
if expected := expectedByPath[primaryPath]; expected.CanonicalPath == canonical && expected.Source != "" {
|
|
if gotSource := strings.TrimSpace(tool.Identity.Source); gotSource != expected.Source {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("tool %s identity source is %q, want resolved source %q", canonical, gotSource, expected.Source))
|
|
}
|
|
}
|
|
if payload, err := deliverySchemaPayload(loaded, []string{canonical}); err != nil {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("canonical %q is not queryable: %v", canonical, err))
|
|
} else if got := strings.TrimSpace(schemaString(payload["canonical_path"])); got != canonical {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("canonical %q resolves to %q", canonical, got))
|
|
} else if expectedPayload, renderErr := deliveryToolPayload(tool); renderErr != nil {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("canonical %q cannot render typed payload: %v", canonical, renderErr))
|
|
} else if !schemaJSONEqual(payload, expectedPayload) {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("canonical %q query differs from final ToolSpec", canonical))
|
|
}
|
|
|
|
paths := []string{tool.Identity.CLIPath, tool.Identity.PrimaryCLIPath}
|
|
paths = append(paths, tool.Identity.Aliases...)
|
|
seenPaths := map[string]bool{}
|
|
for _, rawPath := range paths {
|
|
path := normalizeSchemaCLIPath(rawPath)
|
|
if path == "" || seenPaths[path] {
|
|
continue
|
|
}
|
|
seenPaths[path] = true
|
|
expected := expectedByPath[path]
|
|
if expected.CanonicalPath == "" {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("tool %s advertises non-executable Schema path %q", canonical, path))
|
|
continue
|
|
}
|
|
if expected.CanonicalPath != canonical {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("tool %s advertises path %q owned by %s", canonical, path, expected.CanonicalPath))
|
|
continue
|
|
}
|
|
payload, err := deliverySchemaPayload(loaded, []string{path})
|
|
if err != nil {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("tool %s path %q is not queryable: %v", canonical, path, err))
|
|
continue
|
|
}
|
|
if got := strings.TrimSpace(schemaString(payload["canonical_path"])); got != canonical {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("tool %s path %q resolves to %q", canonical, path, got))
|
|
continue
|
|
}
|
|
expectedTool := schemaToolForResolvedPath(tool, path)
|
|
expectedPayload, renderErr := deliveryToolPayload(expectedTool)
|
|
if renderErr != nil {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("tool %s path %q cannot render typed payload: %v", canonical, path, renderErr))
|
|
} else if !schemaJSONEqual(payload, expectedPayload) {
|
|
deliveryErrors = append(deliveryErrors, fmt.Sprintf("tool %s path %q query differs from final ToolSpec", canonical, path))
|
|
}
|
|
}
|
|
}
|
|
|
|
report := runtimeSchemaCompletenessAgainstPaths(root, exclusions, coveredPaths)
|
|
report.DeliveryErrors = sortedUniqueSchemaStrings(deliveryErrors)
|
|
return report
|
|
}
|
|
|
|
// schemaRegistryProjectionErrors proves every public view is a pure
|
|
// projection of the final typed registry: product/group summaries and --all
|
|
// must never re-resolve annotations or metadata independently from leaf
|
|
// lookup.
|
|
func schemaRegistryProjectionErrors(loaded loadedSchemaCatalog) []string {
|
|
var problems []string
|
|
all, err := deliveryRegistryPayload(loaded.Registry)
|
|
if err != nil {
|
|
return []string{fmt.Sprintf("render final Schema --all projection: %v", err)}
|
|
}
|
|
allByCanonical := map[string]map[string]any{}
|
|
for _, product := range schemaMapSlice(all["products"]) {
|
|
for _, tool := range schemaMapSlice(product["tools"]) {
|
|
canonical := strings.TrimSpace(schemaString(tool["canonical_path"]))
|
|
if canonical == "" {
|
|
problems = append(problems, "Schema --all contains a tool without canonical_path")
|
|
continue
|
|
}
|
|
if _, exists := allByCanonical[canonical]; exists {
|
|
problems = append(problems, fmt.Sprintf("Schema --all contains duplicate tool %s", canonical))
|
|
}
|
|
allByCanonical[canonical] = tool
|
|
}
|
|
}
|
|
|
|
groupPaths := map[string]bool{}
|
|
for _, product := range loaded.Registry.Products {
|
|
expectedProduct, renderErr := product.ToSummaryPayload()
|
|
if renderErr != nil {
|
|
problems = append(problems, fmt.Sprintf("render product %s summary: %v", product.ID, renderErr))
|
|
} else if actual, queryErr := deliverySchemaPayload(loaded, []string{product.ID}); queryErr != nil {
|
|
problems = append(problems, fmt.Sprintf("product %s is not queryable: %v", product.ID, queryErr))
|
|
} else if !schemaJSONEqual(actual["product"], expectedProduct) {
|
|
problems = append(problems, fmt.Sprintf("product %s query differs from final ProductSpec", product.ID))
|
|
}
|
|
for _, tool := range product.Tools {
|
|
canonical := tool.Identity.CanonicalPath
|
|
expectedTool, renderErr := deliveryToolPayload(tool)
|
|
if renderErr != nil {
|
|
problems = append(problems, fmt.Sprintf("render final ToolSpec %s: %v", canonical, renderErr))
|
|
} else if actual, exists := allByCanonical[canonical]; !exists {
|
|
problems = append(problems, fmt.Sprintf("Schema --all is missing final ToolSpec %s", canonical))
|
|
} else if !schemaJSONEqual(actual, expectedTool) {
|
|
problems = append(problems, fmt.Sprintf("Schema --all tool %s differs from final ToolSpec", canonical))
|
|
}
|
|
paths := append([]string{tool.Identity.CLIPath, tool.Identity.PrimaryCLIPath}, tool.Identity.Aliases...)
|
|
for _, rawPath := range paths {
|
|
tokens := splitSchemaPathTokens(rawPath)
|
|
for length := 2; length < len(tokens); length++ {
|
|
groupPaths[strings.Join(tokens[:length], " ")] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if len(allByCanonical) != len(loaded.Index.CanonicalPaths()) {
|
|
problems = append(problems, fmt.Sprintf("Schema --all contains %d tools, typed index contains %d", len(allByCanonical), len(loaded.Index.CanonicalPaths())))
|
|
}
|
|
|
|
groups := make([]string, 0, len(groupPaths))
|
|
for path := range groupPaths {
|
|
groups = append(groups, path)
|
|
}
|
|
sort.Strings(groups)
|
|
for _, path := range groups {
|
|
tokens := splitSchemaPathTokens(path)
|
|
product, ok := loaded.Index.Product(tokens[0])
|
|
if !ok {
|
|
problems = append(problems, fmt.Sprintf("group %s has no typed product", path))
|
|
continue
|
|
}
|
|
expected := make([]map[string]any, 0)
|
|
for _, tool := range product.Tools {
|
|
if !schemaToolUnderGroup(tool, path) {
|
|
continue
|
|
}
|
|
summary, renderErr := deliveryToolSummary(tool)
|
|
if renderErr != nil {
|
|
problems = append(problems, fmt.Sprintf("render group %s tool %s: %v", path, tool.Identity.CanonicalPath, renderErr))
|
|
continue
|
|
}
|
|
expected = append(expected, summary)
|
|
}
|
|
actual, queryErr := deliverySchemaPayload(loaded, []string{path})
|
|
if queryErr != nil {
|
|
problems = append(problems, fmt.Sprintf("group %s is not queryable: %v", path, queryErr))
|
|
} else if !schemaJSONEqual(actual["tools"], expected) {
|
|
problems = append(problems, fmt.Sprintf("group %s query differs from final ToolSpec summaries", path))
|
|
}
|
|
}
|
|
return sortedUniqueSchemaStrings(problems)
|
|
}
|
|
|
|
type runtimeSchemaResolvedIdentity struct {
|
|
CanonicalPath string
|
|
Source string
|
|
}
|
|
|
|
func runtimeSchemaIdentityByBound(bound BoundCommandRegistry) (map[string]runtimeSchemaResolvedIdentity, []string) {
|
|
identityByPath := map[string]runtimeSchemaResolvedIdentity{}
|
|
var conflicts []string
|
|
for _, command := range bound.Commands {
|
|
if command.Visibility != SchemaVisibilityPublic {
|
|
continue
|
|
}
|
|
canonical := strings.TrimSpace(command.CanonicalPath)
|
|
paths := append([]string{command.PrimaryCLIPath}, command.Aliases...)
|
|
for _, rawPath := range paths {
|
|
path := normalizeSchemaCLIPath(rawPath)
|
|
if path == "" || canonical == "" {
|
|
continue
|
|
}
|
|
if existing := identityByPath[path]; existing.CanonicalPath != "" && existing.CanonicalPath != canonical {
|
|
conflicts = append(conflicts, fmt.Sprintf("bound Schema path %q belongs to both %s and %s", path, existing.CanonicalPath, canonical))
|
|
continue
|
|
}
|
|
identityByPath[path] = runtimeSchemaResolvedIdentity{
|
|
CanonicalPath: canonical,
|
|
Source: strings.TrimSpace(command.Source),
|
|
}
|
|
}
|
|
}
|
|
return identityByPath, sortedUniqueSchemaStrings(conflicts)
|
|
}
|
|
|
|
func sortedUniqueSchemaStrings(values []string) []string {
|
|
seen := make(map[string]bool, len(values))
|
|
out := make([]string, 0, len(values))
|
|
for _, value := range values {
|
|
if value = strings.TrimSpace(value); value == "" || seen[value] {
|
|
continue
|
|
}
|
|
seen[value] = true
|
|
out = append(out, value)
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|
|
|
|
func addSchemaCoveredPath(coveredPaths map[string]bool, rawPath string) {
|
|
if path := normalizeSchemaCLIPath(rawPath); path != "" {
|
|
coveredPaths[path] = true
|
|
}
|
|
}
|
|
|
|
func runtimeSchemaCompletenessAgainstPaths(root *cobra.Command, exclusions []RuntimeSchemaExclusion, coveredPaths map[string]bool) RuntimeSchemaCompletenessReport {
|
|
report := RuntimeSchemaCompletenessReport{}
|
|
exclusionByPath := make(map[string]RuntimeSchemaExclusion, len(exclusions))
|
|
for _, exclusion := range exclusions {
|
|
path := normalizeSchemaCLIPath(exclusion.CLIPath)
|
|
if path == "" || strings.TrimSpace(exclusion.Reason) == "" || !exclusion.Reviewed {
|
|
report.InvalidExclusions = append(report.InvalidExclusions, firstNonEmptySchemaString(path, strings.TrimSpace(exclusion.CLIPath), "<empty>"))
|
|
continue
|
|
}
|
|
exclusion.CLIPath = path
|
|
exclusionByPath[path] = exclusion
|
|
}
|
|
|
|
seenPublic := map[string]bool{}
|
|
usedExclusions := map[string]bool{}
|
|
walkPublicRunnableLeaves(root, func(leaf *cobra.Command) {
|
|
path := normalizeSchemaCLIPath(strings.Join(commandPathParts(leaf), " "))
|
|
if path == "" {
|
|
return
|
|
}
|
|
seenPublic[path] = true
|
|
if coveredPaths[path] {
|
|
report.Covered = append(report.Covered, path)
|
|
return
|
|
}
|
|
if _, ok := exclusionByPath[path]; ok {
|
|
report.Excluded = append(report.Excluded, path)
|
|
usedExclusions[path] = true
|
|
return
|
|
}
|
|
report.Missing = append(report.Missing, path)
|
|
})
|
|
|
|
for path := range exclusionByPath {
|
|
if !seenPublic[path] || !usedExclusions[path] {
|
|
report.StaleExclusions = append(report.StaleExclusions, path)
|
|
}
|
|
}
|
|
sort.Strings(report.Covered)
|
|
sort.Strings(report.Excluded)
|
|
sort.Strings(report.Missing)
|
|
sort.Strings(report.InvalidExclusions)
|
|
sort.Strings(report.StaleExclusions)
|
|
return report
|
|
}
|
|
|
|
func walkPublicRunnableLeaves(root *cobra.Command, fn func(*cobra.Command)) {
|
|
if root == nil {
|
|
return
|
|
}
|
|
var walk func(*cobra.Command)
|
|
walk = func(command *cobra.Command) {
|
|
if command.Runnable() && !command.HasSubCommands() {
|
|
fn(command)
|
|
return
|
|
}
|
|
for _, child := range command.Commands() {
|
|
if child.Name() == "help" || !child.IsAvailableCommand() {
|
|
continue
|
|
}
|
|
walk(child)
|
|
}
|
|
}
|
|
walk(root)
|
|
}
|
|
|
|
func normalizeSchemaCLIPath(path string) string {
|
|
parts := strings.Fields(strings.TrimSpace(path))
|
|
if len(parts) > 0 && parts[0] == "dws" {
|
|
parts = parts[1:]
|
|
}
|
|
return strings.Join(parts, " ")
|
|
}
|