#r #plumber #apparmor
#r #сантехник #снаряжение
Вопрос:
Я просто хочу объединить пакеты plumber и RAppArmor таким образом, чтобы пользователи могли отправлять код с помощью plumber-API на сервер, который затем безопасно оценивается с помощью профилей в RAppArmor. Как я могу заставить следующий код работать:
#* Evaluate the result
#* @post /eval_res
function(func){
library("RAppArmor")
data <- cbind(rnorm(100),rnorm(100))
eval.secure(nrow(data),profile="r-user")
}
Этот фрагмент кода представляет собой упрощенную версию того, что произойдет позже. Пока кажется, что любой объект, указанный в функции, например data, не может быть передан в eval.secure, учитывая ограничения пользователя в r-user (стандартный профиль RAppArmor). Я даже пытался разрешить полный доступ к /** для r-пользователя, отредактировав профиль, но безуспешно. Открытие plumber на localhost и использование curl с curl --data "func=function(x){return(nrow(x))}" "http://localhost:8000/eval_res"
для получения результата eval.secure() приводит к пустому ответу {}
. Тот же код работает без eval.secure() и корректно возвращает [100]
результат. Может ли кто-нибудь помочь мне, чтобы я лучше понял проблему или даже исправил код?
Мой текущий обходной путь — сохранить все в формате csv перед eval.secure(), а затем прочитать его в eval.secure, предоставив доступ к этой папке в профиле r-user, но это определенно не убедительное решение.
Для тех из вас, кто запутался в функции: на более позднем этапе опция func будет содержать некоторый код, который будет проанализирован и оценен, но для этого небольшого примера я подумал, что это только добавит ненужной сложности.
Заранее спасибо!
Ответ №1:
library("RAppArmor")
#* Evaluate the result
#* @post /eval_res
function(func){
data <- cbind(rnorm(100),rnorm(100))
unix::eval_safe(nrow(data), profile="r-user")
}
Итак
library("RAppArmor")
#* Evaluate the result
#* @post /eval_res
function(func){
data <- cbind(rnorm(100),rnorm(100))
unix::eval_safe(eval(parse(text=func)), profile="r-user")
}
eval.secure
просто передайте все параметры unix::eval_safe
. Причина eval.secure
, по которой это не работает, заключается в том, что eval_safe
ожидает найти ваши переменные в its parent.frame()
, что в случае eval.secure
является пустым телом функции.
eval_safe
использование parent.frame()
function (expr, tmp = tempfile("fork"), std_out = stdout(), std_err = stderr(),
timeout = 0, priority = NULL, uid = NULL, gid = NULL, rlimits = NULL,
profile = NULL, device = pdf)
{
orig_expr <- substitute(expr)
out <- eval_fork(expr = tryCatch({
if (length(priority))
setpriority(priority)
if (length(rlimits))
set_rlimits(rlimits)
if (length(gid))
setgid(gid)
if (length(uid))
setuid(uid)
if (length(profile))
aa_change_profile(profile)
if (length(device))
options(device = device)
graphics.off()
options(menu.graphics = FALSE)
------> serialize(withVisible(eval(orig_expr, parent.frame())),
NULL)
}, error = function(e) {
old_class <- attr(e, "class")
structure(e, class = c(old_class, "eval_fork_error"))
}, finally = substitute(graphics.off())), tmp = tmp, timeout = timeout,
std_out = std_out, std_err = std_err)
if (inherits(out, "eval_fork_error"))
base::stop(out)
res <- unserialize(out)
if (res$visible)
res$value
else invisible(res$value)
}
# parent.frame() in eval_safe when using eval.secure
function (...)
{
# nothing here
unix::eval_safe(...)
}
# parent.frame() when using eval_safe directly
function(func){
data <- cbind(rnorm(100),rnorm(100))
# Your stuff is here
unix::eval_safe(nrow(data), profile="r-user")
}
Комментарии:
1. Это было именно то, что мне было нужно. Большое вам спасибо!