No permission to declare safe_goal?

I’m using: SWI-Prolog version 8.1.2 and adding an app to the Prolog Engine application server, current master branch.

I am using library(persistency) on a pengine, so I’m calling with_mutex/2, which is an unsafe predicate. I want to declare the predicate that calls with_mutex/2 as safe and am following the rdf example in the docs.

But what I’m getting is:
ERROR: No permission to declare safe_goal `projects_manager:get_project/1’

My code looks like this:

apps/my_app/app.pl

:- module(my_app, []).

:- prolog_load_context(directory, Dir),
   asserta(user:file_search_path(my_app, Dir)).

:- use_module(library(pengines)).
:- pengine_application(my_app).
:- use_module(my_app:projects).

:- use_module(pengine_sandbox:my_app(projects_manager/projects_manager)).
:- use_module(library(sandbox)).
:- multifile sandbox:safe_primitive/1.

sandbox:safe_primitive(projects_manager:get_project/1).

apps/my_app/projects.pl

:- module(projects, []).

:- reexport(my_app(projects_manager/projects_manager)).

apps/my_app/projects_manager/projects_manager.pl

:- module(projects_manager,
    [ get_project/1
    , set_project/1
   %, ... etc.
    ]
).

:- use_module(library(persistency)).
:- persistent project(id:atom, project:any).

get_project(Project) :-
    user_project_id(ID), % from another module, not causing issues
    with_mutex(projects_mutex, project(ID, Project)).
1 Like

One possible reason is that the predicate is not yet defined. safe_primitive/1 can only be used on defined predicates that are not meta predicates. That is a safety measure to avoid clearly wrong safe declarations. So, you may have to change the declaration order. I normally put sandbox declarations at the bottom of the file in which the safe predicates are defined. Note that if you do not use sandboxing this has no consequences except for one unused clause.

1 Like

Thank’s Jan, I tried that, still the same error. I’ve also tried jiggling around when the persistent db file is attached, but that doesn’t seem to help either.

My code now looks like this:

apps/my_app/app.pl

:- module(my_app, []).

:- prolog_load_context(directory, Dir),
   asserta(user:file_search_path(my_app, Dir)).

:- use_module(library(pengines)).
:- pengine_application(my_app).
:- use_module(my_app:projects).

apps/my_app/projects.pl

:- module(projects, []).

:- reexport(my_app(projects_manager/projects_manager)).

apps/my_app/projects_manager/projects_manager.pl

:- module(projects_manager,
    [ get_project/1
    , set_project/1
   %, ... etc.
    ]
).

:- use_module(library(persistency)).
:- persistent project(id:atom, project:any).

get_project(Project) :-
    user_project_id(ID), % from another module, not causing issues
    with_mutex(projects_mutex, project(ID, Project)).


:- use_module(pengine_sandbox:projects_manager).
:- use_module(library(sandbox)).
:- multifile sandbox:safe_primitive/1.

sandbox:safe_primitive(projects_manager:get_project/1).

The argument is a goal, not a predicate indicator. This allows you to verify the safety of the arguments.

2 Likes

Ah-Ha! Thank you Jan! Can’t believe I didn’t see that… All working beautifully now.