Skip to content

Manifest Validation

Shoehorn validates manifests against a JSON Schema and custom rules before applying them to the catalog. This document describes all validation checks.

FieldRule
schemaVersionMust be 1 (integer)
service.idMust match ^[a-z0-9]+(-[a-z0-9]+)*$ (kebab-case)
service.nameNon-empty string
service.typeMust be a valid entity type
ownerAt least one entry required (except catalog-source type)
FieldConstraint
service.idLowercase, hyphens only, no underscores or spaces
service.typeOne of: service, api, frontend, database, library, team, system, resource, domain, extras, catalog-source
service.tierOne of: platinum, gold, silver, bronze, critical, high, medium, low
lifecycleOne of: production, staging, development, deprecated, experimental
tagsArray of lowercase strings
links[].urlMust start with http:// or https://
links[].nameRequired, non-empty
relations[].typeMust be a valid relation type
relations[].targetMust match format <type>:<identifier>
integrations.licenses[].seatsMinimum 1 (if present)
integrations.runbooks[].severityOne of: critical, high, medium, low

Beyond schema validation, these additional checks are applied:

  • Must not contain uppercase letters
  • Must not contain underscores (use hyphens)
  • Must not start or end with a hyphen
  • Must be unique within the tenant
  • At least one owner must be specified (unless type is catalog-source)
  • Owner type must be one of: team, user, productOwner, designer, stakeholder, support, manager
  • Owner id must be non-empty
  • URL must be a valid HTTP or HTTPS URL
  • Icon (if specified) must be a recognized icon name
  • Target format must be <type>:<identifier>
  • Valid target types: service, database, topic, team, channel, link, oncall, system, resource
  • Self-referencing relations produce a warning
  • http.baseUrl must be a valid URL if present
  • http.openapi can be a file path or URL
  • graphql.endpoint must be a valid URL or path if present
  • grpc.package must be non-empty if present

The validation endpoint returns:

{
"valid": true,
"errors": [],
"warnings": [
{
"field": "tags",
"message": "Tag 'MyTag' should be lowercase",
"severity": "warning"
}
]
}
FieldDescription
validtrue if no errors (warnings are allowed)
errorsArray of validation errors (blocks import)
warningsArray of warnings (does not block import)
ErrorCauseFix
service.id is requiredMissing service IDAdd service.id field
service.id must match patternInvalid characters in IDUse lowercase kebab-case only
service.type must be one ofInvalid entity typeUse a supported type
owner is requiredNo owner specifiedAdd at least one owner entry
links[0].url must be a valid URLInvalid link URLUse http:// or https:// prefix
relations[0].target must match formatBad relation targetUse type:identifier format

The analyze endpoint (POST /api/v1/manifest/analyze) provides additional scoring:

CategoryWeightWhat It Checks
Documentation25%README, description, runbooks, changelog
Metadata35%Name, type, tier, lifecycle, tags, links
Relationships20%Relations, owner assignments
Interfaces20%HTTP, gRPC, GraphQL definitions

The analyzer provides prioritized recommendations:

  • High: Missing owner, no lifecycle set, no description
  • Medium: No tags, no links, no relations
  • Low: Missing interfaces, no runbooks, no changelog