module Noir::LocatorKeys

Overview

Every slot in CodeLocator, declared once.

The table below is the registry: the constants, the per-phase reset lists, and spec/unit_test/models/locator_keys_spec.cr are all generated from it, so a key cannot exist without a lifecycle and a lifecycle cannot be declared for a key nothing uses.

Fields: {CONSTANT, name, :array | :single, lifecycle, owning subsystem}.

Every one of these is written by the detector pass and drained during analysis, which is what :detect_scoped means — see LocatorKey::Lifecycle. The runtime-minted Express family below is the only :analyze_scoped slot.

Defined in:

models/locator_keys.cr

Constant Summary

ANDROID_ASSETLINKS = ::Noir::LocatorKey(Array(String)).new("android-assetlinks", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/mobile/well_known")
ANDROID_MANIFEST = ::Noir::LocatorKey(Array(String)).new("android-manifest", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/mobile/android")
APACHE_HTTPD_SPEC = ::Noir::LocatorKey(Array(String)).new("apache-httpd-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/apache_httpd")
APISIX_JSON = ::Noir::LocatorKey(Array(String)).new("apisix-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/apisix")
APISIX_YAML = ::Noir::LocatorKey(Array(String)).new("apisix-yaml", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/apisix")
APPWRITE_CONFIG = ::Noir::LocatorKey(Array(String)).new("appwrite-config", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/appwrite")
ARRAY_KEYS = [ANDROID_ASSETLINKS, ANDROID_MANIFEST, APACHE_HTTPD_SPEC, APISIX_JSON, APISIX_YAML, APPWRITE_CONFIG, ASYNCAPI_JSON, ASYNCAPI_YAML, AWS_CDK_SPEC, AWS_CLOUDFORMATION_SPEC, AZURE_FUNCTIONS_SPEC, BRUNO_BRU, BURP_SITEMAP, CADDY_SPEC, CAIDO_JSON, CLOUDFLARE_WRANGLER_SPEC, DIRECTUS_SNAPSHOT, ENVOY_JSON, ENVOY_YAML, GRAPHQL_SDL, GRPC_PROTO, HAR_PATH, HASURA_REST_ENDPOINTS, HASURA_TABLES, HTTP_FILE, INSOMNIA_JSON, INSOMNIA_YAML, IOS_AASA, IOS_ENTITLEMENTS, IOS_INFO_PLIST, ISTIO_VIRTUALSERVICE_SPEC, K8S_GATEWAY_API_SPEC, K8S_INGRESS_SPEC, KAMAL_SPEC, KONG_SPEC, MITMPROXY_PATH, NETLIFY_REDIRECTS, NETLIFY_TOML, NGINX_SPEC, OAS3_JSON, OAS3_YAML, ODATA_SPEC, OPENRPC_JSON, PAYLOAD_COLLECTION, PAYLOAD_CONFIG, PAYLOAD_GLOBAL, POSTMAN_JSON, RAML_SPEC, SERVERLESS_FRAMEWORK_SPEC, SMITHY_SPEC, STRAPI_ROUTES, STRAPI_SCHEMA, SUPABASE_CONFIG, SUPABASE_MIGRATION, SWAGGER_JSON, SWAGGER_YAML, TERRAFORM_SPEC, TRAEFIK_SPEC, TYPESPEC_SPEC, VERCEL_SPEC, WSDL_SPEC, ZAP_SITES_TREE] of ::Noir::LocatorKey(Array(String))

The array literals are what force the constants above into existence. Do not "simplify" this into per-constant registration side effects: Crystal may elide an unused constant's initializer, and the reset lists would silently come up short.

ASYNCAPI_JSON = ::Noir::LocatorKey(Array(String)).new("asyncapi-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/asyncapi")
ASYNCAPI_YAML = ::Noir::LocatorKey(Array(String)).new("asyncapi-yaml", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/asyncapi")
AWS_CDK_SPEC = ::Noir::LocatorKey(Array(String)).new("aws-cdk-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/aws_cdk")
AWS_CLOUDFORMATION_SPEC = ::Noir::LocatorKey(Array(String)).new("aws-cloudformation-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/aws_cloudformation")
AZURE_FUNCTIONS_SPEC = ::Noir::LocatorKey(Array(String)).new("azure-functions-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/azure_functions")
BRUNO_BRU = ::Noir::LocatorKey(Array(String)).new("bruno-bru", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/bruno")
BURP_SITEMAP = ::Noir::LocatorKey(Array(String)).new("burp-sitemap", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/burp")
CADDY_SPEC = ::Noir::LocatorKey(Array(String)).new("caddy-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/caddy")
CAIDO_JSON = ::Noir::LocatorKey(Array(String)).new("caido-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/caido")
CLOUDFLARE_WRANGLER_SPEC = ::Noir::LocatorKey(Array(String)).new("cloudflare-wrangler-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/cloudflare_wrangler")
CS_APINET_MVC_ROUTECONFIG = ::Noir::LocatorKey(String).new("cs-apinet-mvc-routeconfig", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/csharp/aspnet_mvc")
DECLARATIONS = [{:ANDROID_ASSETLINKS, "android-assetlinks", :array, :detect_scoped, "detector/mobile/well_known"}, {:ANDROID_MANIFEST, "android-manifest", :array, :detect_scoped, "detector/mobile/android"}, {:APACHE_HTTPD_SPEC, "apache-httpd-spec", :array, :detect_scoped, "detector/specification/apache_httpd"}, {:APISIX_JSON, "apisix-json", :array, :detect_scoped, "detector/specification/apisix"}, {:APISIX_YAML, "apisix-yaml", :array, :detect_scoped, "detector/specification/apisix"}, {:APPWRITE_CONFIG, "appwrite-config", :array, :detect_scoped, "detector/specification/appwrite"}, {:ASYNCAPI_JSON, "asyncapi-json", :array, :detect_scoped, "detector/specification/asyncapi"}, {:ASYNCAPI_YAML, "asyncapi-yaml", :array, :detect_scoped, "detector/specification/asyncapi"}, {:AWS_CDK_SPEC, "aws-cdk-spec", :array, :detect_scoped, "detector/specification/aws_cdk"}, {:AWS_CLOUDFORMATION_SPEC, "aws-cloudformation-spec", :array, :detect_scoped, "detector/specification/aws_cloudformation"}, {:AZURE_FUNCTIONS_SPEC, "azure-functions-spec", :array, :detect_scoped, "detector/specification/azure_functions"}, {:BRUNO_BRU, "bruno-bru", :array, :detect_scoped, "detector/specification/bruno"}, {:BURP_SITEMAP, "burp-sitemap", :array, :detect_scoped, "detector/specification/burp"}, {:CADDY_SPEC, "caddy-spec", :array, :detect_scoped, "detector/specification/caddy"}, {:CAIDO_JSON, "caido-json", :array, :detect_scoped, "detector/specification/caido"}, {:CLOUDFLARE_WRANGLER_SPEC, "cloudflare-wrangler-spec", :array, :detect_scoped, "detector/specification/cloudflare_wrangler"}, {:CS_APINET_MVC_ROUTECONFIG, "cs-apinet-mvc-routeconfig", :single, :detect_scoped, "detector/csharp/aspnet_mvc"}, {:DIRECTUS_SNAPSHOT, "directus-snapshot", :array, :detect_scoped, "detector/specification/directus"}, {:ENVOY_JSON, "envoy-json", :array, :detect_scoped, "detector/specification/envoy"}, {:ENVOY_YAML, "envoy-yaml", :array, :detect_scoped, "detector/specification/envoy"}, {:GRAPHQL_SDL, "graphql-sdl", :array, :detect_scoped, "detector/specification/graphql_sdl"}, {:GRPC_PROTO, "grpc-proto", :array, :detect_scoped, "detector/specification/grpc"}, {:HAR_PATH, "har-path", :array, :detect_scoped, "detector/specification/har"}, {:HASURA_REST_ENDPOINTS, "hasura-rest-endpoints", :array, :detect_scoped, "detector/specification/hasura"}, {:HASURA_TABLES, "hasura-tables", :array, :detect_scoped, "detector/specification/hasura"}, {:HTTP_FILE, "http-file", :array, :detect_scoped, "detector/specification/http_file"}, {:INSOMNIA_JSON, "insomnia-json", :array, :detect_scoped, "detector/specification/insomnia"}, {:INSOMNIA_YAML, "insomnia-yaml", :array, :detect_scoped, "detector/specification/insomnia"}, {:IOS_AASA, "ios-aasa", :array, :detect_scoped, "detector/mobile/well_known"}, {:IOS_ENTITLEMENTS, "ios-entitlements", :array, :detect_scoped, "detector/mobile/ios"}, {:IOS_INFO_PLIST, "ios-info-plist", :array, :detect_scoped, "detector/mobile/ios"}, {:ISTIO_VIRTUALSERVICE_SPEC, "istio-virtualservice-spec", :array, :detect_scoped, "detector/specification/istio_virtualservice"}, {:K8S_GATEWAY_API_SPEC, "k8s-gateway-api-spec", :array, :detect_scoped, "detector/specification/k8s_gateway_api"}, {:K8S_INGRESS_SPEC, "k8s-ingress-spec", :array, :detect_scoped, "detector/specification/k8s_ingress"}, {:KAMAL_SPEC, "kamal-spec", :array, :detect_scoped, "detector/specification/kamal"}, {:KONG_SPEC, "kong-spec", :array, :detect_scoped, "detector/specification/kong"}, {:MITMPROXY_PATH, "mitmproxy-path", :array, :detect_scoped, "detector/specification/mitmproxy"}, {:NETLIFY_REDIRECTS, "netlify-redirects", :array, :detect_scoped, "detector/specification/netlify"}, {:NETLIFY_TOML, "netlify-toml", :array, :detect_scoped, "detector/specification/netlify"}, {:NGINX_SPEC, "nginx-spec", :array, :detect_scoped, "detector/specification/nginx"}, {:OAS3_JSON, "oas3-json", :array, :detect_scoped, "detector/specification/oas3"}, {:OAS3_YAML, "oas3-yaml", :array, :detect_scoped, "detector/specification/oas3"}, {:ODATA_SPEC, "odata-spec", :array, :detect_scoped, "detector/specification/odata"}, {:OPENRPC_JSON, "openrpc-json", :array, :detect_scoped, "detector/specification/openrpc"}, {:PAYLOAD_COLLECTION, "payload-collection", :array, :detect_scoped, "detector/specification/payload_cms"}, {:PAYLOAD_CONFIG, "payload-config", :array, :detect_scoped, "detector/specification/payload_cms"}, {:PAYLOAD_GLOBAL, "payload-global", :array, :detect_scoped, "detector/specification/payload_cms"}, {:POSTMAN_JSON, "postman-json", :array, :detect_scoped, "detector/specification/postman"}, {:RAML_SPEC, "raml-spec", :array, :detect_scoped, "detector/specification/raml"}, {:SERVERLESS_FRAMEWORK_SPEC, "serverless-framework-spec", :array, :detect_scoped, "detector/specification/serverless_framework"}, {:SMITHY_SPEC, "smithy-spec", :array, :detect_scoped, "detector/specification/smithy"}, {:STRAPI_ROUTES, "strapi-routes", :array, :detect_scoped, "detector/specification/strapi"}, {:STRAPI_SCHEMA, "strapi-schema", :array, :detect_scoped, "detector/specification/strapi"}, {:SUPABASE_CONFIG, "supabase-config", :array, :detect_scoped, "detector/specification/supabase"}, {:SUPABASE_MIGRATION, "supabase-migration", :array, :detect_scoped, "detector/specification/supabase"}, {:SWAGGER_JSON, "swagger-json", :array, :detect_scoped, "detector/specification/oas2"}, {:SWAGGER_YAML, "swagger-yaml", :array, :detect_scoped, "detector/specification/oas2"}, {:TERRAFORM_SPEC, "terraform-spec", :array, :detect_scoped, "detector/specification/terraform"}, {:TRAEFIK_SPEC, "traefik-spec", :array, :detect_scoped, "detector/specification/traefik"}, {:TYPESPEC_SPEC, "typespec-spec", :array, :detect_scoped, "detector/specification/typespec"}, {:VERCEL_SPEC, "vercel-spec", :array, :detect_scoped, "detector/specification/vercel"}, {:WSDL_SPEC, "wsdl-spec", :array, :detect_scoped, "detector/specification/wsdl"}, {:ZAP_SITES_TREE, "zap-sites-tree", :array, :detect_scoped, "detector/specification/zap_sites_tree"}]
DIRECTUS_SNAPSHOT = ::Noir::LocatorKey(Array(String)).new("directus-snapshot", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/directus")
ENVOY_JSON = ::Noir::LocatorKey(Array(String)).new("envoy-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/envoy")
ENVOY_YAML = ::Noir::LocatorKey(Array(String)).new("envoy-yaml", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/envoy")
EXPRESS_ROUTER_PREFIX = ::Noir::LocatorKeyNamespace.new("express_router_prefix", ::Noir::LocatorKey::Lifecycle::AnalyzeScoped, "analyzer/javascript")

Runtime-minted key family: express_router_prefix:<file>[:<function>].

The prose above this declaration always said "written by the Express router-mount scanner and by Koa", but the owner field said analyzer/javascript/express — which covers express.cr and express/router_mount_scanner.cr and excludes koa.cr. The comment and the metadata disagreed, and nothing checked the metadata beyond it being non-blank, so the field that exists to answer "who writes this slot" was the one place in the typed-key registry that was wrong.

The owner is the JavaScript analyzer family, which is what both writers actually are. They mint through ExpressConstants.file_key / .function_key, and Noir::JSRouteExtractor reads it — two analyzers and a shared extractor, none of which is "express" specifically.

spec/unit_test/models/locator_ownership_spec.cr now verifies this against the source rather than trusting it.

GRAPHQL_SDL = ::Noir::LocatorKey(Array(String)).new("graphql-sdl", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/graphql_sdl")
GRPC_PROTO = ::Noir::LocatorKey(Array(String)).new("grpc-proto", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/grpc")
HAR_PATH = ::Noir::LocatorKey(Array(String)).new("har-path", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/har")
HASURA_REST_ENDPOINTS = ::Noir::LocatorKey(Array(String)).new("hasura-rest-endpoints", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/hasura")
HASURA_TABLES = ::Noir::LocatorKey(Array(String)).new("hasura-tables", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/hasura")
HTTP_FILE = ::Noir::LocatorKey(Array(String)).new("http-file", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/http_file")
INSOMNIA_JSON = ::Noir::LocatorKey(Array(String)).new("insomnia-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/insomnia")
INSOMNIA_YAML = ::Noir::LocatorKey(Array(String)).new("insomnia-yaml", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/insomnia")
IOS_AASA = ::Noir::LocatorKey(Array(String)).new("ios-aasa", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/mobile/well_known")
IOS_ENTITLEMENTS = ::Noir::LocatorKey(Array(String)).new("ios-entitlements", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/mobile/ios")
IOS_INFO_PLIST = ::Noir::LocatorKey(Array(String)).new("ios-info-plist", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/mobile/ios")
ISTIO_VIRTUALSERVICE_SPEC = ::Noir::LocatorKey(Array(String)).new("istio-virtualservice-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/istio_virtualservice")
K8S_GATEWAY_API_SPEC = ::Noir::LocatorKey(Array(String)).new("k8s-gateway-api-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/k8s_gateway_api")
K8S_INGRESS_SPEC = ::Noir::LocatorKey(Array(String)).new("k8s-ingress-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/k8s_ingress")
KAMAL_SPEC = ::Noir::LocatorKey(Array(String)).new("kamal-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/kamal")
KONG_SPEC = ::Noir::LocatorKey(Array(String)).new("kong-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/kong")
MITMPROXY_PATH = ::Noir::LocatorKey(Array(String)).new("mitmproxy-path", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/mitmproxy")
NAMESPACES = [EXPRESS_ROUTER_PREFIX]
NETLIFY_REDIRECTS = ::Noir::LocatorKey(Array(String)).new("netlify-redirects", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/netlify")
NETLIFY_TOML = ::Noir::LocatorKey(Array(String)).new("netlify-toml", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/netlify")
NGINX_SPEC = ::Noir::LocatorKey(Array(String)).new("nginx-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/nginx")
OAS3_JSON = ::Noir::LocatorKey(Array(String)).new("oas3-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/oas3")
OAS3_YAML = ::Noir::LocatorKey(Array(String)).new("oas3-yaml", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/oas3")
ODATA_SPEC = ::Noir::LocatorKey(Array(String)).new("odata-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/odata")
OPENRPC_JSON = ::Noir::LocatorKey(Array(String)).new("openrpc-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/openrpc")
PAYLOAD_COLLECTION = ::Noir::LocatorKey(Array(String)).new("payload-collection", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/payload_cms")
PAYLOAD_CONFIG = ::Noir::LocatorKey(Array(String)).new("payload-config", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/payload_cms")
PAYLOAD_GLOBAL = ::Noir::LocatorKey(Array(String)).new("payload-global", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/payload_cms")
POSTMAN_JSON = ::Noir::LocatorKey(Array(String)).new("postman-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/postman")
RAML_SPEC = ::Noir::LocatorKey(Array(String)).new("raml-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/raml")
SERVERLESS_FRAMEWORK_SPEC = ::Noir::LocatorKey(Array(String)).new("serverless-framework-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/serverless_framework")
SINGLE_KEYS = [CS_APINET_MVC_ROUTECONFIG] of ::Noir::LocatorKey(String)
SMITHY_SPEC = ::Noir::LocatorKey(Array(String)).new("smithy-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/smithy")
STRAPI_ROUTES = ::Noir::LocatorKey(Array(String)).new("strapi-routes", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/strapi")
STRAPI_SCHEMA = ::Noir::LocatorKey(Array(String)).new("strapi-schema", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/strapi")
SUPABASE_CONFIG = ::Noir::LocatorKey(Array(String)).new("supabase-config", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/supabase")
SUPABASE_MIGRATION = ::Noir::LocatorKey(Array(String)).new("supabase-migration", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/supabase")
SWAGGER_JSON = ::Noir::LocatorKey(Array(String)).new("swagger-json", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/oas2")
SWAGGER_YAML = ::Noir::LocatorKey(Array(String)).new("swagger-yaml", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/oas2")
TERRAFORM_SPEC = ::Noir::LocatorKey(Array(String)).new("terraform-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/terraform")
TRAEFIK_SPEC = ::Noir::LocatorKey(Array(String)).new("traefik-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/traefik")
TYPESPEC_SPEC = ::Noir::LocatorKey(Array(String)).new("typespec-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/typespec")
VERCEL_SPEC = ::Noir::LocatorKey(Array(String)).new("vercel-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/vercel")
WSDL_SPEC = ::Noir::LocatorKey(Array(String)).new("wsdl-spec", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/wsdl")
ZAP_SITES_TREE = ::Noir::LocatorKey(Array(String)).new("zap-sites-tree", ::Noir::LocatorKey::Lifecycle::DetectScoped, "detector/specification/zap_sites_tree")

Class Method Summary

Class Method Detail

def self.reset(phase : Noir::LocatorKey::Lifecycle) : Nil #

Drop everything phase owns.

Called at the top of the phase, before it writes anything, so a second scan in the same process cannot read the first one's registrations. This replaces a hand-written list at the top of detect_techs that named six of the 64 keys — the other 58 were never cleared at all, which is why SpecificationEngine#each_spec_file needed a File.exists? guard to avoid reading a previous scan's paths.

The phases are separate on purpose. Detector-written keys are drained during analysis, so clearing them at analysis start would destroy the scan; the Express keys are written and read inside one analysis pass and must not survive into the next.


[View source]