Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Added command center #2674

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

Sahil-Chhoker
Copy link
Collaborator

@Sahil-Chhoker Sahil-Chhoker commented Feb 9, 2025

Summary

This feature is inspired by this comment from issue #2176.

This pull request aims to add a command center into Solara Viz to execute commands directly from the browser to your model.

Implementation

This PR adds a solara component named CommandCenter into the sidebar directly. Runs commands written in the text area directly in the global scope using exec function and updates the visualization to show the changes.
image

Every function and property available through model can be used and updated using the command center. Some examples:

  1. model.step()
  2. print(len(model.agents))
  3. Something like this can also work:
  from mesa.experimental.continuous_space import ContinuousSpace, ContinuousSpaceAgent 
  import random
  
  agents = model.agents_by_type[ContinuousSpaceAgent]
  
  for agent in agents:
     agent.position = [random.random(), random.random()]

For custom imports:

from agents import myAgent

page = SolaraViz(
    model,
    components=[space_component],
    model_params=model_params,
    name="Test Model",
    additional_imports={
        "myAgent": myAgent, # for custom classes
        "np" : "import numpy as np", # for strings
    }
)
page

now both np and myAgent can be used in the command center.

Copy link

github-actions bot commented Feb 9, 2025

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 +3.3% [+2.1%, +4.5%] 🔵 -0.7% [-0.9%, -0.6%]
BoltzmannWealth large 🔵 -0.8% [-1.2%, -0.3%] 🔵 +1.1% [+0.6%, +1.6%]
Schelling small 🔵 -0.3% [-0.7%, -0.0%] 🔵 -0.2% [-0.4%, -0.0%]
Schelling large 🔵 -0.5% [-0.7%, -0.2%] 🔵 -0.6% [-1.5%, +0.2%]
WolfSheep small 🔵 +0.3% [+0.1%, +0.5%] 🔵 +0.1% [-0.1%, +0.3%]
WolfSheep large 🔵 +1.4% [+0.8%, +2.1%] 🔵 +3.2% [+2.3%, +4.3%]
BoidFlockers small 🔵 -0.1% [-0.5%, +0.4%] 🔵 -0.1% [-0.3%, +0.0%]
BoidFlockers large 🔵 +0.5% [+0.3%, +0.8%] 🔵 +0.4% [+0.2%, +0.7%]

@Sahil-Chhoker
Copy link
Collaborator Author

Some known limitations:

  1. Ruff error S102.
  2. Ugly spellcheck:
    image

@Sahil-Chhoker
Copy link
Collaborator Author

@EwoutH Since you were the one who recommended this feature over on issue #2176, I would love to hear your thoughts on this.

@EwoutH EwoutH requested review from Corvince, quaquel and EwoutH February 9, 2025 09:32
@EwoutH EwoutH added feature Release notes label visualisation labels Feb 9, 2025
@EwoutH
Copy link
Member

EwoutH commented Feb 9, 2025

This is super cool. I'm in a long distance train this afternoon, I will try to look at it then!

@quaquel
Copy link
Member

quaquel commented Feb 9, 2025

I think this is cool. However, the unchecked use of exec is a massive security risk. Just try import shutil; shutil.rmtree("/"),.....

I don't have time to dig a bit deeper, but e.g., https://www.stackhawk.com/blog/command-injection-python/ might be a good starting point to think about this a bit more.

@EwoutH
Copy link
Member

EwoutH commented Feb 9, 2025

Really like the idea so far!

There are a few minor things. For example, to make it practical, it should probably import at least the Agent types used (in this example Wolf, Sheep, etc.)

image

@Sahil-Chhoker
Copy link
Collaborator Author

@EwoutH I don't think it is possible to import custom classes directly, but it works if the additional imports are passed to the to SolaraViz instance

@quaquel
Copy link
Member

quaquel commented Feb 9, 2025

I suggest also checking the code module, which allows you to attach a full console to a running python process.

@Sahil-Chhoker
Copy link
Collaborator Author

I did some research on making exec() safer, and with a little help from AI, I came up with this final implementation. It throws an error for dangerous commands. Also, since the server runs on the client's machine, it's unlikely they'd try to sabotage themselves.

@Sahil-Chhoker
Copy link
Collaborator Author

I suggest also checking the code module, which allows you to attach a full console to a running python process.

The code module could be useful for turning the command center into a command console. I also tried building it separately, but with my current Solara skills, it looks quite ugly.

@quaquel
Copy link
Member

quaquel commented Feb 11, 2025

The code module could be useful for turning the command center into a command console. I also tried building it separately, but with my current Solara skills, it looks quite ugly.

Thanks for checking! Might it be an idea to open a separate discussion or issue where you share what you did? One dream feature would be to have a full variable explorer and console when running mesa models through the GUI. This PR is a stepping stone towards that vision and anything you learned can be valuable for others. I'll try to review this PR more closely hopefully over the weekend.

@Sahil-Chhoker
Copy link
Collaborator Author

One dream feature would be to have a full variable explorer and console when running mesa models through the GUI.

That sounds like a great feature! I have opened an issue (#2683) for discussions. I decided to start from scratch to make it easier to incorporate valuable input. I would greatly appreciate any help you can provide!

@@ -157,6 +164,8 @@ def SolaraViz(
)
with solara.Card("Information"):
ShowSteps(model.value)
with solara.Card("Command Center"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want the command center to be allways there, or make it optional in some way?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally would prefer it to be always be there, it will encourage the users to play around with it and know it better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a design point of view, I prefer giving users the choice but show it in all our examples.

Someone might want to built a UI with very limited possibility for interaction, or only show the animation to a client.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, does a boolean parameter in SolaraViz work?

Copy link
Member

@quaquel quaquel Feb 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking more along the lines of treating it as a component so you could just at it to the list of components:

page = SolaraViz(
    model,
    components=[SpaceComponent, SomeGraphComponent, Console],
    model_params=model_params,
    name="my fancy model",
)

But I am open to having it as a boolean as well. I haven't thought about the layout anyway in great detail.

Copy link
Collaborator Author

@Sahil-Chhoker Sahil-Chhoker Feb 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that works as well, in fact that is more intuitive. I like this idea more than that of a boolean.

@@ -586,3 +595,156 @@ def ShowSteps(model):
"""Display the current step of the model."""
update_counter.get()
return solara.Text(f"Step: {model.steps}")


class _SecureCodeValidator(ast.NodeVisitor):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what did you use as inspiration, if any for this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any source exactly resembling this, but after search a bit I found some open discussions on stackoverflow suggesting the use of ast, after doing a little research over it, I used AI to assemble those ideas into a prototype.

Copy link
Member

@quaquel quaquel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not move all command center stuff into its own seperate module?

A few clarifying questions to start this review.

@Sahil-Chhoker
Copy link
Collaborator Author

Should we not move all command center stuff into its own separate module?

I realized the same after implementing it, but I think the development of console is going smooth, that can replace the command center entirely. We can have an separate file for that.

@Corvince
Copy link
Contributor

I just want to say that I am really impressed with the work done here and in #2683 . Definitely something that has been on my frontend wishlist for a long time. But I am not sure how to proceed from here, is this PR here superseded by the work done in #2683? Or should this here be merged before implementing the changes there? Or is the scope of both features different?

@Sahil-Chhoker
Copy link
Collaborator Author

Thanks @Corvince for your reply!

But I am not sure how to proceed from here, is this PR here superseded by the work done in #2683?

Yes the work done in #2683 will replace the work done by this PR. This PR is here to get the review on the the feature _SecureCodeValidator, because it is going to be reused in the work in #2683. I would really appreciate if you could give some useful insights on that.

"open", # File system access
"globals",
"locals", # Global state manipulation
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of these make sense to me

is the model itself by default available in the namespace?

also, we can refine this based on experiences

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't think I exactly understand what you mean here. Can you add a little more context.

f"Access to system module '{attr}' is not allowed"
)

self.generic_visit(node)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the overhead of this security validation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran some tests, and most of the time, the overhead from the security validator is more than double the execution time of the code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is a lot, it might be an argument to leave out validation at all and just give a very clear warning in the docs about security.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's a lot, I didn't think it to be so performance heavy. But since it could be used for smaller models, I think a warning in the docs should do the job (personal view).

@Corvince
Copy link
Contributor

Yes the work done in #2683 will replace the work done by this PR. This PR is here to get the review on the the feature _SecureCodeValidator, because it is going to be reused in the work in #2683. I would really appreciate if you could give some useful insights on that.

I am no expert in this domain, but I reviewed your code with the help of an ai assistant.

While your code offers some first protection against malicious actors, it is by no means complete. There are various ways to circumvent the protections. So I think its more of an architectural problem of how and where the code is executed. If you run this yourself on your local computer, I see no additional security risk and I don't think we need a code validator.

If the model is hosted some site where the code is executed client-side (e.g. py.cafe, basically the same applies, you can only harm yourself (at most).

This leaves only the possibility of hosting it on a server, where the code is also executed on the server. In principle this is always a bad idea, no matter the amount of protection. Something like this can only work safely by whitelisting allowed commands, not trying to catch malicious attempts.

So in summary I don't think we need the code validator. For server environments it might even give a false impression of security. We could warn not to use the command center for hosted solutions, but since we don't currently have any guidelines for that anyways its a bit pointless. Don't get me wrong, enabling easy hosting of models should be high on our todo list imho, but it should be run client-side, not server-side anyways.

@quaquel
Copy link
Member

quaquel commented Feb 18, 2025

Although I am sympathetic to @Corvince's points, I don't fully agree. One use case is that I am giving a model with a UI to some novice student. She will run the model locally, but might not be intimately familiar with python or even with programming. In such a context, a minimum level of protection of what can be done via the console seems desirable.

@Corvince
Copy link
Contributor

Good point, you are right, I haven't considered the use-case of someone who isn't a model developer, but is playing with a model locally. But I am not sure how much of a risk that is. Its not that easy to cause serious harm. If you are worried about that you shouldn't let users use the computer unsupervised ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Release notes label visualisation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants