kratos/oryx/jsonnetsecure/jsonnet.go

134 lines
2.9 KiB
Go

package jsonnetsecure
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"path"
"runtime"
"testing"
"github.com/google/go-jsonnet"
)
type (
VM interface {
EvaluateAnonymousSnippet(filename string, snippet string) (json string, formattedErr error)
ExtCode(key string, val string)
ExtVar(key string, val string)
TLACode(key string, val string)
TLAVar(key string, val string)
}
kv struct {
Key, Value string
}
processParameters struct {
Filename, Snippet string
TLACodes, TLAVars, ExtCodes, ExtVars []kv
}
vmOptions struct {
jsonnetBinaryPath string
args []string
ctx context.Context
pool *pool
}
Option func(o *vmOptions)
)
func (pp *processParameters) EncodeTo(w io.Writer) error {
return json.NewEncoder(w).Encode(pp)
}
func (pp *processParameters) Decode(d []byte) error {
return json.Unmarshal(d, pp)
}
func newVMOptions() *vmOptions {
jsonnetBinaryPath, _ := os.Executable()
return &vmOptions{
jsonnetBinaryPath: jsonnetBinaryPath,
ctx: context.Background(),
}
}
func WithContext(ctx context.Context) Option {
return func(o *vmOptions) {
o.ctx = ctx
}
}
func WithProcessPool(p Pool) Option {
return func(o *vmOptions) {
pool, _ := p.(*pool)
o.pool = pool
}
}
func WithJsonnetBinary(jsonnetBinaryPath string) Option {
return func(o *vmOptions) {
o.jsonnetBinaryPath = jsonnetBinaryPath
}
}
func WithProcessArgs(args ...string) Option {
return func(o *vmOptions) {
o.args = args
}
}
func MakeSecureVM(opts ...Option) VM {
options := newVMOptions()
for _, o := range opts {
o(options)
}
if options.pool != nil {
return NewProcessPoolVM(options)
} else {
vm := jsonnet.MakeVM()
vm.Importer(new(ErrorImporter))
return vm
}
}
// ErrorImporter errors when calling "import".
type ErrorImporter struct{}
// Import fetches data from a map entry.
// All paths are treated as absolute keys.
func (importer *ErrorImporter) Import(importedFrom, importedPath string) (contents jsonnet.Contents, foundAt string, err error) {
return jsonnet.Contents{}, "", fmt.Errorf("import not available %v", importedPath)
}
func JsonnetTestBinary(t testing.TB) string {
t.Helper()
// We can force the usage of a given jsonnet executable.
// Useful to test different versions, or run the tests under wine.
if s := os.Getenv("ORY_JSONNET_PATH"); s != "" {
return s
}
var stderr bytes.Buffer
// Using `t.TempDir()` results in permissions errors on Windows, sometimes.
outPath := path.Join(os.TempDir(), "jsonnet")
if runtime.GOOS == "windows" {
outPath = outPath + ".exe"
}
cmd := exec.Command("go", "build", "-o", outPath, "github.com/ory/x/jsonnetsecure/cmd")
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil || stderr.Len() != 0 {
t.Fatalf("building the Go binary returned error: %v\n%s", err, stderr.String())
}
return outPath
}