validation

package
v3.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package validation checks a contract across three layers — structural (JSON Schema), cross-field consistency, and policy enforcement — and reports errors and warnings. It supports local-only policy resolution as well as recursive, ref-based resolution through a pluggable BundleResolver.

Index

Examples

Constants

View Source
const PolicySchemaPath = "policy/schema.json"

PolicySchemaPath is the fixed path where policy schemas are located inside referenced bundles, as documented in the JSON Schema specification.

Variables

This section is empty.

Functions

func ResolvePoliciesFromBundle

func ResolvePoliciesFromBundle(c *contract.Contract, bundleFS fs.FS) ([]ResolvedPolicy, ValidationResult)

ResolvePoliciesFromBundle resolves policy sources from a contract using only the local bundle filesystem. This is the default resolver used when no external resolver (OCI/file) is configured. It compiles local schema files and skips external refs (which are validated structurally but not enforced without a resolver).

func ResolvePoliciesWithResolver

func ResolvePoliciesWithResolver(ctx context.Context, c *contract.Contract, bundleFS fs.FS, resolver BundleResolver) ([]ResolvedPolicy, ValidationResult)

ResolvePoliciesWithResolver resolves all policy sources, including ref-based policies, using the provided BundleResolver. It recurses into referenced bundles' own policies with cycle detection. If resolver is nil, ref-based policies produce a hard POLICY_REF_UNRESOLVED error (fail closed).

func SchemaBytes

func SchemaBytes() []byte

SchemaBytes returns the raw embedded JSON Schema bytes for the supported version (2.0). This is used by the doc package to extract field descriptions.

Types

type BundleResolver

type BundleResolver interface {
	ResolveBundle(ctx context.Context, ref string) (*contract.Bundle, error)
}

BundleResolver resolves a ref string (OCI or local) into a contract Bundle. This abstracts away whether the ref is oci:// or file://.

type Coverage

type Coverage struct {
	Evaluated int `json:"evaluated"`
	Required  int `json:"required"`
}

Coverage reports how many of the contract's REQUIRED assertions were actually evaluated (Outcome=Observed). Explanatory metadata; it NEVER changes the aggregate compliance state (INV-2). Computed in the same pass as Evaluate.

func Evaluate

Evaluate reasons over Contract x Evidence -> typed Findings + Coverage. It emits a confirmed violation ONLY when a matching observation has Outcome=Observed AND its payload contradicts the contract; a required assertion with no usable observation yields a SeverityUnknown finding. The engine is pure and stateless: it reads the operator-stamped Outcome and applies no temporal or k8s logic. Spec section 4.

Example

ExampleEvaluate is the canonical "custom collector" flow shown in docs/collectors.md: construct a Contract, have a collector produce a validated EvidenceSet, then call the pure engine and inspect Findings + Coverage. It is a compiled, run test (the // Output line is asserted by `go test`), so the documentation snippet can never drift from an API that actually exists.

package main

import (
	"fmt"
	"time"

	"github.com/trianalab/pacto/v3/pkg/contract"
	"github.com/trianalab/pacto/v3/pkg/evidence"
	"github.com/trianalab/pacto/v3/pkg/validation"
)

func main() {
	// 1. The contract declares intent (loaded from a bundle in real use).
	c := contract.Contract{
		Service:    contract.Service{Name: "orders", Version: "1.0.0"},
		Interfaces: []contract.Interface{{Name: "public-api", Type: "openapi", Ref: "interfaces/openapi.yaml"}},
	}

	// 2. A collector observes the running environment and produces an EvidenceSet.
	prov := evidence.Provenance{Collector: "example", DetectedAt: time.Unix(0, 0)}
	ev := evidence.EvidenceSet{
		Subject:     evidence.SubjectRef{Kind: "service", Name: "orders"},
		ContractRef: "oci://example/orders:1.0.0",
		Source:      "example",
		ObservedAt:  time.Unix(0, 0),
		Observations: []evidence.Observation{
			evidence.NewInterfaceObserved(evidence.SubjectRef{Kind: "interface", Name: "public-api"}, "openapi", true, prov),
		},
	}

	// 3. The pure engine evaluates Contract x Evidence.
	findings, coverage := validation.Evaluate(c, ev)

	fmt.Printf("findings=%d evaluated=%d/%d\n", len(findings), coverage.Evaluated, coverage.Required)
}
Output:
findings=0 evaluated=1/1

type ResolvedPolicy

type ResolvedPolicy struct {
	Origin string             // human-readable origin (e.g., "policies[0]", "oci://ghcr.io/acme/policy:1.0.0")
	Schema *jsonschema.Schema // compiled JSON Schema
}

ResolvedPolicy holds a compiled policy schema and its origin for error reporting.

type ValidationResult

type ValidationResult struct {
	Errors   []contract.ValidationError
	Warnings []contract.ValidationWarning
}

ValidationResult aggregates errors and warnings from all validation layers.

func EnforcePolicies

func EnforcePolicies(rawYAML []byte, policies []ResolvedPolicy) ValidationResult

EnforcePolicies validates the contract document against all resolved policy schemas. Each policy is applied independently with strict AND semantics: the contract must satisfy every policy. Contradictory policies naturally fail — no precedence or override logic is applied.

func Validate

func Validate(c *contract.Contract, rawYAML []byte, bundleFS fs.FS) ValidationResult

Validate runs all three validation layers in order on the given contract. If structural validation fails, subsequent layers are skipped. The rawYAML parameter is the original YAML bytes for JSON Schema validation. The bundleFS parameter provides access to bundle files for cross-field validation.

func ValidateCrossField

func ValidateCrossField(c *contract.Contract, bundleFS fs.FS) ValidationResult

ValidateCrossField performs Layer 2 validation: cross-field consistency, file existence, reference validation, and semantic rules that cannot be expressed in JSON Schema alone.

func ValidateStructural

func ValidateStructural(data any) ValidationResult

ValidateStructural performs Layer 1 validation using JSON Schema. It takes the generic (JSON-compatible) contract data, selects the schema that matches the declared pactoVersion, and validates against it. An unrecognized or missing pactoVersion is a hard error (fail closed) rather than silently validating against an arbitrary schema.

func ValidateStructuralRaw

func ValidateStructuralRaw(rawYAML []byte) ValidationResult

ValidateStructuralRaw performs Layer 1 (JSON Schema) validation on raw YAML bytes. It converts the YAML to a generic interface{} and validates against the schema.

func ValidateWithResolver

func ValidateWithResolver(ctx context.Context, c *contract.Contract, rawYAML []byte, bundleFS fs.FS, resolver BundleResolver) ValidationResult

ValidateWithResolver runs all three validation layers, using the provided BundleResolver for recursive ref-based policy resolution. If resolver is nil, any ref-based policies produce a hard POLICY_REF_UNRESOLVED error (fail closed).

func (*ValidationResult) AddError

func (r *ValidationResult) AddError(path, code, message string)

AddError appends a validation error.

func (*ValidationResult) AddWarning

func (r *ValidationResult) AddWarning(path, code, message string)

AddWarning appends a validation warning.

func (ValidationResult) Findings

func (r ValidationResult) Findings() []finding.Finding

Findings projects the layered ValidationResult into typed, severity-tagged findings. It is additive: ValidationResult is unchanged and remains the engine's internal accumulator. Errors become SeverityError, warnings SeverityWarning; category is looked up from the finding registry.

func (*ValidationResult) IsValid

func (r *ValidationResult) IsValid() bool

IsValid returns true if there are no errors.

func (*ValidationResult) Merge

func (r *ValidationResult) Merge(other ValidationResult)

Merge combines another result into this one.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL