Anyone used Clojure as Scripting language? Why not?

Lately I’ve been interested in learning security stuff. The majority of the community from security seems to agree that having a scripting language as a tool is really beneficial for penetration tests and so on. The two main languages that they point to is Python and Bash (is Bash the correct name? I don’t know)

I’d like to raise a discussion, regarding what makes a scripting language a scripting language? Why Python and Bash? Is Clojure viable? If not why? I say that because I get annoyed when looking for infosec learning resources and they always say, learn Bash or Python for scripting… I want to stick with clojure when I have to script stuff, but I want the thoughts of the experts here :slight_smile:

Ok I’ve just found out https://github.com/borkdude/babashka/blob/master/README.md

I’m amazed

4 Likes

Yup, highly recommend babashka, also a shout out to Joker here: https://github.com/candid82/joker

They both make scripting in Clojure viable. There’s also self-hosted ClojureScript as an option, you can use Lumo or Planck. https://github.com/anmonteiro/lumo and https://github.com/planck-repl/planck

4 Likes

Many mean “a scripting language” as in “no compile cycle / quick to hack on”. In this sense the REPL is the ultimate scripting language…

This said, I use Clojure (JVM) for all my scripting, and I ended up writing a library to wrap it: https://github.com/l3nz/cli-matic that you may find useful.

2 Likes

I’ve used lumo with good success. Planck seems nice too but Babashka appears to be quite the challenger in that arena recently.

2 Likes

I’ve been using lumo, but the cold start-up time still hurts (about 2 seconds-ish time). Other than that, using libraries is also a pain and I feel that I have to rely on the Javascript interop more often than usual because of that.

Babashka seems really cool, want to try it because it seems to solve those problems.

1 Like

Ya, babashka and joker solves those issues.

One thing I want to say, with babashka and joker, there are no libraries. You are limited to their included set of namespaces and functions. You can’t depend on additional Clojure libraries or Node libraries, etc.

That said, they’re meant to be used more like bash. When you script with bash, you similarly don’t have access to libraries, but instead you rely on the Unix style of composing programs using Pipes.

This is what you’d do in babashka or joker as well. You might make a call to ls and mkdir, etc. I call this shelling out. On Windows you can shell out as well to say run some powershell commands.

So with both babashka and joker, have a look at the sh function. You will rely on it a lot.

That being said, the number of useful namespaces included in Babashka is pretty impressive, and constantly growing…

2 Likes

I believe you can add pure Clojure libraries: https://github.com/borkdude/babashka#additional-namespaces

1 Like

No you can’t. You can add babashka libraries, and you can do the same with joker, but you can’t add Clojure, Java, or ClojureScript, Node, etc., libraries.

But the biggest need for libraries that you can’t write in babashka is for side effect and IO. Anything where you need to interact with the OS. Where languages like Java and Python generally expose the full set of OS APIs through their own standard library, for now, Joker and Babashka expect you to interact with the OS by shelling out mostly. For certain things their standard library can do it, but for all they are missing shelling out is the way to go. While in Clojure you’d use Java interop instead, and in ClojureScript you’d use JS interop instead.

1 Like

My team’s been using Lumo for about a year. We translated all our shell scripts to it, and couldn’t be happier. We were already using Clojure for full stack apps, so moving our scripts to the same language was the logical next step. I think babashka is also an excellent option nowadays, and would probably prefer it since it doesn’t require Node.js.

1 Like

We’re getting into the weeds here, but unless I’m mistaken, you can use Leiningen or Deps to download a jar file, use Clojure to compute the java classpath, and pass it to babashka. Then your script uses the library as long as sci is able to run it.

Hum, maybe I’m the one that’s mistaken, but I don’t believe that’s possible.

Sci can be configured to contain more Clojure dependencies and as long as they are GraalVM friendly they could be included in the bb binary. But bb itself is not able to do so. Only Clojure libraries that were part of its compilation phase are included.

Sci and BB are related, but not the same thing.

Sci is like a micro-framework for making custom Clojure interpreters in Clojure. Those resulting interpreters can delegate back to any Clojure function, so from that perspective you can make an interpreter using Sci which would support some namespace from most Clojure dependency.

BB is a concrete instance of such resulting interpreter, which supports being compiled to native using GraalVM.

When it comes to sci itself, I don’t know if you can dynamically modify its context as you add/remove more supported Clojure namespaces to it.

When it comes to BB though, I’m pretty sure that’s not possible, mostly because of the GraalVM compilation. The native compiled binary doesn’t have the capacity to compile Java at run-time. On top of that, I don’t think bb currently can reify itself, even say if you were to run it as a standard JIT app.

Have you seen https://github.com/borkdude/babashka/#classpath? I think it’s quite new.

I thought so too, but that’s not the case, actually. Have a look here, you actually have access to the ProcessBuilder API, which gives significantly more flexibility than just shelling out.

I did see it, but I still believe it doesn’t let you depend on Java or Clojure dependencies. The classpath as I understand is for babashka dependencies. So you can write libraries in babashka and have other scripts depend on them, where you tell babashka where to find them by listing their paths on the bb classpath.

Ah true, didn’t know about this. But what I meant by system calls wasn’t to start external processes, but make direct OS syscalls for all syscalls.

I mean, process controls are one kind of OS system call, but there are others, like file management, device management, etc.

I’m not sure if bb exposed all of them through some wrapping higher level interface, or if it has a way to directly use glibc, libcgroup, ntdll.dll, etc.

Well, you can’t actually access syscalls natively from Java, either. You need to go through JNA or similar, via LibC. Graal does have some integration with LLVM, but I don’t know whether would enable what you’re talking about.

Yes, but Java has standard APIs for almost all of them, not sure bb covers them all. Also JNI is a part of Java, so I mean, going through JNI is like saying you need to use ProcessBuilder, in that it is still true that Java exposes a mechanism to do native syscalls.

I don’t know if bb allows you to use JNI or JNA or something similar. I think that actually be a nice feature, if it added support for one of the easy dynamic JNA libs like https://github.com/Chouser/clojure-jna or https://github.com/techascent/tech.jna

For example, if Java didn’t have JNI, you’d need to wait for the runtime itself to add native implementations of each syscall and expose some API for them. Since it has JNI, in theory you can build those native extensions yourself.

I’m just not sure when it comes to this if bb allows to build those native extensions over it yet, or if it already exposes enough of its own APIs to cover most syscalls.

Which is what I meant by, in case it doesn’t cover a syscall, or lets you leverage some native functionality of the OS, you can delegate to another process that does it for you.

Sure, the whole point of it is being a scritpting tool. :slight_smile:

Then we’re on the same page :100: That’s what I meant with:

1 Like