mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
3f7a5496dc
- FFI: add RVM/Program APIs, execution state accessors, HostAwait handling, and buffer/result helpers in rvm.rs, common.rs, engine.rs. - Compiler: emit HostAwait for __builtin_host_await in function_calls.rs. - RVM tests: add HostAwait regression cases and extend harness for suspend/resume responses in host_await.yaml and mod.rs. - C/C++: add RVM tests/examples and wrapper updates in rvm_tests.c, rvm_tests.cpp, regorus.hpp, plus CMake wiring. - C#: add Program/Rvm bindings, SafeHandle/PInvoke, tests, and example usage in Regorus, RvmProgramTests.cs, Program.cs, and README updates. - Go: add Program/Rvm bindings, tests, and examples in rvm.go, rvm_test.go, main.go. - Java: add Program/Rvm bindings, JNI glue, and examples in lib.rs, regorus, Test.java. - Python: add Program/Rvm bindings and examples in lib.rs, test.py. - WASM: add Program/Rvm bindings and examples in lib.rs, test.js. - Tooling: wire binding tests in xtask and ignore generated Java artifacts in .gitignore. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
284 lines
7.4 KiB
Go
284 lines
7.4 KiB
Go
package regorus
|
|
|
|
// #cgo LDFLAGS: -L ../../../ffi/target/release -L ../../../ffi/target/debug -lregorus_ffi
|
|
// #include "../../../ffi/regorus.h"
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
type PolicyModule struct {
|
|
Id string
|
|
Content string
|
|
}
|
|
|
|
type Program struct {
|
|
p *C.RegorusProgram
|
|
}
|
|
|
|
type Rvm struct {
|
|
vm *C.RegorusRvm
|
|
}
|
|
|
|
type Buffer struct {
|
|
b *C.RegorusBuffer
|
|
}
|
|
|
|
func (b *Buffer) Close() {
|
|
if b != nil && b.b != nil {
|
|
C.regorus_buffer_drop(b.b)
|
|
b.b = nil
|
|
}
|
|
}
|
|
|
|
func (b *Buffer) Bytes() []byte {
|
|
if b == nil || b.b == nil || b.b.data == nil || b.b.len == 0 {
|
|
return nil
|
|
}
|
|
return C.GoBytes(unsafe.Pointer(b.b.data), C.int(b.b.len))
|
|
}
|
|
|
|
func (p *Program) Close() {
|
|
if p != nil && p.p != nil {
|
|
C.regorus_program_drop(p.p)
|
|
p.p = nil
|
|
}
|
|
}
|
|
|
|
func (p *Program) SerializeBinary() ([]byte, error) {
|
|
result := C.regorus_program_serialize_binary(p.p)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return nil, fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
buffer := &Buffer{b: (*C.RegorusBuffer)(result.pointer_value)}
|
|
defer buffer.Close()
|
|
return buffer.Bytes(), nil
|
|
}
|
|
|
|
func (p *Program) GenerateListing() (string, error) {
|
|
result := C.regorus_program_generate_listing(p.p)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return C.GoString(result.output), nil
|
|
}
|
|
|
|
func (p *Program) GenerateTabularListing() (string, error) {
|
|
result := C.regorus_program_generate_tabular_listing(p.p)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return C.GoString(result.output), nil
|
|
}
|
|
|
|
func DeserializeProgram(data []byte) (*Program, bool, error) {
|
|
if len(data) == 0 {
|
|
return nil, false, fmt.Errorf("empty program data")
|
|
}
|
|
var isPartial C.bool
|
|
result := C.regorus_program_deserialize_binary((*C.uchar)(unsafe.Pointer(&data[0])), C.ulong(len(data)), (*C.bool)(unsafe.Pointer(&isPartial)))
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return nil, false, fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return &Program{p: (*C.RegorusProgram)(result.pointer_value)}, bool(isPartial), nil
|
|
}
|
|
|
|
func CompileProgramFromModules(data string, modules []PolicyModule, entryPoints []string) (*Program, error) {
|
|
dataC := C.CString(data)
|
|
defer C.free(unsafe.Pointer(dataC))
|
|
|
|
cModules := make([]C.RegorusPolicyModule, len(modules))
|
|
moduleIdPtrs := make([]*C.char, len(modules))
|
|
moduleContentPtrs := make([]*C.char, len(modules))
|
|
for i, module := range modules {
|
|
idC := C.CString(module.Id)
|
|
contentC := C.CString(module.Content)
|
|
moduleIdPtrs[i] = idC
|
|
moduleContentPtrs[i] = contentC
|
|
cModules[i].id = idC
|
|
cModules[i].content = contentC
|
|
}
|
|
defer func() {
|
|
for i := range moduleIdPtrs {
|
|
if moduleIdPtrs[i] != nil {
|
|
C.free(unsafe.Pointer(moduleIdPtrs[i]))
|
|
}
|
|
if moduleContentPtrs[i] != nil {
|
|
C.free(unsafe.Pointer(moduleContentPtrs[i]))
|
|
}
|
|
}
|
|
}()
|
|
|
|
entryPtrs := make([]*C.char, len(entryPoints))
|
|
for i, entry := range entryPoints {
|
|
entryPtrs[i] = C.CString(entry)
|
|
}
|
|
defer func() {
|
|
for _, ptr := range entryPtrs {
|
|
C.free(unsafe.Pointer(ptr))
|
|
}
|
|
}()
|
|
|
|
var modulesPtr *C.RegorusPolicyModule
|
|
if len(cModules) > 0 {
|
|
modulesPtr = (*C.RegorusPolicyModule)(unsafe.Pointer(&cModules[0]))
|
|
}
|
|
var entryPtr **C.char
|
|
if len(entryPtrs) > 0 {
|
|
entryPtr = (**C.char)(unsafe.Pointer(&entryPtrs[0]))
|
|
}
|
|
|
|
result := C.regorus_program_compile_from_modules(
|
|
dataC,
|
|
modulesPtr,
|
|
C.ulong(len(cModules)),
|
|
entryPtr,
|
|
C.ulong(len(entryPtrs)),
|
|
)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return nil, fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return &Program{p: (*C.RegorusProgram)(result.pointer_value)}, nil
|
|
}
|
|
|
|
func CompileProgramFromEngine(engine *Engine, entryPoints []string) (*Program, error) {
|
|
entryPtrs := make([]*C.char, len(entryPoints))
|
|
for i, entry := range entryPoints {
|
|
entryPtrs[i] = C.CString(entry)
|
|
}
|
|
defer func() {
|
|
for _, ptr := range entryPtrs {
|
|
C.free(unsafe.Pointer(ptr))
|
|
}
|
|
}()
|
|
|
|
var entryPtr **C.char
|
|
if len(entryPtrs) > 0 {
|
|
entryPtr = (**C.char)(unsafe.Pointer(&entryPtrs[0]))
|
|
}
|
|
|
|
result := C.regorus_engine_compile_program_with_entrypoints(
|
|
engine.e,
|
|
entryPtr,
|
|
C.ulong(len(entryPtrs)),
|
|
)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return nil, fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return &Program{p: (*C.RegorusProgram)(result.pointer_value)}, nil
|
|
}
|
|
|
|
func NewRvm() (*Rvm, error) {
|
|
vm := C.regorus_rvm_new()
|
|
if vm == nil {
|
|
return nil, fmt.Errorf("failed to create RVM")
|
|
}
|
|
return &Rvm{vm: vm}, nil
|
|
}
|
|
|
|
func (r *Rvm) Close() {
|
|
if r != nil && r.vm != nil {
|
|
C.regorus_rvm_drop(r.vm)
|
|
r.vm = nil
|
|
}
|
|
}
|
|
|
|
func (r *Rvm) LoadProgram(program *Program) error {
|
|
result := C.regorus_rvm_load_program(r.vm, program.p)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Rvm) SetDataJson(data string) error {
|
|
dataC := C.CString(data)
|
|
defer C.free(unsafe.Pointer(dataC))
|
|
result := C.regorus_rvm_set_data(r.vm, dataC)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Rvm) SetInputJson(input string) error {
|
|
inputC := C.CString(input)
|
|
defer C.free(unsafe.Pointer(inputC))
|
|
result := C.regorus_rvm_set_input(r.vm, inputC)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Rvm) SetExecutionMode(mode byte) error {
|
|
result := C.regorus_rvm_set_execution_mode(r.vm, C.uchar(mode))
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Rvm) Execute() (string, error) {
|
|
result := C.regorus_rvm_execute(r.vm)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return C.GoString(result.output), nil
|
|
}
|
|
|
|
func (r *Rvm) ExecuteEntryPoint(name string) (string, error) {
|
|
nameC := C.CString(name)
|
|
defer C.free(unsafe.Pointer(nameC))
|
|
result := C.regorus_rvm_execute_entry_point_by_name(r.vm, nameC)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return C.GoString(result.output), nil
|
|
}
|
|
|
|
func (r *Rvm) ExecuteEntryPointIndex(index uint64) (string, error) {
|
|
result := C.regorus_rvm_execute_entry_point_by_index(r.vm, C.ulong(index))
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return C.GoString(result.output), nil
|
|
}
|
|
|
|
func (r *Rvm) Resume(resumeValue string, hasValue bool) (string, error) {
|
|
var valueC *C.char
|
|
if hasValue {
|
|
valueC = C.CString(resumeValue)
|
|
defer C.free(unsafe.Pointer(valueC))
|
|
}
|
|
result := C.regorus_rvm_resume(r.vm, valueC, C.bool(hasValue))
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return C.GoString(result.output), nil
|
|
}
|
|
|
|
func (r *Rvm) GetExecutionState() (string, error) {
|
|
result := C.regorus_rvm_get_execution_state(r.vm)
|
|
defer C.regorus_result_drop(result)
|
|
if result.status != C.Ok {
|
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
|
}
|
|
return C.GoString(result.output), nil
|
|
}
|