feat(coredeno): gRPC server with permission-gated I/O fortress

Generated Go code from proto. Server implements CoreService with
FileRead/FileWrite/FileList/FileDelete/StoreGet/StoreSet — every
request checked against the calling module's manifest permissions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude 2026-02-17 21:09:40 +00:00
parent 0681fba48e
commit e8695b72a6
No known key found for this signature in database
GPG key ID: AF404715446AEB41
6 changed files with 2238 additions and 2 deletions

4
go.mod
View file

@ -112,8 +112,8 @@ require (
golang.org/x/tools v0.42.0 // indirect golang.org/x/tools v0.42.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
gonum.org/v1/gonum v0.17.0 // indirect gonum.org/v1/gonum v0.17.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.78.0 // indirect google.golang.org/grpc v1.79.1 // indirect
google.golang.org/protobuf v1.36.11 // indirect google.golang.org/protobuf v1.36.11 // indirect
modernc.org/libc v1.67.7 // indirect modernc.org/libc v1.67.7 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect

9
go.sum
View file

@ -247,14 +247,19 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -299,8 +304,12 @@ gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,579 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.1
// - protoc v3.21.12
// source: pkg/coredeno/proto/coredeno.proto
package proto
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
CoreService_FileRead_FullMethodName = "/coredeno.CoreService/FileRead"
CoreService_FileWrite_FullMethodName = "/coredeno.CoreService/FileWrite"
CoreService_FileList_FullMethodName = "/coredeno.CoreService/FileList"
CoreService_FileDelete_FullMethodName = "/coredeno.CoreService/FileDelete"
CoreService_StoreGet_FullMethodName = "/coredeno.CoreService/StoreGet"
CoreService_StoreSet_FullMethodName = "/coredeno.CoreService/StoreSet"
CoreService_ProcessStart_FullMethodName = "/coredeno.CoreService/ProcessStart"
CoreService_ProcessStop_FullMethodName = "/coredeno.CoreService/ProcessStop"
)
// CoreServiceClient is the client API for CoreService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// CoreService is implemented by CoreGO — Deno calls this for I/O.
type CoreServiceClient interface {
// Filesystem (gated by manifest permissions)
FileRead(ctx context.Context, in *FileReadRequest, opts ...grpc.CallOption) (*FileReadResponse, error)
FileWrite(ctx context.Context, in *FileWriteRequest, opts ...grpc.CallOption) (*FileWriteResponse, error)
FileList(ctx context.Context, in *FileListRequest, opts ...grpc.CallOption) (*FileListResponse, error)
FileDelete(ctx context.Context, in *FileDeleteRequest, opts ...grpc.CallOption) (*FileDeleteResponse, error)
// Object store
StoreGet(ctx context.Context, in *StoreGetRequest, opts ...grpc.CallOption) (*StoreGetResponse, error)
StoreSet(ctx context.Context, in *StoreSetRequest, opts ...grpc.CallOption) (*StoreSetResponse, error)
// Process management
ProcessStart(ctx context.Context, in *ProcessStartRequest, opts ...grpc.CallOption) (*ProcessStartResponse, error)
ProcessStop(ctx context.Context, in *ProcessStopRequest, opts ...grpc.CallOption) (*ProcessStopResponse, error)
}
type coreServiceClient struct {
cc grpc.ClientConnInterface
}
func NewCoreServiceClient(cc grpc.ClientConnInterface) CoreServiceClient {
return &coreServiceClient{cc}
}
func (c *coreServiceClient) FileRead(ctx context.Context, in *FileReadRequest, opts ...grpc.CallOption) (*FileReadResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(FileReadResponse)
err := c.cc.Invoke(ctx, CoreService_FileRead_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *coreServiceClient) FileWrite(ctx context.Context, in *FileWriteRequest, opts ...grpc.CallOption) (*FileWriteResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(FileWriteResponse)
err := c.cc.Invoke(ctx, CoreService_FileWrite_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *coreServiceClient) FileList(ctx context.Context, in *FileListRequest, opts ...grpc.CallOption) (*FileListResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(FileListResponse)
err := c.cc.Invoke(ctx, CoreService_FileList_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *coreServiceClient) FileDelete(ctx context.Context, in *FileDeleteRequest, opts ...grpc.CallOption) (*FileDeleteResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(FileDeleteResponse)
err := c.cc.Invoke(ctx, CoreService_FileDelete_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *coreServiceClient) StoreGet(ctx context.Context, in *StoreGetRequest, opts ...grpc.CallOption) (*StoreGetResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(StoreGetResponse)
err := c.cc.Invoke(ctx, CoreService_StoreGet_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *coreServiceClient) StoreSet(ctx context.Context, in *StoreSetRequest, opts ...grpc.CallOption) (*StoreSetResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(StoreSetResponse)
err := c.cc.Invoke(ctx, CoreService_StoreSet_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *coreServiceClient) ProcessStart(ctx context.Context, in *ProcessStartRequest, opts ...grpc.CallOption) (*ProcessStartResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ProcessStartResponse)
err := c.cc.Invoke(ctx, CoreService_ProcessStart_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *coreServiceClient) ProcessStop(ctx context.Context, in *ProcessStopRequest, opts ...grpc.CallOption) (*ProcessStopResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ProcessStopResponse)
err := c.cc.Invoke(ctx, CoreService_ProcessStop_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// CoreServiceServer is the server API for CoreService service.
// All implementations must embed UnimplementedCoreServiceServer
// for forward compatibility.
//
// CoreService is implemented by CoreGO — Deno calls this for I/O.
type CoreServiceServer interface {
// Filesystem (gated by manifest permissions)
FileRead(context.Context, *FileReadRequest) (*FileReadResponse, error)
FileWrite(context.Context, *FileWriteRequest) (*FileWriteResponse, error)
FileList(context.Context, *FileListRequest) (*FileListResponse, error)
FileDelete(context.Context, *FileDeleteRequest) (*FileDeleteResponse, error)
// Object store
StoreGet(context.Context, *StoreGetRequest) (*StoreGetResponse, error)
StoreSet(context.Context, *StoreSetRequest) (*StoreSetResponse, error)
// Process management
ProcessStart(context.Context, *ProcessStartRequest) (*ProcessStartResponse, error)
ProcessStop(context.Context, *ProcessStopRequest) (*ProcessStopResponse, error)
mustEmbedUnimplementedCoreServiceServer()
}
// UnimplementedCoreServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedCoreServiceServer struct{}
func (UnimplementedCoreServiceServer) FileRead(context.Context, *FileReadRequest) (*FileReadResponse, error) {
return nil, status.Error(codes.Unimplemented, "method FileRead not implemented")
}
func (UnimplementedCoreServiceServer) FileWrite(context.Context, *FileWriteRequest) (*FileWriteResponse, error) {
return nil, status.Error(codes.Unimplemented, "method FileWrite not implemented")
}
func (UnimplementedCoreServiceServer) FileList(context.Context, *FileListRequest) (*FileListResponse, error) {
return nil, status.Error(codes.Unimplemented, "method FileList not implemented")
}
func (UnimplementedCoreServiceServer) FileDelete(context.Context, *FileDeleteRequest) (*FileDeleteResponse, error) {
return nil, status.Error(codes.Unimplemented, "method FileDelete not implemented")
}
func (UnimplementedCoreServiceServer) StoreGet(context.Context, *StoreGetRequest) (*StoreGetResponse, error) {
return nil, status.Error(codes.Unimplemented, "method StoreGet not implemented")
}
func (UnimplementedCoreServiceServer) StoreSet(context.Context, *StoreSetRequest) (*StoreSetResponse, error) {
return nil, status.Error(codes.Unimplemented, "method StoreSet not implemented")
}
func (UnimplementedCoreServiceServer) ProcessStart(context.Context, *ProcessStartRequest) (*ProcessStartResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessStart not implemented")
}
func (UnimplementedCoreServiceServer) ProcessStop(context.Context, *ProcessStopRequest) (*ProcessStopResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ProcessStop not implemented")
}
func (UnimplementedCoreServiceServer) mustEmbedUnimplementedCoreServiceServer() {}
func (UnimplementedCoreServiceServer) testEmbeddedByValue() {}
// UnsafeCoreServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to CoreServiceServer will
// result in compilation errors.
type UnsafeCoreServiceServer interface {
mustEmbedUnimplementedCoreServiceServer()
}
func RegisterCoreServiceServer(s grpc.ServiceRegistrar, srv CoreServiceServer) {
// If the following call panics, it indicates UnimplementedCoreServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&CoreService_ServiceDesc, srv)
}
func _CoreService_FileRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(FileReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).FileRead(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_FileRead_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).FileRead(ctx, req.(*FileReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _CoreService_FileWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(FileWriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).FileWrite(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_FileWrite_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).FileWrite(ctx, req.(*FileWriteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _CoreService_FileList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(FileListRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).FileList(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_FileList_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).FileList(ctx, req.(*FileListRequest))
}
return interceptor(ctx, in, info, handler)
}
func _CoreService_FileDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(FileDeleteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).FileDelete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_FileDelete_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).FileDelete(ctx, req.(*FileDeleteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _CoreService_StoreGet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StoreGetRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).StoreGet(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_StoreGet_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).StoreGet(ctx, req.(*StoreGetRequest))
}
return interceptor(ctx, in, info, handler)
}
func _CoreService_StoreSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StoreSetRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).StoreSet(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_StoreSet_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).StoreSet(ctx, req.(*StoreSetRequest))
}
return interceptor(ctx, in, info, handler)
}
func _CoreService_ProcessStart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProcessStartRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).ProcessStart(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_ProcessStart_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).ProcessStart(ctx, req.(*ProcessStartRequest))
}
return interceptor(ctx, in, info, handler)
}
func _CoreService_ProcessStop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProcessStopRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CoreServiceServer).ProcessStop(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: CoreService_ProcessStop_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CoreServiceServer).ProcessStop(ctx, req.(*ProcessStopRequest))
}
return interceptor(ctx, in, info, handler)
}
// CoreService_ServiceDesc is the grpc.ServiceDesc for CoreService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var CoreService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "coredeno.CoreService",
HandlerType: (*CoreServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "FileRead",
Handler: _CoreService_FileRead_Handler,
},
{
MethodName: "FileWrite",
Handler: _CoreService_FileWrite_Handler,
},
{
MethodName: "FileList",
Handler: _CoreService_FileList_Handler,
},
{
MethodName: "FileDelete",
Handler: _CoreService_FileDelete_Handler,
},
{
MethodName: "StoreGet",
Handler: _CoreService_StoreGet_Handler,
},
{
MethodName: "StoreSet",
Handler: _CoreService_StoreSet_Handler,
},
{
MethodName: "ProcessStart",
Handler: _CoreService_ProcessStart_Handler,
},
{
MethodName: "ProcessStop",
Handler: _CoreService_ProcessStop_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "pkg/coredeno/proto/coredeno.proto",
}
const (
DenoService_LoadModule_FullMethodName = "/coredeno.DenoService/LoadModule"
DenoService_UnloadModule_FullMethodName = "/coredeno.DenoService/UnloadModule"
DenoService_ModuleStatus_FullMethodName = "/coredeno.DenoService/ModuleStatus"
)
// DenoServiceClient is the client API for DenoService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// DenoService is implemented by CoreDeno — Go calls this for module lifecycle.
type DenoServiceClient interface {
LoadModule(ctx context.Context, in *LoadModuleRequest, opts ...grpc.CallOption) (*LoadModuleResponse, error)
UnloadModule(ctx context.Context, in *UnloadModuleRequest, opts ...grpc.CallOption) (*UnloadModuleResponse, error)
ModuleStatus(ctx context.Context, in *ModuleStatusRequest, opts ...grpc.CallOption) (*ModuleStatusResponse, error)
}
type denoServiceClient struct {
cc grpc.ClientConnInterface
}
func NewDenoServiceClient(cc grpc.ClientConnInterface) DenoServiceClient {
return &denoServiceClient{cc}
}
func (c *denoServiceClient) LoadModule(ctx context.Context, in *LoadModuleRequest, opts ...grpc.CallOption) (*LoadModuleResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(LoadModuleResponse)
err := c.cc.Invoke(ctx, DenoService_LoadModule_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *denoServiceClient) UnloadModule(ctx context.Context, in *UnloadModuleRequest, opts ...grpc.CallOption) (*UnloadModuleResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UnloadModuleResponse)
err := c.cc.Invoke(ctx, DenoService_UnloadModule_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *denoServiceClient) ModuleStatus(ctx context.Context, in *ModuleStatusRequest, opts ...grpc.CallOption) (*ModuleStatusResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ModuleStatusResponse)
err := c.cc.Invoke(ctx, DenoService_ModuleStatus_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// DenoServiceServer is the server API for DenoService service.
// All implementations must embed UnimplementedDenoServiceServer
// for forward compatibility.
//
// DenoService is implemented by CoreDeno — Go calls this for module lifecycle.
type DenoServiceServer interface {
LoadModule(context.Context, *LoadModuleRequest) (*LoadModuleResponse, error)
UnloadModule(context.Context, *UnloadModuleRequest) (*UnloadModuleResponse, error)
ModuleStatus(context.Context, *ModuleStatusRequest) (*ModuleStatusResponse, error)
mustEmbedUnimplementedDenoServiceServer()
}
// UnimplementedDenoServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedDenoServiceServer struct{}
func (UnimplementedDenoServiceServer) LoadModule(context.Context, *LoadModuleRequest) (*LoadModuleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method LoadModule not implemented")
}
func (UnimplementedDenoServiceServer) UnloadModule(context.Context, *UnloadModuleRequest) (*UnloadModuleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UnloadModule not implemented")
}
func (UnimplementedDenoServiceServer) ModuleStatus(context.Context, *ModuleStatusRequest) (*ModuleStatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ModuleStatus not implemented")
}
func (UnimplementedDenoServiceServer) mustEmbedUnimplementedDenoServiceServer() {}
func (UnimplementedDenoServiceServer) testEmbeddedByValue() {}
// UnsafeDenoServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to DenoServiceServer will
// result in compilation errors.
type UnsafeDenoServiceServer interface {
mustEmbedUnimplementedDenoServiceServer()
}
func RegisterDenoServiceServer(s grpc.ServiceRegistrar, srv DenoServiceServer) {
// If the following call panics, it indicates UnimplementedDenoServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&DenoService_ServiceDesc, srv)
}
func _DenoService_LoadModule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LoadModuleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DenoServiceServer).LoadModule(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: DenoService_LoadModule_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DenoServiceServer).LoadModule(ctx, req.(*LoadModuleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _DenoService_UnloadModule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UnloadModuleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DenoServiceServer).UnloadModule(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: DenoService_UnloadModule_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DenoServiceServer).UnloadModule(ctx, req.(*UnloadModuleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _DenoService_ModuleStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ModuleStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DenoServiceServer).ModuleStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: DenoService_ModuleStatus_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DenoServiceServer).ModuleStatus(ctx, req.(*ModuleStatusRequest))
}
return interceptor(ctx, in, info, handler)
}
// DenoService_ServiceDesc is the grpc.ServiceDesc for DenoService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var DenoService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "coredeno.DenoService",
HandlerType: (*DenoServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "LoadModule",
Handler: _DenoService_LoadModule_Handler,
},
{
MethodName: "UnloadModule",
Handler: _DenoService_UnloadModule_Handler,
},
{
MethodName: "ModuleStatus",
Handler: _DenoService_ModuleStatus_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "pkg/coredeno/proto/coredeno.proto",
}

131
pkg/coredeno/server.go Normal file
View file

@ -0,0 +1,131 @@
package coredeno
import (
"context"
"fmt"
pb "forge.lthn.ai/core/go/pkg/coredeno/proto"
"forge.lthn.ai/core/go/pkg/io"
"forge.lthn.ai/core/go/pkg/manifest"
"forge.lthn.ai/core/go/pkg/store"
)
// Server implements the CoreService gRPC interface with permission gating.
// Every I/O request is checked against the calling module's declared permissions.
type Server struct {
pb.UnimplementedCoreServiceServer
medium io.Medium
store *store.Store
manifests map[string]*manifest.Manifest
}
// NewServer creates a CoreService server backed by the given Medium and Store.
func NewServer(medium io.Medium, st *store.Store) *Server {
return &Server{
medium: medium,
store: st,
manifests: make(map[string]*manifest.Manifest),
}
}
// RegisterModule adds a module's manifest to the permission registry.
func (s *Server) RegisterModule(m *manifest.Manifest) {
s.manifests[m.Code] = m
}
// getManifest looks up a module and returns an error if unknown.
func (s *Server) getManifest(code string) (*manifest.Manifest, error) {
m, ok := s.manifests[code]
if !ok {
return nil, fmt.Errorf("unknown module: %s", code)
}
return m, nil
}
// FileRead implements CoreService.FileRead with permission gating.
func (s *Server) FileRead(_ context.Context, req *pb.FileReadRequest) (*pb.FileReadResponse, error) {
m, err := s.getManifest(req.ModuleCode)
if err != nil {
return nil, err
}
if !CheckPath(req.Path, m.Permissions.Read) {
return nil, fmt.Errorf("permission denied: %s cannot read %s", req.ModuleCode, req.Path)
}
content, err := s.medium.Read(req.Path)
if err != nil {
return nil, err
}
return &pb.FileReadResponse{Content: content}, nil
}
// FileWrite implements CoreService.FileWrite with permission gating.
func (s *Server) FileWrite(_ context.Context, req *pb.FileWriteRequest) (*pb.FileWriteResponse, error) {
m, err := s.getManifest(req.ModuleCode)
if err != nil {
return nil, err
}
if !CheckPath(req.Path, m.Permissions.Write) {
return nil, fmt.Errorf("permission denied: %s cannot write %s", req.ModuleCode, req.Path)
}
if err := s.medium.Write(req.Path, req.Content); err != nil {
return nil, err
}
return &pb.FileWriteResponse{Ok: true}, nil
}
// FileList implements CoreService.FileList with permission gating.
func (s *Server) FileList(_ context.Context, req *pb.FileListRequest) (*pb.FileListResponse, error) {
m, err := s.getManifest(req.ModuleCode)
if err != nil {
return nil, err
}
if !CheckPath(req.Path, m.Permissions.Read) {
return nil, fmt.Errorf("permission denied: %s cannot list %s", req.ModuleCode, req.Path)
}
entries, err := s.medium.List(req.Path)
if err != nil {
return nil, err
}
var pbEntries []*pb.FileEntry
for _, e := range entries {
info, _ := e.Info()
pbEntries = append(pbEntries, &pb.FileEntry{
Name: e.Name(),
IsDir: e.IsDir(),
Size: info.Size(),
})
}
return &pb.FileListResponse{Entries: pbEntries}, nil
}
// FileDelete implements CoreService.FileDelete with permission gating.
func (s *Server) FileDelete(_ context.Context, req *pb.FileDeleteRequest) (*pb.FileDeleteResponse, error) {
m, err := s.getManifest(req.ModuleCode)
if err != nil {
return nil, err
}
if !CheckPath(req.Path, m.Permissions.Write) {
return nil, fmt.Errorf("permission denied: %s cannot delete %s", req.ModuleCode, req.Path)
}
if err := s.medium.Delete(req.Path); err != nil {
return nil, err
}
return &pb.FileDeleteResponse{Ok: true}, nil
}
// StoreGet implements CoreService.StoreGet.
func (s *Server) StoreGet(_ context.Context, req *pb.StoreGetRequest) (*pb.StoreGetResponse, error) {
val, err := s.store.Get(req.Group, req.Key)
if err != nil {
return &pb.StoreGetResponse{Found: false}, nil
}
return &pb.StoreGetResponse{Value: val, Found: true}, nil
}
// StoreSet implements CoreService.StoreSet.
func (s *Server) StoreSet(_ context.Context, req *pb.StoreSetRequest) (*pb.StoreSetResponse, error) {
if err := s.store.Set(req.Group, req.Key, req.Value); err != nil {
return nil, err
}
return &pb.StoreSetResponse{Ok: true}, nil
}

View file

@ -0,0 +1,97 @@
package coredeno
import (
"context"
"testing"
"forge.lthn.ai/core/go/pkg/io"
"forge.lthn.ai/core/go/pkg/manifest"
pb "forge.lthn.ai/core/go/pkg/coredeno/proto"
"forge.lthn.ai/core/go/pkg/store"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func newTestServer(t *testing.T) *Server {
t.Helper()
medium := io.NewMockMedium()
medium.Files["./data/test.txt"] = "hello"
st, err := store.New(":memory:")
require.NoError(t, err)
t.Cleanup(func() { st.Close() })
srv := NewServer(medium, st)
srv.RegisterModule(&manifest.Manifest{
Code: "test-mod",
Permissions: manifest.Permissions{
Read: []string{"./data/"},
Write: []string{"./data/"},
},
})
return srv
}
func TestFileRead_Good(t *testing.T) {
srv := newTestServer(t)
resp, err := srv.FileRead(context.Background(), &pb.FileReadRequest{
Path: "./data/test.txt", ModuleCode: "test-mod",
})
require.NoError(t, err)
assert.Equal(t, "hello", resp.Content)
}
func TestFileRead_Bad_PermissionDenied(t *testing.T) {
srv := newTestServer(t)
_, err := srv.FileRead(context.Background(), &pb.FileReadRequest{
Path: "./secrets/key.pem", ModuleCode: "test-mod",
})
assert.Error(t, err)
assert.Contains(t, err.Error(), "permission denied")
}
func TestFileRead_Bad_UnknownModule(t *testing.T) {
srv := newTestServer(t)
_, err := srv.FileRead(context.Background(), &pb.FileReadRequest{
Path: "./data/test.txt", ModuleCode: "unknown",
})
assert.Error(t, err)
assert.Contains(t, err.Error(), "unknown module")
}
func TestFileWrite_Good(t *testing.T) {
srv := newTestServer(t)
resp, err := srv.FileWrite(context.Background(), &pb.FileWriteRequest{
Path: "./data/new.txt", Content: "world", ModuleCode: "test-mod",
})
require.NoError(t, err)
assert.True(t, resp.Ok)
}
func TestFileWrite_Bad_PermissionDenied(t *testing.T) {
srv := newTestServer(t)
_, err := srv.FileWrite(context.Background(), &pb.FileWriteRequest{
Path: "./secrets/bad.txt", Content: "nope", ModuleCode: "test-mod",
})
assert.Error(t, err)
assert.Contains(t, err.Error(), "permission denied")
}
func TestStoreGetSet_Good(t *testing.T) {
srv := newTestServer(t)
ctx := context.Background()
_, err := srv.StoreSet(ctx, &pb.StoreSetRequest{Group: "cfg", Key: "theme", Value: "dark"})
require.NoError(t, err)
resp, err := srv.StoreGet(ctx, &pb.StoreGetRequest{Group: "cfg", Key: "theme"})
require.NoError(t, err)
assert.True(t, resp.Found)
assert.Equal(t, "dark", resp.Value)
}
func TestStoreGet_Good_NotFound(t *testing.T) {
srv := newTestServer(t)
resp, err := srv.StoreGet(context.Background(), &pb.StoreGetRequest{Group: "cfg", Key: "missing"})
require.NoError(t, err)
assert.False(t, resp.Found)
}