Files
dingtalk-workspace-cli/scripts/policy/check-schema-command-registry.sh

114 lines
5.7 KiB
Bash
Executable File

#!/bin/sh
set -eu
# Validate the reviewed CommandRegistry as an input contract. This check is
# deliberately independent of Catalog/interface/provenance output policy so a
# malformed identity source cannot be hidden by a healthy generated snapshot.
ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)"
cd "$ROOT"
. "$ROOT/scripts/policy/search.sh"
. "$ROOT/scripts/policy/policy-runtime.sh"
policy_prepare_runtime "$ROOT"
if [ -e internal/cli/schema_native_contracts.go ] ||
[ -e internal/cli/schema_native_contracts_generated.go ] ||
policy_search_go 'ApplyNativeRuntimeSchemaContracts|nativeRuntimeSchemaContracts|runtimeSchemaIdentityCandidate' internal/cli; then
printf '%s\n' 'native Schema identity materialization must not be reintroduced' >&2
exit 1
fi
# Legacy hint maps used to select primary CLI paths and discover helper roots.
# They are identity/navigation sources, so bringing any of them back would
# silently reintroduce a second source beside CommandRegistry.
if policy_search_go '(schemaPrimaryCLIPath|RuntimeSchemaRootHint|RegisterRuntimeSchemaRoot|PrimaryCLIPaths|RegisterSchemaProductVisibility|SchemaProductVisibilityFor|productVisibility)' \
internal/cli; then
printf '%s\n' 'legacy Schema hint navigation or visibility sources must not be reintroduced' >&2
exit 1
fi
if [ ! -f internal/cli/schema_command_registry.schema.json ] ||
! jq -e '
."$schema" == "./schema_command_registry.schema.json" and
.version == 1 and
(.products | type) == "array" and
(.products | length) > 0
' internal/cli/schema_command_registry.json >/dev/null; then
printf '%s\n' 'reviewed CommandRegistry is missing its local JSON Schema contract' >&2
exit 1
fi
# The registry argument is validation-only and all go:generate outputs must be
# downstream assets. Reject any directive that targets the reviewed input.
if ! grep -Eq '^//go:generate .*cmd_schema_agent_metadata .* -registry internal/cli/schema_command_registry\.json ' internal/cli/schema_agent_metadata.go; then
printf '%s\n' 'go generate must validate the reviewed CommandRegistry explicitly' >&2
exit 1
fi
if policy_search_go '^//go:generate .*-(output|output-dir|audit-output)(=|[[:space:]]+)([^[:space:]]*/)?schema_command_registry\.json([[:space:]]|$)' \
internal/cli ||
policy_search_go '^//go:generate .*(>|>>)[[:space:]]*([^[:space:]]*/)?schema_command_registry\.json([[:space:]]|$)' \
internal/cli; then
printf '%s\n' 'go generate must never overwrite the reviewed CommandRegistry' >&2
exit 1
fi
# Embedded Agent/MCP/parameter metadata is intentionally expensive and must be
# parsed only through its sync.Once accessor. Each raw loader is allowed at
# exactly two production locations: its declaration and the assignment inside
# that accessor. Any third reference is an eager initializer or an accessor
# bypass and fails this static check.
check_schema_loader_references() {
loader="$1"
allowed="$2"
references="$(policy_search_production_go "${loader}\\(" internal/cli || true)"
count="$(printf '%s\n' "$references" | awk 'NF { count++ } END { print count + 0 }')"
if [ "$count" -ne 2 ]; then
printf 'Schema loader %s has %s production references, want exactly declaration + lazy accessor\n' "$loader" "$count" >&2
printf '%s\n' "$references" >&2
exit 1
fi
unexpected="$(printf '%s\n' "$references" | grep -Ev "$allowed" || true)"
if [ -n "$unexpected" ]; then
printf 'Schema loader %s is called outside its lazy accessor:\n%s\n' "$loader" "$unexpected" >&2
exit 1
fi
}
check_schema_loader_references \
'loadEmbeddedAgentMetadata' \
'^internal/cli/schema_agent_metadata\.go:[0-9]+:(func loadEmbeddedAgentMetadata\(\) embeddedAgentMetadata \{|[[:space:]]*runtimeEmbeddedAgentMetadataLazy\.metadata = loadEmbeddedAgentMetadata\(\))$'
check_schema_loader_references \
'loadEmbeddedMCPMetadata' \
'^internal/cli/runtime_schema\.go:[0-9]+:(func loadEmbeddedMCPMetadata\(\) embeddedMCPMetadata \{|[[:space:]]*runtimeEmbeddedMCPMetadataLazy\.metadata = loadEmbeddedMCPMetadata\(\))$'
check_schema_loader_references \
'loadSchemaParameterBindings' \
'^internal/cli/schema_parameter_bindings\.go:[0-9]+:(func loadSchemaParameterBindings\(\) \(schemaParameterBindingSnapshot, error\) \{|[[:space:]]*runtimeSchemaParameterBindingsLazy\.snapshot, runtimeSchemaParameterBindingsLazy\.err = loadSchemaParameterBindings\(\))$'
# Catch the common direct eager form statically; the fresh-process tests below
# additionally catch indirect or multi-line package initializers.
if policy_search_production_go '^[[:space:]]*var .*=[[:space:]]*(runtimeAgentMetadata|runtimeMCPMetadata|runtimeSchemaParameterBindingData)\(' \
internal/cli; then
printf '%s\n' 'Schema metadata accessors must not be called from package-scope variable initializers' >&2
exit 1
fi
# Root construction may register the schema command, but app production code
# must never parse or inspect generation metadata. The schema command reads the
# already embedded Catalog only when it is actually executed.
if policy_search_production_go '(loadEmbeddedAgentMetadata|loadEmbeddedMCPMetadata|loadSchemaParameterBindings|runtimeAgentMetadata|runtimeMCPMetadata|runtimeSchemaParameterBindingData|EmbeddedSchemaParameterBindings)\(' \
internal/app; then
printf '%s\n' 'root/app production code must not access Schema generation metadata loaders or accessors' >&2
exit 1
fi
go test ./internal/cli \
-run '^(TestCommandRegistry.*|TestDecodeCommandRegistry.*|TestBuildEffectiveCommandRegistry.*|TestBindEffectiveCommandRegistry.*|TestRuntimeSchemaMetadataLoadsOnlyOnDemand)$' \
-count=1
go test ./internal/app \
-run '^TestOrdinaryRootCommandsDoNotLoadSchemaMetadata$' \
-count=1
printf 'schema CommandRegistry check: ok (%s reviewed commands)\n' \
"$(jq '[.products[].tools[]] | length' internal/cli/schema_command_registry.json)"