Skip to content

Commit

Permalink
feat: generate JSON schema
Browse files Browse the repository at this point in the history
  • Loading branch information
theseion committed Jun 9, 2024
1 parent 40c8c33 commit fd83027
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
env:
GOBIN: /home/runner/go/bin
with:
go-version: v1.21.x
go-version: v1.22.x
cache: true
- name: setup
run: |
Expand Down
47 changes: 47 additions & 0 deletions cmd/generate-doc-yaml-schema/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@
package main

import (
"fmt"
"io/fs"
"log"
"os"
"path"
"regexp"
"slices"

"github.com/coreruleset/ftw-tests-schema/v2/types"
"github.com/coreruleset/ftw-tests-schema/v2/types/overrides"
"github.com/invopop/jsonschema"
)

func main() {
Expand All @@ -28,4 +35,44 @@ func main() {
if err != nil {
panic(err)
}

exportJsonSchema()
}

// Writes a JSON schema based on the current version.
// Make sure the update https://github.com/SchemaStore/schemastore when
// you create a new version.
func exportJsonSchema() {
specsDir := "../../spec"
_json, err := jsonschema.Reflect(&types.FTWTest{}).MarshalJSON()
if err != nil {
log.Fatal(err)
}

entries, err := os.ReadDir(specsDir)
if err != nil {
log.Fatal(err)
}
slices.SortFunc(entries, func(a fs.DirEntry, b fs.DirEntry) int {
// sort v2.0 before v1
if a.Name() < b.Name() {
return 1
} else if a.Name() > b.Name() {
return -1
} else {
return 0
}
})
versionRegex := regexp.MustCompile(`v\d+(\.\d+)?`)
outputDir := "."
for _, entry := range entries {
if entry.IsDir() && versionRegex.MatchString(entry.Name()) {
outputDir = entry.Name()
break
}
}
err = os.WriteFile(path.Join(specsDir, outputDir, fmt.Sprintf("waf-tests-schema-%s.json", outputDir)), _json, fs.ModePerm)
if err != nil {
log.Fatal(err)
}
}
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
module github.com/coreruleset/ftw-tests-schema/v2

go 1.21
go 1.22

require github.com/magefile/mage v1.15.0

require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/invopop/jsonschema v0.12.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
)

require (
Expand Down
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -12,10 +16,15 @@ github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7a
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/goccy/go-yaml v1.9.2 h1:2Njwzw+0+pjU2gb805ZC1B/uBuAs2VcZ3K+ZgHwDs7w=
github.com/goccy/go-yaml v1.9.2/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
Expand All @@ -28,6 +37,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
Expand Down
1 change: 1 addition & 0 deletions spec/v2.0/waf-tests-schema-v2.0.0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://github.com/coreruleset/ftw-tests-schema/v2/types/ftw-test","$ref":"#/$defs/FTWTest","$defs":{"FTWTest":{"properties":{"meta":{"$ref":"#/$defs/FTWTestMeta"},"rule_id":{"type":"integer"},"tests":{"items":{"$ref":"#/$defs/Test"},"type":"array"}},"additionalProperties":false,"type":"object","required":["meta","rule_id","tests"]},"FTWTestMeta":{"properties":{"author":{"type":"string"},"enabled":{"type":"boolean"},"name":{"type":"string"},"description":{"type":"string"},"version":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"additionalProperties":false,"type":"object"},"Input":{"properties":{"dest_addr":{"type":"string"},"port":{"type":"integer"},"protocol":{"type":"string"},"uri":{"type":"string"},"follow_redirect":{"type":"boolean"},"version":{"type":"string"},"method":{"type":"string"},"headers":{"additionalProperties":{"type":"string"},"type":"object"},"data":{"type":"string"},"encoded_data":{"type":"string"},"save_cookie":{"type":"boolean"},"stop_magic":{"type":"boolean"},"autocomplete_headers":{"type":"boolean"},"encoded_request":{"type":"string"},"raw_request":{"type":"string"}},"additionalProperties":false,"type":"object"},"Log":{"properties":{"expect_ids":{"items":{"type":"integer"},"type":"array"},"no_expect_ids":{"items":{"type":"integer"},"type":"array"},"match_regex":{"type":"string"},"no_match_regex":{"type":"string"}},"additionalProperties":false,"type":"object"},"Output":{"properties":{"status":{"type":"integer"},"response_contains":{"type":"string"},"log_contains":{"type":"string"},"no_log_contains":{"type":"string"},"log":{"$ref":"#/$defs/Log"},"expect_error":{"type":"boolean"},"retry_once":{"type":"boolean"},"isolated":{"type":"boolean"}},"additionalProperties":false,"type":"object"},"Stage":{"properties":{"description":{"type":"string"},"input":{"$ref":"#/$defs/Input"},"output":{"$ref":"#/$defs/Output"}},"additionalProperties":false,"type":"object","required":["input","output"]},"Test":{"properties":{"test_title":{"type":"string"},"test_id":{"type":"integer"},"desc":{"type":"string"},"stages":{"items":{"$ref":"#/$defs/Stage"},"type":"array"},"tags":{"items":{"type":"string"},"type":"array"}},"additionalProperties":false,"type":"object","required":["test_id","stages"]}}}
24 changes: 12 additions & 12 deletions types/overrides/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ type FTWOverrides struct {
// The version field designates the version of the schema that validates this file
// examples:
// - value: "\"v0.1.0\""
Version string `yaml:"version"`
Version string `yaml:"version" json:"version"`

// description: |
// Meta describes the metadata information
// examples:
// - value: MetaExample
Meta FTWOverridesMeta `yaml:"meta"`
Meta FTWOverridesMeta `yaml:"meta" json:"meta"`

// description: |
// List of test override specifications
// examples:
// - value: TestOverridesExample
TestOverrides []TestOverride `yaml:"test_overrides"`
TestOverrides []TestOverride `yaml:"test_overrides" json:"test_overrides"`
}

// FTWOverridesMeta describes the metadata information of this yaml file
Expand All @@ -36,19 +36,19 @@ type FTWOverridesMeta struct {
// The name of the WAF engine the tests are expected to run against
// examples:
// - value: "\"coraza\""
Engine string `yaml:"engine"`
Engine string `yaml:"engine" json:"engine"`

// description: |
// The name of the platform (e.g., web server) the tests are expected to run against
// examples:
// - value: "\"nginx\""
Platform string `yaml:"platform"`
Platform string `yaml:"platform" json:"platform"`

// description: |
// Custom annotations; can be used to add additional meta information
// examples:
// - value: AnnotationsExample
Annotations map[string]string `yaml:"annotations"`
Annotations map[string]string `yaml:"annotations" json:"annotations"`
}

// TestOverride describes overrides for a single test
Expand All @@ -57,39 +57,39 @@ type TestOverride struct {
// ID of the rule this test targets.
// examples:
// - value: TestOverridesExample[0].RuleId
RuleId uint `yaml:"rule_id"`
RuleId uint `yaml:"rule_id" json:"rule_id"`

// description: |
// IDs of the tests for rule_id that overrides should be applied to.
// If this field is not set, the overrides will be applied to all tests of rule_id.
// examples:
// - value: TestOverridesExample[0].TestIds
TestIds []uint `yaml:"test_ids,flow,omitempty"`
TestIds []uint `yaml:"test_ids,flow,omitempty" json:"test_ids,flow,omitempty"`

// description: |
// IDs of the stages to which overrides should be applied.
// Stage IDs listed will be overridden for all test IDs listed in `TestIds`.
// If this field is not set, the overrides will be applied to all stages.
StageIds []uint `yaml:"stage_ids,omitempty"`
StageIds []uint `yaml:"stage_ids,omitempty" json:"stage_ids,omitempty"`

// description: |
// Describes why this override is necessary.
// examples:
// - value: ReasonExample
Reason string `yaml:"reason"`
Reason string `yaml:"reason" json:"reason"`

// description: |
// Whether a stage should be retried once in case of failure.
// This option is primarily a workaround for a race condition in phase 5,
// where the log entry of a rule may be flushed after the test end marker.
// examples:
// - value: true
RetryOnce *bool `yaml:"retry_once,omitempty"`
RetryOnce *bool `yaml:"retry_once,omitempty" json:"retry_once,omitempty"`

// description: |
// Specifies overrides on the test output.
// This definition *replaces* the output definition of the test.
// examples:
// - value: ExampleOutput
Output types.Output `yaml:"output"`
Output types.Output `yaml:"output" json:"output"`
}
Loading

0 comments on commit fd83027

Please sign in to comment.