SIGN IN SIGN UP

engine: the manifest, its schema, and a validator that names the line

schemas/manifest.v1.json is the source of truth for the whole configuration
surface: services, database and golden and subset, egress rules, personas,
workflows, invariants, insights, load, runtime, and the GitHub integration.
The full surface is defined now, before most of it is implemented, so that the
manifest never changes shape mid build. pkg/schema mirrors it in Go.

internal/manifest loads, validates, normalizes, and explains it. Three
decisions shape the package.

Unknown keys are errors, not warnings. A silently ignored key produces an
environment that is subtly not what the user asked for, and they find out in
production. Every rejection names the line, and a near miss gets a suggestion,
so "unknown key healthpath" becomes a fix rather than a search.

Problems are collected rather than returned one at a time. Fixing a manifest by
rerunning the command once per problem is an experience a validator can
trivially avoid. The report is capped at forty and says how many it is not
showing, because locating each problem walks the document and an unbounded
report is quadratic as well as unhelpful.

Normalization happens exactly once, at load, and is idempotent under a property
test. Every later package reads a manifest with defaults applied and paths
cleaned and confined, so no downstream code re-derives what the default health
path was.

The validator carries the rules a JSON Schema cannot express: port collisions,
dependency cycles reported as a readable chain, paths that escape the
repository, build arguments named or shaped like secrets, sandbox rules with no
credential to check against the live key formats, egress rules that can never
apply, and invariants that could write. Two defaults are promises rather than
conveniences and are called out as such in the code: egress blocks by default,
and a fork gets an environment only when a maintainer labels it.

The parser is fuzzed. Two bounds came out of that: a cap on nodes walked, and
the discovery that an exhausted alias scan cannot claim a document has no
aliases, while the decoder that runs next expands them. An unscannable document
is now refused rather than passed through.

Failure paths covered:
  a typo silently changes an environment: TestParse_UnknownKeyIsAnErrorWithALineAndASuggestion
  a manifest from a newer build: TestParse_RejectsANewerSchemaVersion
  an alias bomb: TestParse_RejectsAnchorsAndAliases, TestParse_RefusesADocumentTooLargeToScanForAliases
  a path escaping the repository: TestParse_RejectsPathsOutsideTheRepository
  two services on one port: TestParse_RejectsAPortCollision
  a dependency cycle: TestParse_RejectsADependencyCycle
  a credential committed in the manifest: TestParse_RejectsACredentialShapedLiteralValue
  a secret baked into image metadata: TestParse_RejectsASecretShapedBuildArgument
  an invariant that could write: TestParse_RejectsAnInvariantThatCouldWrite (11 cases)
  an unbounded problem report: TestParse_ReportsAtMostAFixedNumberOfProblems
  normalization changing meaning on reload: TestNormalize_IsIdempotent (property)
  a pathologically slow parse: TestParse_NoCorpusInputIsPathologicallySlow

Fuzzed 325,000 executions with no crashes; slowest corpus input parses in
222 microseconds. Coverage 87.2 percent.

Signed-off-by: Vir Sanghavi <Virrsanghavi@gmail.com>
V
Vir Sanghavi committed
318f08e9f1b392967a010c3a2b53ac77ccfcbc5d
Parent: 6bf4142