updated vendor
This commit is contained in:
+191
@@ -0,0 +1,191 @@
|
||||
// Copyright 2026 The go-yaml Project Contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package limit provides a configurable safety limit plugin for go-yaml.
|
||||
//
|
||||
// The limit plugin controls the maximum nesting depth and alias expansion
|
||||
// ratio during YAML parsing.
|
||||
// By default, go-yaml enforces conservative limits to prevent DoS attacks.
|
||||
// This plugin lets you relax or tighten those limits for your use case.
|
||||
//
|
||||
// # Usage
|
||||
//
|
||||
// import (
|
||||
// "go.yaml.in/yaml/v4"
|
||||
// "go.yaml.in/yaml/v4/plugin/limit"
|
||||
// )
|
||||
//
|
||||
// // Default limits
|
||||
// loader := yaml.NewLoader(data, yaml.WithPlugin(limit.New()))
|
||||
//
|
||||
// // Disable alias checking (e.g. for 11,000 programmatic aliases)
|
||||
// loader := yaml.NewLoader(data, yaml.WithPlugin(limit.New(limit.AliasNone())))
|
||||
//
|
||||
// // Custom depth limit
|
||||
// loader := yaml.NewLoader(data, yaml.WithPlugin(limit.New(limit.DepthValue(50))))
|
||||
//
|
||||
// # Third-Party Plugins
|
||||
//
|
||||
// You can implement [yaml.LimitPlugin] directly instead of using this package:
|
||||
//
|
||||
// type StrictLimit struct{}
|
||||
// func (s *StrictLimit) CheckDepth(depth int, ctx *yaml.DepthContext) error { ... }
|
||||
// func (s *StrictLimit) CheckAlias(aliasCount, constructCount int) error { ... }
|
||||
// yaml.NewLoader(data, yaml.WithPlugin(&StrictLimit{}))
|
||||
package limit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.yaml.in/yaml/v4/internal/libyaml"
|
||||
)
|
||||
|
||||
// DepthContext is an alias for the type used in depth check callbacks.
|
||||
// See [yaml.DepthContext] for field documentation.
|
||||
type DepthContext = libyaml.DepthContext
|
||||
|
||||
// Plugin implements configurable safety limits for YAML parsing.
|
||||
type Plugin struct {
|
||||
depthLimit *int
|
||||
depthDisabled bool
|
||||
depthFn func(int, *DepthContext) error
|
||||
aliasLimit *int
|
||||
aliasDisabled bool
|
||||
aliasFn func(int, int) error
|
||||
}
|
||||
|
||||
// Option configures a [Plugin].
|
||||
type Option func(*Plugin)
|
||||
|
||||
// New creates a limit plugin with the given options.
|
||||
// With no options, it uses the same defaults as the bare go-yaml library.
|
||||
func New(opts ...Option) *Plugin {
|
||||
p := &Plugin{}
|
||||
for _, o := range opts {
|
||||
o(p)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// DepthValue sets a maximum nesting depth (both flow and block).
|
||||
func DepthValue(n int) Option {
|
||||
return func(p *Plugin) {
|
||||
p.depthLimit = &n
|
||||
p.depthDisabled = false
|
||||
p.depthFn = nil
|
||||
}
|
||||
}
|
||||
|
||||
// DepthNone disables depth checking entirely.
|
||||
func DepthNone() Option {
|
||||
return func(p *Plugin) {
|
||||
p.depthDisabled = true
|
||||
p.depthLimit = nil
|
||||
p.depthFn = nil
|
||||
}
|
||||
}
|
||||
|
||||
// DepthFunc sets a custom depth check function.
|
||||
func DepthFunc(fn func(depth int, ctx *DepthContext) error) Option {
|
||||
return func(p *Plugin) {
|
||||
p.depthFn = fn
|
||||
p.depthLimit = nil
|
||||
p.depthDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// AliasValue sets a simple alias expansion count threshold.
|
||||
func AliasValue(n int) Option {
|
||||
return func(p *Plugin) {
|
||||
p.aliasLimit = &n
|
||||
p.aliasDisabled = false
|
||||
p.aliasFn = nil
|
||||
}
|
||||
}
|
||||
|
||||
// AliasNone disables alias checking entirely.
|
||||
func AliasNone() Option {
|
||||
return func(p *Plugin) {
|
||||
p.aliasDisabled = true
|
||||
p.aliasLimit = nil
|
||||
p.aliasFn = nil
|
||||
}
|
||||
}
|
||||
|
||||
// AliasFunc sets a custom alias check function.
|
||||
func AliasFunc(fn func(aliasCount, constructCount int) error) Option {
|
||||
return func(p *Plugin) {
|
||||
p.aliasFn = fn
|
||||
p.aliasLimit = nil
|
||||
p.aliasDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// CheckDepth implements [yaml.LimitPlugin].
|
||||
func (p *Plugin) CheckDepth(depth int, ctx *DepthContext) error {
|
||||
if p.depthFn != nil {
|
||||
return p.depthFn(depth, ctx)
|
||||
}
|
||||
if p.depthDisabled {
|
||||
return nil
|
||||
}
|
||||
if p.depthLimit != nil {
|
||||
if depth > *p.depthLimit {
|
||||
return fmt.Errorf("exceeded max depth of %d", *p.depthLimit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return libyaml.DefaultDepthCheck(depth, ctx)
|
||||
}
|
||||
|
||||
// CheckAlias implements [yaml.LimitPlugin].
|
||||
func (p *Plugin) CheckAlias(aliasCount, constructCount int) error {
|
||||
if p.aliasFn != nil {
|
||||
return p.aliasFn(aliasCount, constructCount)
|
||||
}
|
||||
if p.aliasDisabled {
|
||||
return nil
|
||||
}
|
||||
if p.aliasLimit != nil {
|
||||
if aliasCount > *p.aliasLimit {
|
||||
return fmt.Errorf("exceeded max alias count of %d", *p.aliasLimit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return libyaml.DefaultAliasCheck(aliasCount, constructCount)
|
||||
}
|
||||
|
||||
// NewFromYAML creates a limit plugin from a YAML config map.
|
||||
// Keys: "depth" (int or null), "alias" (int or null).
|
||||
// Null values disable the corresponding check.
|
||||
// Omitted keys use defaults.
|
||||
func NewFromYAML(cfg map[string]any) (*Plugin, error) {
|
||||
var opts []Option
|
||||
for key, val := range cfg {
|
||||
switch key {
|
||||
case "depth":
|
||||
if val == nil {
|
||||
opts = append(opts, DepthNone())
|
||||
} else {
|
||||
n, ok := val.(int)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("limit: depth must be int or null, got %T", val)
|
||||
}
|
||||
opts = append(opts, DepthValue(n))
|
||||
}
|
||||
case "alias":
|
||||
if val == nil {
|
||||
opts = append(opts, AliasNone())
|
||||
} else {
|
||||
n, ok := val.(int)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("limit: alias must be int or null, got %T", val)
|
||||
}
|
||||
opts = append(opts, AliasValue(n))
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("limit: unknown key %q", key)
|
||||
}
|
||||
}
|
||||
return New(opts...), nil
|
||||
}
|
||||
Reference in New Issue
Block a user