meshery / meshery/meshkit

Refactor meshkit/schema to wrap meshery/schemas/validation leaf package

Open
#976 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
223
Forks
225
Avg merge
7d 1h
Merged PRs (30d)
1

Description

## Context

The `meshery/schemas` repository now has a `validation/` leaf package (`github.com/meshery/schemas/validation`) that owns schema-backed validation using [kin-openapi](https://github.com/getkin/kin-openapi). This is the Phase 0 deliverable from the [validation package design document](https://github.com/meshery/schemas/blob/master/specs/validation-package.md) and [meshery/schemas#624](https://github.com/meshery/schemas/issues/624).

The package is a **dependency-leaf**: it imports `kin-openapi`, `yaml.v3`, and stdlib only. It does NOT import MeshKit or `meshery/schemas/models/...`. This makes it safe for `meshkit/schema` to import without creating cycles.

Currently, `meshkit/schema` owns the full validation implementation — schema loading, compilation, caching, registration, and the validation engine. The design calls for `meshkit/schema` to become a **thin integration layer** that wraps the lower-level engine from `meshery/schemas/validation`, rather than maintaining a separate implementation.

## Current State

### `meshery/schemas/validation` (new — leaf package)

**Package:** `github.com/meshery/schemas/validation`

Currently provides **build-time schema auditing** (41 rules via `go run ./cmd/validate-schemas`). The runtime document validation API is the next addition:

```go
// Planned additions to the leaf package:
func ValidateDocument(data []byte) error
func ValidateWithRef(ref Ref, data []byte) error
func ValidateAny(ref Ref, value any) error
func DecodeAndValidate[T any](data []byte) (T, error)
func ValidationDetailsFromError(err error) (ValidationDetails, bool)
```

These will use `kin-openapi`'s `schema.VisitJSON()` for constraint enforcement, with embedded schema discovery from the `meshery/schemas` module's filesystem.

### `meshkit/schema` (current — full implementation)

**Package:** `github.com/meshery/meshkit/schema`

Full API surface that must be preserved or migrated:

| Category | Functions |
|---|---|
| **Factory** | `Default()`, `New()`, `MustNew()` |
| **Package-level** | `Validate()`, `ValidateWithRef()`, `ValidateAs()`, `DetectRef()` |
| **Generic decode** | `DecodeAndValidate[T]()`, `DecodeAndValidateWithRef[T]()`, `DecodeAndValidateWithValidator[T]()` |
| **Instance methods** | `(*Validator).Validate()`, `.ValidateBytes()`, `.ValidateAny()`, `.Register()` |
| **Error handling** | `ValidationDetailsFromError()`, `ErrValidateDocument()`, etc. |
| **Types** | `Ref`, `Registration`, `Violation`, `ValidationDetails`, `Validator`, `DocumentType` |

## Displacement Plan

### Phase 1: Add runtime validation API to `meshery/schemas/validation`

**Where:** `meshery/schemas` repo

Add these functions to the leaf package, matching the core validation semantics that `meshkit/schema` currently provides:

```go
package validation

// Ref identifies which schema to validate against.
type Ref struct {
SchemaVersion string
Type DocumentType
}

// DocumentType identifies a Meshery document family.
type DocumentType string

const (
TypeComponent DocumentType = "component"
TypeConnection DocumentType = "connection"
TypeDesign DocumentType = "design"
TypeEnvironment DocumentType = "environment"
TypeModel DocumentType = "model"
TypeRelationship DocumentType = "relationship"
TypeWorkspace DocumentType = "workspace"
)

// Violation is a field-level validation failure.
type Violation struct {
InstancePath string
SchemaPath string
Keyword string
Message string
}

// ValidationDetails contains all violations for a rejected document.
type ValidationDetails struct {
Ref Ref
SchemaLocation string
Violations []Violation
}

// ValidateDocument validates bytes against auto-detected schema.
func ValidateDocument(data []byte) error

// ValidateWithRef validates bytes against a specific schema.
func ValidateWithRef(ref Ref, data []byte) error

// ValidateAny validates a Go value against a specific schema.
func ValidateAny(ref Ref, value any) error

// ValidationDetailsFromError extracts structured details from a validation error.
func ValidationDetailsFromError(err error) (ValidationDetails, bool)
```

Key implementation details:
- Schema discovery uses the embedded `meshery/schemas` filesystem (same approach as current `meshkit/schema`)
- Schema compilation uses `kin-openapi` with `singleflight` caching (same pattern)
- `schemaVersion` field detection for auto-ref (same algorithm)
- Returns plain `error` with `ValidationDetails` extractable via `errors.As`

### Phase 2: Refactor `meshkit/schema` to delegate to the leaf package

**Where:** `meshery/meshkit` repo (this issue)

Refactor `meshkit/schema` to:
1. **Import** `github.com/meshery/schemas/validation` as the engine
2. **Delegate** all validation calls to the leaf package
3. **Wrap** leaf package errors into MeshKit `ErrorV2` types
4. **Preserve** the existing `meshkit/schema` public API for backward compatibility

```go
package schema

import (
schemavalidation "github.com/meshery/schemas/validation"
"github.com/meshery/meshkit/errors"
)

// Validate delegates to the leaf package and wraps errors.
func (v *Validator) Validate(data []byte) error {
err := v.leaf.ValidateDocument(data)
if err != nil {
if details, ok := schemavalidation.ValidationDetailsFromError(err); ok {
return ErrValidateDocument(convertDetails(details))
}
return ErrDecodeDocument(err)
}
return nil
}

// ValidateAny delegates to the leaf package.
func (v *Validator) ValidateAny(ref Ref, value any) error {
leafRef := schemavalidation.Ref{
SchemaVersion: ref.SchemaVersion,
Type: schemavalidation.DocumentType(ref.Type),
}
return v.leaf.ValidateAny(leafRef, value)
}
```

What moves **out** of `meshkit/schema`:
- Schema loading, compilation, and caching logic
- `kin-openapi` import and schema visitor calls
- Embedded schema filesystem access
- `singleflight` compilation guard
- Built-in registration discovery

What **stays** in `meshkit/schema`:
- MeshKit-specific error wrapping (`ErrorV2`, error codes `meshkit-11320` through `meshkit-11327`)
- The public API surface (all exported functions and types)
- MeshKit-specific integration patterns (e.g., `DecodeAndValidate[T]` using MeshKit encoding)

### Phase 3: Bump `meshery/schemas` dependency in MeshKit

- Update `go.mod` in meshery/meshkit to the schemas version containing the runtime validation API
- Run `go mod tidy`
- Verify all existing `meshkit/schema` tests pass with the delegation layer
- Verify no API surface changes visible to consumers

## Acceptance Criteria

- [ ] `meshery/schemas/validation` exposes `ValidateDocument`, `ValidateWithRef`, `ValidateAny`, and `ValidationDetailsFromError`
- [ ] `meshkit/schema` imports `meshery/schemas/validation` and delegates all validation calls
- [ ] `meshkit/schema` public API surface is unchanged — no breaking changes for consumers
- [ ] All existing `meshkit/schema` tests pass
- [ ] `kin-openapi` is no longer a direct import in `meshkit/schema` (it comes transitively through the leaf package)
- [ ] Schema compilation caching and singleflight live in the leaf package, not MeshKit
- [ ] MeshKit error wrapping (`ErrorV2` with meshkit error codes) remains in `meshkit/schema`
- [ ] The dependency graph is acyclic: `schemas/validation` → kin-openapi; `meshkit/schema` → `schemas/validation`

## References

- Design document: [meshery/schemas specs/validation-package.md](https://github.com/meshery/schemas/blob/master/specs/validation-package.md)
- Parent issue: [meshery/schemas#624](https://github.com/meshery/schemas/issues/624)
- Original MeshKit PR: meshery/meshkit#932

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing meshkit/schema implementation and its tests, then inspect go.mod and the planned github.com/meshery/schemas/validation API. Trace the current validation, caching, registration, and error-wrapping entry points before assessing the delegation boundaries. Done means the public API and existing meshkit/schema tests remain unchanged while validation ownership moves to the leaf package.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.