Skip to content

Commit

Permalink
Merge pull request #34 from krakend/embed_json_schema
Browse files Browse the repository at this point in the history
Embed json schema in the binary
  • Loading branch information
taik0 authored Jan 8, 2025
2 parents a7448e2 + 64c4a13 commit 6bf1b18
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 190 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Go

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.22

- name: Test
run: go test -v ./...
14 changes: 7 additions & 7 deletions audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ const (
func auditFunc(cmd *cobra.Command, _ []string) {
if cfgFile == "" {
cmd.Println(errorMsg("Please, provide the path to the configuration file with --config or see all the options with --help"))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}

cfg, err := parser.Parse(cfgFile)
if err != nil {
cmd.Println(errorMsg("ERROR parsing the configuration file:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}
cfg.Normalize()
Expand All @@ -46,7 +46,7 @@ func auditFunc(cmd *cobra.Command, _ []string) {
b, err := os.ReadFile(rulesToExcludePath)
if err != nil {
cmd.Println(errorMsg("ERROR accessing the ignore file:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}
for _, line := range strings.Split(strings.ReplaceAll(string(b), " ", ""), "\n") {
Expand All @@ -64,7 +64,7 @@ func auditFunc(cmd *cobra.Command, _ []string) {
)
if err != nil {
cmd.Println(errorMsg("ERROR auditing the configuration file:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}

Expand Down Expand Up @@ -92,17 +92,17 @@ func auditFunc(cmd *cobra.Command, _ []string) {
tmpl, err := template.New("audit").Funcs(funcMap).Parse(formatTmpl)
if err != nil {
cmd.Println(errorMsg("ERROR parsing the template:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}

if err := tmpl.Execute(os.Stderr, result); err != nil {
cmd.Println(errorMsg("ERROR rendering the results:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}

if len(result.Recommendations) > 0 {
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
}
}
100 changes: 77 additions & 23 deletions check.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"strings"
"time"

"github.com/krakendio/krakend-cobra/v2/dumper"
"github.com/santhosh-tekuri/jsonschema/v6"

"github.com/luraproject/lura/v2/config"
"github.com/luraproject/lura/v2/core"
Expand All @@ -18,8 +20,6 @@ import (
krakendgin "github.com/luraproject/lura/v2/router/gin"

"github.com/gin-gonic/gin"
"github.com/santhosh-tekuri/jsonschema/v5"
_ "github.com/santhosh-tekuri/jsonschema/v5/httploader"
"github.com/spf13/cobra"
)

Expand All @@ -36,10 +36,15 @@ type LastSourcer interface {
LastSource() ([]byte, error)
}

func checkFunc(cmd *cobra.Command, _ []string) {
func NewCheckCmd(rawSchema string) Command {
rawEmbedSchema = rawSchema
return CheckCommand
}

func checkFunc(cmd *cobra.Command, _ []string) { // skipcq: GO-R1005
if cfgFile == "" {
cmd.Println(errorMsg("Please, provide the path to the configuration file with --config or see all the options with --help"))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003 // skipcq: RVV-A0003
return
}

Expand All @@ -48,11 +53,13 @@ func checkFunc(cmd *cobra.Command, _ []string) {
v, err := parser.Parse(cfgFile)
if err != nil {
cmd.Println(errorMsg("ERROR parsing the configuration file:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003 // skipcq: RVV-A0003
return
}

if schemaValidation {
shouldLint := lintCurrentSchema || lintNoNetwork || (lintCustomSchemaPath != "")

if shouldLint {
var data []byte
var err error
if ls, ok := parser.(LastSourcer); ok {
Expand All @@ -63,52 +70,77 @@ func checkFunc(cmd *cobra.Command, _ []string) {

if err != nil {
cmd.Println(errorMsg("ERROR loading the configuration content:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}

var raw interface{}
if err := json.Unmarshal(data, &raw); err != nil {
cmd.Println(errorMsg("ERROR converting configuration content to JSON:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}

var url string
if strings.Contains(SchemaURL, "v%s") {
url = fmt.Sprintf(SchemaURL, getVersionMinor(core.KrakendVersion))
var sch *jsonschema.Schema
var compilationErr error
if lintNoNetwork {
rawSchema, parseError := jsonschema.UnmarshalJSON(strings.NewReader(rawEmbedSchema))
if parseError != nil {
cmd.Println(errorMsg("ERROR parsing the embed schema:") + fmt.Sprintf("\t%s\n", parseError.Error()))
os.Exit(1) // skipcq: RVV-A0003
return
}

compiler := jsonschema.NewCompiler()
compiler.AddResource("schema.json", rawSchema)

sch, compilationErr = compiler.Compile("schema.json")
} else {
// the global schema url var might have been set at build time
// to something different
url = SchemaURL
if lintCustomSchemaPath == "" {
lintCustomSchemaPath = fmt.Sprintf(SchemaURL, getVersionMinor(core.KrakendVersion))
}

httpLoader := SchemaHttpLoader(http.Client{
Timeout: 10 * time.Second,
})

loader := jsonschema.SchemeURLLoader{
"file": jsonschema.FileLoader{},
"http": &httpLoader,
"https": &httpLoader,
}
compiler := jsonschema.NewCompiler()
compiler.UseLoader(loader)

sch, compilationErr = compiler.Compile(lintCustomSchemaPath)
}
sch, err := jsonschema.Compile(url)
if err != nil {
cmd.Println(errorMsg("ERROR compiling the schema:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)

if compilationErr != nil {
cmd.Println(errorMsg("ERROR compiling the schema:") + fmt.Sprintf("\t%s\n", compilationErr.Error()))
os.Exit(1) // skipcq: RVV-A0003
return
}

if err = sch.Validate(raw); err != nil {
cmd.Println(errorMsg("ERROR linting the configuration file:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}
}

if debug > 0 {
cc := dumper.NewWithColors(cmd, checkDumpPrefix, debug, IsTTY)
if checkDebug > 0 {
cc := dumper.NewWithColors(cmd, checkDumpPrefix, checkDebug, IsTTY)
if err := cc.Dump(v); err != nil {
cmd.Println(errorMsg("ERROR checking the configuration file:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}
}

if checkGinRoutes {
if err := RunRouterFunc(v); err != nil {
cmd.Println(errorMsg("ERROR testing the configuration file:") + fmt.Sprintf("\t%s\n", err.Error()))
os.Exit(1)
os.Exit(1) // skipcq: RVV-A0003
return
}
}
Expand Down Expand Up @@ -146,3 +178,25 @@ func getVersionMinor(ver string) string {
}
return fmt.Sprintf("%s.%s", comps[0], comps[1])
}

type SchemaHttpLoader http.Client

func (l *SchemaHttpLoader) Load(url string) (interface{}, error) {
client := (*http.Client)(l)
resp, err := client.Get(url)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
_ = resp.Body.Close()
return nil, fmt.Errorf("%s returned status code %d", url, resp.StatusCode)
}

body, err := jsonschema.UnmarshalJSON(resp.Body)
if err != nil {
resp.Body.Close()
return nil, err
}

return body, resp.Body.Close()
}
42 changes: 37 additions & 5 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,41 @@ func CountFlagBuilder(dst *int, long, short, help string) FlagBuilder {
}
}

type ConstraintBuilder func(*cobra.Command)

func OneRequired(flags ...string) ConstraintBuilder {
return func(cmd *cobra.Command) {
cmd.MarkFlagsOneRequired(flags...)
}
}

func RequiredTogether(flags ...string) ConstraintBuilder {
return func(cmd *cobra.Command) {
cmd.MarkFlagsRequiredTogether(flags...)
}
}

func MutuallyExclusive(flags ...string) ConstraintBuilder {
return func(cmd *cobra.Command) {
cmd.MarkFlagsMutuallyExclusive(flags...)
}
}

type Command struct {
Cmd *cobra.Command
Flags []FlagBuilder
once *sync.Once
Cmd *cobra.Command
Flags []FlagBuilder
once *sync.Once
Constraints []ConstraintBuilder
}

func NewCommand(command *cobra.Command, flags ...FlagBuilder) Command {
return Command{Cmd: command, Flags: flags, once: new(sync.Once)}
}

func (c *Command) AddConstraint(r ConstraintBuilder) {
c.Constraints = append(c.Constraints, r)
}

func (c *Command) AddFlag(f FlagBuilder) {
c.Flags = append(c.Flags, f)
}
Expand Down Expand Up @@ -116,9 +141,16 @@ type Root struct {
func (r *Root) Build() {
r.once.Do(func() {
r.BuildFlags()
for i := range r.Constraints {
r.Constraints[i](r.Cmd)
}
for i := range r.SubCommands {
r.SubCommands[i].BuildFlags()
r.Cmd.AddCommand(r.SubCommands[i].Cmd)
s := r.SubCommands[i]
s.BuildFlags()
for j := range s.Constraints {
s.Constraints[j](s.Cmd)
}
r.Cmd.AddCommand(s.Cmd)
}
})
}
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
module github.com/krakendio/krakend-cobra/v2

go 1.17
go 1.22.0

require (
github.com/gin-gonic/gin v1.9.1
github.com/krakendio/krakend-audit v0.0.7
github.com/krakendio/krakend-viper/v2 v2.0.1
github.com/luraproject/lura/v2 v2.7.0
github.com/mattn/go-isatty v0.0.20
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0
github.com/spf13/cobra v1.1.3
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
golang.org/x/mod v0.12.0
)
Expand Down Expand Up @@ -75,7 +75,7 @@ require (
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/hashicorp/vault/api v1.10.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
Expand Down
Loading

0 comments on commit 6bf1b18

Please sign in to comment.