dify icon indicating copy to clipboard operation
dify copied to clipboard

JS Code Node: "operation not permitted"

Open hmenzagh opened this issue 1 year ago • 8 comments

Self Checks

  • [X] This is only for bug report, if you would like to ask a question, please head to Discussions.
  • [X] I have searched for existing issues search for existing issues, including closed ones.
  • [X] I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
  • [X] [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:)
  • [X] Please do not modify this template :) and fill in all the required fields.

Dify version

0.13.2

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

TLDR: Running Python3 Code nodes works fine, JS one outputs error "operation not permitted" regardless of the code. Details:

  • I'm running Dify self-hosted with docker-compose. Pretty stock & vanilla at this point.
  • My machine is a Apple Silicon mac running Asahi Linux, so platform is ideally linux/arm64.
  • Tried changing the sandbox container's platform to amd64 & arm64
  • There are no errors in the logs, just a log attesting POST request is recieved
  • Sandbox API Key is personalised
  • Error appears by running the node or the workflow itself
  • Error is not linked to input params either
  • Tried using this image too: langgenius/dify-sandbox:f40de1f6bc5f87d0e847cbf52076280bf61c05d5 Any ideas ? 😦

✔️ Expected Behavior

Not an error

❌ Actual Behavior

Returns error: "operation not permitted"

hmenzagh avatar Dec 15 '24 21:12 hmenzagh

Hey @hmenzagh! 👋 I'm here to help you with bugs, questions, and becoming a contributor. Let's squash those bugs together!

I found a similar closed issue that might be relevant to your problem. The issue titled "Workflow run code tool error: operation not permitted" suggests that the "operation not permitted" error is likely related to the Docker environment rather than the code itself. Here are some steps that were suggested to troubleshoot and potentially resolve the issue:

  1. Check Docker Permissions: Ensure the Docker container has the necessary permissions. Adjust the Dockerfile or run the container with a user that has the required permissions.
  2. Volume Mounts: Verify that the Docker container has the correct volume mounts with the appropriate permissions for any file operations.
  3. Container User: Make sure the Docker container runs as a user with sufficient permissions, specified either in the Dockerfile or with the --user flag when running the container.
  4. SELinux/AppArmor Policies: If SELinux or AppArmor is active, adjust the policies to allow the needed operations.
  5. File System Permissions: On the host, ensure file system permissions allow the Docker container's user to perform the necessary operations.
  6. Docker Security Options: Consider Docker's security options like --cap-add or --privileged to grant additional permissions, but use them cautiously.
  7. Review Docker Logs: The Docker container logs might provide additional insights into the permission issue.
  8. Python Code Operations: Ensure the Docker environment supports any special permissions required by operations in your Python code.

For Dify v0.6.1 running in Docker, especially note that the docker-compose.yaml file indicates the need for SYS_ADMIN capabilities for certain operations. This is a critical point to check if your workflow involves operations that require elevated privileges [1].

To continue talking to Dosu, mention @dosu.


Help Dosu learn! Give it feedback: Great Response | Irrelevant Answer | Incorrect Sources | Too Verbose | Hallucination | Other

dosubot[bot] avatar Dec 15 '24 21:12 dosubot[bot]

also found that in my local machine (docker-compose mac m3) will give a try to figure out why these days

yihong0618 avatar Dec 16 '24 00:12 yihong0618

more info if we run pytest -s api/tests/integration_tests/workflow

docker ps -a

langgenius/dify-sandbox:0.2.10

the javascript side fails

_______________________________________________________________ test_javascript_plain ________________________________________________________________

    def test_javascript_plain():
        code = 'console.log("Hello World")'
>       result_message = CodeExecutor.execute_code(language=CODE_LANGUAGE, preload="", code=code)

api/tests/integration_tests/workflow/nodes/code_executor/test_code_javascript.py:12: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'core.helper.code_executor.code_executor.CodeExecutor'>, language = <CodeLanguage.JAVASCRIPT: 'javascript'>, preload = '', code = 0

    @classmethod
    def execute_code(cls, language: CodeLanguage, preload: str, code: str) -> str:
        """
        Execute code
        :param language: code language
        :param code: code
        :return:
        """
        url = URL(str(dify_config.CODE_EXECUTION_ENDPOINT)) / "v1" / "sandbox" / "run"
    
        headers = {"X-Api-Key": dify_config.CODE_EXECUTION_API_KEY}
    
        data = {
            "language": cls.code_language_to_running_language.get(language),
            "code": code,
            "preload": preload,
            "enable_network": True,
        }
    
        try:
            response = post(
                str(url),
                json=data,
                headers=headers,
                timeout=Timeout(
                    connect=dify_config.CODE_EXECUTION_CONNECT_TIMEOUT,
                    read=dify_config.CODE_EXECUTION_READ_TIMEOUT,
                    write=dify_config.CODE_EXECUTION_WRITE_TIMEOUT,
                    pool=None,
                ),
            )
            if response.status_code == 503:
                raise CodeExecutionError("Code execution service is unavailable")
            elif response.status_code != 200:
                raise Exception(
                    f"Failed to execute code, got status code {response.status_code},"
                    f" please check if the sandbox service is running"
                )
        except CodeExecutionError as e:
            raise e
        except Exception as e:
            raise CodeExecutionError(
                "Failed to execute code, which is likely a network issue,"
                " please check if the sandbox service is running."
                f" ( Error: {str(e)} )"
            )
    
        try:
            response = response.json()
        except:
            raise CodeExecutionError("Failed to parse response")
    
        if (code := response.get("code")) != 0:
            raise CodeExecutionError(f"Got error code: {code}. Got error msg: {response.get('message')}")
    
        response = CodeExecutionResponse(**response)
    
        if response.data.error:
>           raise CodeExecutionError(response.data.error)
E           core.helper.code_executor.code_executor.CodeExecutionError: error: operation not permitted

api/core/helper/code_executor/code_executor.py:116: CodeExecutionError
________________________________________________________________ test_javascript_json ________________________________________________________________

    def test_javascript_json():
        code = dedent("""
        obj = {'Hello': 'World'}
        console.log(JSON.stringify(obj))
        """)
>       result = CodeExecutor.execute_code(language=CODE_LANGUAGE, preload="", code=code)

api/tests/integration_tests/workflow/nodes/code_executor/test_code_javascript.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'core.helper.code_executor.code_executor.CodeExecutor'>, language = <CodeLanguage.JAVASCRIPT: 'javascript'>, preload = '', code = 0

    @classmethod
    def execute_code(cls, language: CodeLanguage, preload: str, code: str) -> str:
        """
        Execute code
        :param language: code language
        :param code: code
        :return:
        """
        url = URL(str(dify_config.CODE_EXECUTION_ENDPOINT)) / "v1" / "sandbox" / "run"
    
        headers = {"X-Api-Key": dify_config.CODE_EXECUTION_API_KEY}
    
        data = {
            "language": cls.code_language_to_running_language.get(language),
            "code": code,
            "preload": preload,
            "enable_network": True,
        }
    
        try:
            response = post(
                str(url),
                json=data,
                headers=headers,
                timeout=Timeout(
                    connect=dify_config.CODE_EXECUTION_CONNECT_TIMEOUT,
                    read=dify_config.CODE_EXECUTION_READ_TIMEOUT,
                    write=dify_config.CODE_EXECUTION_WRITE_TIMEOUT,
                    pool=None,
                ),
            )
            if response.status_code == 503:
                raise CodeExecutionError("Code execution service is unavailable")
            elif response.status_code != 200:
                raise Exception(
                    f"Failed to execute code, got status code {response.status_code},"
                    f" please check if the sandbox service is running"
                )
        except CodeExecutionError as e:
            raise e
        except Exception as e:
            raise CodeExecutionError(
                "Failed to execute code, which is likely a network issue,"
                " please check if the sandbox service is running."
                f" ( Error: {str(e)} )"
            )
    
        try:
            response = response.json()
        except:
            raise CodeExecutionError("Failed to parse response")
    
        if (code := response.get("code")) != 0:
            raise CodeExecutionError(f"Got error code: {code}. Got error msg: {response.get('message')}")
    
        response = CodeExecutionResponse(**response)
    
        if response.data.error:
>           raise CodeExecutionError(response.data.error)
E           core.helper.code_executor.code_executor.CodeExecutionError: error: operation not permitted

api/core/helper/code_executor/code_executor.py:116: CodeExecutionError
_________________________________________________________ test_javascript_with_code_template _________________________________________________________

    def test_javascript_with_code_template():
>       result = CodeExecutor.execute_workflow_code_template(
            language=CODE_LANGUAGE,
            code=JavascriptCodeProvider.get_default_code(),
            inputs={"arg1": "Hello", "arg2": "World"},
        )

api/tests/integration_tests/workflow/nodes/code_executor/test_code_javascript.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
api/core/helper/code_executor/code_executor.py:138: in execute_workflow_code_template
    raise e
api/core/helper/code_executor/code_executor.py:136: in execute_workflow_code_template
    response = cls.execute_code(language, preload, runner)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'core.helper.code_executor.code_executor.CodeExecutor'>, language = <CodeLanguage.JAVASCRIPT: 'javascript'>, preload = '', code = 0

    @classmethod
    def execute_code(cls, language: CodeLanguage, preload: str, code: str) -> str:
        """
        Execute code
        :param language: code language
        :param code: code
        :return:
        """
        url = URL(str(dify_config.CODE_EXECUTION_ENDPOINT)) / "v1" / "sandbox" / "run"
    
        headers = {"X-Api-Key": dify_config.CODE_EXECUTION_API_KEY}
    
        data = {
            "language": cls.code_language_to_running_language.get(language),
            "code": code,
            "preload": preload,
            "enable_network": True,
        }
    
        try:
            response = post(
                str(url),
                json=data,
                headers=headers,
                timeout=Timeout(
                    connect=dify_config.CODE_EXECUTION_CONNECT_TIMEOUT,
                    read=dify_config.CODE_EXECUTION_READ_TIMEOUT,
                    write=dify_config.CODE_EXECUTION_WRITE_TIMEOUT,
                    pool=None,
                ),
            )
            if response.status_code == 503:
                raise CodeExecutionError("Code execution service is unavailable")
            elif response.status_code != 200:
                raise Exception(
                    f"Failed to execute code, got status code {response.status_code},"
                    f" please check if the sandbox service is running"
                )
        except CodeExecutionError as e:
            raise e
        except Exception as e:
            raise CodeExecutionError(
                "Failed to execute code, which is likely a network issue,"
                " please check if the sandbox service is running."
                f" ( Error: {str(e)} )"
            )
    
        try:
            response = response.json()
        except:
            raise CodeExecutionError("Failed to parse response")
    
        if (code := response.get("code")) != 0:
            raise CodeExecutionError(f"Got error code: {code}. Got error msg: {response.get('message')}")
    
        response = CodeExecutionResponse(**response)
    
        if response.data.error:
>           raise CodeExecutionError(response.data.error)
E           core.helper.code_executor.code_executor.CodeExecutionError: error: operation not permitted

api/core/helper/code_executor/code_executor.py:116: CodeExecutionError

yihong0618 avatar Dec 16 '24 02:12 yihong0618

Additional Info:

  • Works on my M2 mac running MacOS
  • Does not work on Asahi Linux (tried a fresh install)
  • Works on my RPi

hmenzagh avatar Dec 16 '24 09:12 hmenzagh

Additional Info:

  • Works on my M2 mac running MacOS
  • Does not work on Asahi Linux (tried a fresh install)
  • Works on my RPi

I build local(use orbstack) and load in my M3 macbook it succeed...

yihong0618 avatar Dec 16 '24 14:12 yihong0618

Hi, @hmenzagh. I'm Dosu, and I'm helping the Dify team manage their backlog. I'm marking this issue as stale.

Issue Summary:

  • "Operation not permitted" error occurs when executing JavaScript code nodes in a self-hosted Dify setup on Asahi Linux.
  • Attempts to adjust the sandbox container's platform have not resolved the issue.
  • The setup works on an M2 Mac running MacOS and a Raspberry Pi, suggesting a compatibility issue with Asahi Linux.
  • @yihong0618 is also experiencing similar issues and is investigating further.

Next Steps:

  • Please confirm if this issue is still relevant with the latest version of the Dify repository. If so, you can keep the discussion open by commenting here.
  • If there is no further activity, this issue will be automatically closed in 15 days.

Thank you for your understanding and contribution!

dosubot[bot] avatar Jan 22 '25 16:01 dosubot[bot]

Just tried on 15.2 from a fresh install, still failing

hmenzagh avatar Feb 02 '25 18:02 hmenzagh

Hi, @hmenzagh. I'm Dosu, and I'm helping the Dify team manage their backlog. I'm marking this issue as stale.

Issue Summary:

  • JavaScript code nodes in a self-hosted Dify setup on Asahi Linux result in an "operation not permitted" error.
  • Python3 nodes function correctly, indicating a specific issue with JavaScript nodes.
  • Various troubleshooting steps, including changing the sandbox container's platform, have not resolved the issue.
  • The issue persists on a fresh install of Asahi Linux 15.2, suggesting a compatibility problem with this environment.
  • @yihong0618 is also experiencing similar issues and is investigating further.

Next Steps:

  • Please confirm if this issue is still relevant with the latest version of the Dify repository. If so, you can keep the discussion open by commenting here.
  • If there is no further activity, this issue will be automatically closed in 15 days.

Thank you for your understanding and contribution!

dosubot[bot] avatar Mar 05 '25 16:03 dosubot[bot]