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 ¶
- Constants
- func ResolvePoliciesFromBundle(c *contract.Contract, bundleFS fs.FS) ([]ResolvedPolicy, ValidationResult)
- func ResolvePoliciesWithResolver(ctx context.Context, c *contract.Contract, bundleFS fs.FS, ...) ([]ResolvedPolicy, ValidationResult)
- func SchemaBytes() []byte
- type BundleResolver
- type Coverage
- type ResolvedPolicy
- type ValidationResult
- func EnforcePolicies(rawYAML []byte, policies []ResolvedPolicy) ValidationResult
- func Validate(c *contract.Contract, rawYAML []byte, bundleFS fs.FS) ValidationResult
- func ValidateCrossField(c *contract.Contract, bundleFS fs.FS) ValidationResult
- func ValidateStructural(data any) ValidationResult
- func ValidateStructuralRaw(rawYAML []byte) ValidationResult
- func ValidateWithResolver(ctx context.Context, c *contract.Contract, rawYAML []byte, bundleFS fs.FS, ...) ValidationResult
Examples ¶
Constants ¶
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 ¶
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 ¶
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.