Documentation
¶
Overview ¶
Example ¶
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/google/go-jsonnet"
"github.com/thevilledev/safesonnet"
)
func main() {
// Create a temporary directory for our examples
rootDir, err := os.MkdirTemp("", "safesonnet-example")
if err != nil {
fmt.Printf("Failed to create temp dir: %v\n", err)
return
}
defer os.RemoveAll(rootDir)
// Create some jsonnet files
if err := os.MkdirAll(filepath.Join(rootDir, "lib"), 0755); err != nil {
fmt.Printf("Failed to create lib dir: %v\n", err)
return
}
mainJsonnet := `local utils = import 'utils.jsonnet';
{
result: utils.add(40, 2)
}`
utilsJsonnet := `{
add(a, b): a + b,
}`
if err := os.WriteFile(filepath.Join(rootDir, "main.jsonnet"), []byte(mainJsonnet), 0o600); err != nil {
fmt.Printf("Failed to write main.jsonnet: %v\n", err)
return
}
if err := os.WriteFile(filepath.Join(rootDir, "lib", "utils.jsonnet"), []byte(utilsJsonnet), 0o600); err != nil {
fmt.Printf("Failed to write utils.jsonnet: %v\n", err)
return
}
// Create a SafeImporter with the root directory and a library path
importer, err := safesonnet.NewSafeImporter(rootDir, []string{filepath.Join(rootDir, "lib")})
if err != nil {
fmt.Printf("Failed to create importer: %v\n", err)
return
}
defer importer.Close()
// First, show how to import a file
contents, foundAt, err := importer.Import("", "main.jsonnet")
if err != nil {
fmt.Printf("Failed to import: %v\n", err)
return
}
fmt.Printf("Found file at: %s\n", filepath.Base(foundAt))
fmt.Printf("Contents: %s\n", contents.String())
// Now, evaluate the jsonnet code
vm := jsonnet.MakeVM()
vm.Importer(importer)
// Evaluate the jsonnet code directly
result, err := vm.EvaluateAnonymousSnippet("example.jsonnet", mainJsonnet)
if err != nil {
fmt.Printf("Failed to evaluate: %v\n", err)
return
}
fmt.Printf("Evaluated result: %s\n", result)
}
Output: Found file at: main.jsonnet Contents: local utils = import 'utils.jsonnet'; { result: utils.add(40, 2) } Evaluated result: { "result": 42 }
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrJPathOutsideRoot is returned when a JPath is outside the root directory. ErrJPathOutsideRoot = errors.New("jpath is outside root directory") // ErrEmptyRootDir is returned when the root directory is empty. ErrEmptyRootDir = errors.New("root directory must not be empty") // ErrOpenRootDir is returned when the root directory cannot be opened. ErrOpenRootDir = errors.New("failed to open root directory") // ErrAbsPath is returned when the absolute path cannot be obtained. ErrAbsPath = errors.New("failed to get absolute path of root") // ErrAbsPathJPath is returned when the absolute path of a JPath cannot be obtained. ErrAbsPathJPath = errors.New("failed to get absolute path of jpath") // ErrRelPath is returned when the relative path cannot be obtained. ErrRelPath = errors.New("failed to get relative path of jpath") // ErrReadFile is returned when a file cannot be read. ErrReadFile = errors.New("failed to read file") // ErrOpenFile is returned when a file cannot be opened. ErrOpenFile = errors.New("failed to open file") // ErrRootAbsPath is returned when the root absolute path cannot be obtained. ErrRootAbsPath = errors.New("failed to get root absolute path") // ErrRelPathConversion is returned when a relative path cannot be obtained. ErrRelPathConversion = errors.New("failed to convert path to be relative to root") // ErrFileNotFound is returned when a file is not found in any library path. ErrFileNotFound = errors.New("file not found in any library path") // ErrCloseRootDir is returned when the root directory cannot be closed. ErrCloseRootDir = errors.New("failed to close root directory") // ErrCacheInternalType is returned when the cache contains an unexpected value type. ErrCacheInternalType = errors.New("internal cache error: unexpected type") // ErrForbiddenAbsolutePath is returned when an import path is absolute and outside the // root directory. ErrForbiddenAbsolutePath = errors.New("forbidden absolute import path") // ErrForbiddenRelativePathTraversal is returned when a relative import path attempts to // traverse outside the root directory. ErrForbiddenRelativePathTraversal = errors.New("forbidden relative import path traversal") // ErrInvalidNullByte is returned when a path contains a null byte, which is invalid. ErrInvalidNullByte = errors.New("path contains an invalid null byte") )
Functions ¶
This section is empty.
Types ¶
type Option ¶ added in v1.0.0
type Option func(*SafeImporter)
Option is a functional option for configuring SafeImporter.
func WithLogger ¶ added in v1.0.0
WithLogger allows providing a custom logger to SafeImporter. If nil is provided, the default discarding logger will be used.
type SafeImporter ¶
type SafeImporter struct {
// JPaths is a list of library search paths within the root directory.
JPaths []string
// contains filtered or unexported fields
}
SafeImporter implements jsonnet.Importer interface that restricts imports to a specific directory. It prevents path traversal attacks by ensuring all imports are within the specified root directory. The importer supports a list of library paths (JPaths) within the root directory, similar to the standard jsonnet importer. Caches file reads.
func NewSafeImporter ¶
func NewSafeImporter(rootDir string, jpaths []string, opts ...Option) (*SafeImporter, error)
NewSafeImporter creates a new SafeImporter that restricts imports to the given directory. It validates that all provided JPaths are within the root directory to maintain the security boundary. If no JPaths are provided, the root directory is used as the only search path.
rootDir must be a valid directory path or an error will be returned. jpaths should be a list of directories inside rootDir to search for imports. opts can be used to configure the SafeImporter, e.g., by providing a logger.
func (*SafeImporter) Close ¶
func (i *SafeImporter) Close() error
Close releases resources associated with the importer. This should be called when the importer is no longer needed to prevent resource leaks.
func (*SafeImporter) Import ¶
Import implements jsonnet.Importer interface. It searches for the importedPath in several locations in order:
- Relative to the importing file (if importedFrom is provided)
- In the root directory (if importedPath is not absolute)
- In each of the JPaths
The method respects the security boundary and will not allow imports from outside the root directory.