Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
395392c
feat: add support for pkl files
olunusib Aug 21, 2024
b706fe9
feat: skip pkl files when binary isn't in PATH
olunusib Sep 2, 2024
80c436b
Merge branch 'main' into feat/pkl-validation
olunusib Sep 2, 2024
1fb119b
chore: use the new action tag in ref comment
olunusib Sep 2, 2024
2e01953
fix(test): resolve data race in pkl validation test
Oct 7, 2025
df3e3de
fix: move PKL to alphabetically correct spot in list of supported con…
Oct 7, 2025
e33c522
test: add fleshed out example for good.pkl
Oct 7, 2025
4f54b22
Merge branch 'main' into feat/pkl-validation
akhil-rasheed Oct 7, 2025
a3f1ca6
fix(test): repair test suite after pkl validator refactor
Oct 7, 2025
1b7e7cd
fix: correct build and pkl test fixture
Oct 7, 2025
e59a61c
fix: remove whitespace in workflow file
Oct 8, 2025
309847e
feat(pkl): Improve test coverage for pkl validator
Oct 8, 2025
8ffa41d
fix(test): Prevent race conditions in pkl validator tests
akhil-rasheed Oct 8, 2025
158c3c6
refactor: rename ErrSkipped to ErrPklSkipped
akhil-rasheed Oct 9, 2025
7fe75c1
refactor: improve pkl binary detection
akhil-rasheed Oct 9, 2025
5a7e6c0
revert: add back validator to .gitignore
akhil-rasheed Oct 9, 2025
b2e4e29
Merge branch 'main' into feat/pkl-validation
akhil-rasheed Oct 9, 2025
29461bc
fix: remove whitespace
akhil-rasheed Oct 9, 2025
8398985
fix: remove whitespace
akhil-rasheed Oct 9, 2025
306e190
refactor(suggestion): mark unused parameters
akhil-rasheed Oct 11, 2025
c40da87
feat: remove pkl binary dependency
akhil-rasheed Nov 3, 2025
31d7dec
Merge branch 'main' into feat/pkl-validation
akhil-rasheed Nov 3, 2025
87e10a7
fix: remove pkl installation in workflow
akhil-rasheed Nov 3, 2025
f6400f9
fix: remove unintented whitespace additions
akhil-rasheed Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
* INI
* JSON
* Properties
* PKL
* TOML
* XML
* YAML
Expand Down Expand Up @@ -192,8 +193,7 @@ validator --exclude-dirs=/path/to/search/tests /path/to/search
![Exclude Dirs Run](./img/exclude_dirs.gif)

#### Exclude file types

Exclude file types in the search path. Available file types are `csv`, `env`, `hcl`, `hocon`, `ini`, `json`, `plist`, `properties`, `toml`, `xml`, `yaml`, and `yml`
Exclude file types in the search path. Available file types are `csv`, `env`, `hcl`, `hocon`, `ini`, `json`, `plist`, `properties`, `pkl`, `toml`, `xml`, `yaml`, and `yml`

```shell
validator --exclude-file-types=json /path/to/search
Expand Down
2 changes: 1 addition & 1 deletion cmd/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Validator recursively scans a directory to search for configuration files and
validates them using the go package for each configuration type.

Currently Apple PList XML, CSV, HCL, HOCON, INI, JSON, Properties, TOML, XML, and YAML.
Currently Apple PList XML, CSV, HCL, HOCON, INI, JSON, PKL, Properties, TOML, XML, and YAML.
configuration file types are supported.

Usage: validator [OPTIONS] [<search_path>...]
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/Boeing/config-file-validator
go 1.25.0

require (
github.com/apple/pkl-go v0.8.0
github.com/bmatcuk/doublestar/v4 v4.9.1
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2
github.com/fatih/color v1.18.0
Expand All @@ -26,6 +27,8 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/zclconf/go-cty v1.13.0 // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/sys v0.25.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/apple/pkl-go v0.8.0 h1:GRcBvFWeXjT9rc7A5gHK89qrel2wGZ3/a7ge4rPlT5M=
github.com/apple/pkl-go v0.8.0/go.mod h1:5Hwil5tyZGrOekh7JXLZJvIAcGHb4gT19lnv4WEiKeI=
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down Expand Up @@ -38,6 +40,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0=
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
Expand Down
4 changes: 2 additions & 2 deletions index.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
* INI
* JSON
* Properties
* PKL
* TOML
* XML
* YAML
Expand Down Expand Up @@ -206,8 +207,7 @@ validator --exclude-dirs=/path/to/search/tests /path/to/search
![Exclude Dirs Run](./img/exclude_dirs.gif)

#### Exclude file types

Exclude file types in the search path. Available file types are `csv`, `env`, `hcl`, `hocon`, `ini`, `json`, `plist`, `properties`, `toml`, `xml`, `yaml`, and `yml`
Exclude file types in the search path. Available file types are `csv`, `env`, `hcl`, `hocon`, `ini`, `json`, `plist`, `properties`, `pkl`, `toml`, `xml`, `yaml`, and `yml`

```shell
validator --exclude-file-types=json /path/to/search
Expand Down
9 changes: 9 additions & 0 deletions pkg/filetype/file_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ var PropFileType = FileType{
validator.PropValidator{},
}

// Instance of the FileType object to
// represent a Pkl file
var PklFileType = FileType{
"pkl",
tools.ArrToMap("pkl"),
validator.PklValidator{},
}

// Instance of the FileType object to
// represent a HCL file
var HclFileType = FileType{
Expand Down Expand Up @@ -120,6 +128,7 @@ var FileTypes = []FileType{
TomlFileType,
IniFileType,
PropFileType,
PklFileType,
HclFileType,
PlistFileType,
CsvFileType,
Expand Down
39 changes: 39 additions & 0 deletions pkg/validator/pkl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package validator

import (
"context"
"fmt"

"github.com/apple/pkl-go/pkl"
)

// PklValidator is used to validate a byte slice that is intended to represent a
// PKL file.
type PklValidator struct {
evaluatorFactory func(context.Context, ...func(*pkl.EvaluatorOptions)) (pkl.Evaluator, error)
}

// Validate attempts to evaluate the provided byte slice as a PKL file.
func (v PklValidator) Validate(b []byte) (bool, error) {
ctx := context.Background()

// Convert the byte slice to a ModuleSource using TextSource
source := pkl.TextSource(string(b))

evaluatorFactory := v.evaluatorFactory
if evaluatorFactory == nil {
evaluatorFactory = pkl.NewEvaluator
}

evaluator, err := evaluatorFactory(ctx)
if err != nil {
return false, fmt.Errorf("failed to create evaluator: %w", err)
}

_, err = evaluator.EvaluateExpressionRaw(ctx, source, "")
if err != nil {
return false, fmt.Errorf("failed to evaluate module: %w", err)
}

return true, nil
}
26 changes: 26 additions & 0 deletions pkg/validator/validator_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package validator

import (
"context"
_ "embed"
"errors"
"strings"
"testing"

"github.com/apple/pkl-go/pkl"
)

var (
Expand Down Expand Up @@ -71,6 +76,8 @@ var testData = []struct {
{"invalidIni", []byte(`\nCatalog hidden\n`), false, IniValidator{}},
{"validProperties", []byte("key=value\nkey2=${key}"), true, PropValidator{}},
{"invalidProperties", []byte("key=${key}"), false, PropValidator{}},
{"validPkl", []byte(`name = "Swallow"`), true, PklValidator{}},
{"invalidPkl", []byte(`"name" = "Swallow"`), false, PklValidator{}},
{"validHcl", []byte(`key = "value"`), true, HclValidator{}},
{"invalidHcl", []byte(`"key" = "value"`), false, HclValidator{}},
{"multipleInvalidHcl", []byte(`"key1" = "value1"\n"key2"="value2"`), false, HclValidator{}},
Expand Down Expand Up @@ -111,6 +118,25 @@ func Test_ValidationInput(t *testing.T) {
}
}

func TestPklValidator_EvaluatorCreationError(t *testing.T) {
expectedErr := errors.New("evaluator creation failed")

validator := PklValidator{
evaluatorFactory: func(_ context.Context, _ ...func(options *pkl.EvaluatorOptions)) (pkl.Evaluator, error) {
return nil, expectedErr
},
}

_, err := validator.Validate([]byte(`name = "test"`))

if !strings.Contains(err.Error(), "failed to create evaluator") {
t.Errorf("expected error to contain 'failed to create evaluator', got %v", err)
}

if !errors.Is(err, expectedErr) {
t.Errorf("expected error to wrap %v, got %v", expectedErr, err)
}
}
func addFuzzCases(f *testing.F) {
f.Helper()
for _, tc := range fuzzbank {
Expand Down
50 changes: 50 additions & 0 deletions test/fixtures/good.pkl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@


name = "PhoenixWebApp"

package {
name = "phoenix"
version = "2.1.0"
authors = List("Phoenix Engineering <contact@phoenix.dev>")
}

database {
host = "db.phoenix.internal"
port = 5432
username = "phoenix_user"
poolSize = 20
sslMode = "require"
}

server {
host = "0.0.0.0"
port = 8080
logLevel = "info" // "debug", "info", "warn", "error"
corsOrigins = List("https://phoenix.example", "https://app.phoenix.example")
}

features {
newSignupFlow = true
apiRateLimiting = true
dashboardAnalytics = false
}

// --- Service Replica Configuration ---
local class Replica {
region: "us-east-1" | "us-west-2" | "eu-central-1"
instanceType: String
count: Int
}

replicas = List(
new Replica {
region = "us-east-1"
instanceType = "t3.medium"
count = 3
},
new Replica {
region = "us-west-2"
instanceType = "t3.medium"
count = 2
}
)
1 change: 1 addition & 0 deletions test/fixtures/subdir2/bad.pkl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"invalid"
Loading