Fork me on GitHub
#babashka
<
2023-05-23
>
emccue00:05:23

Idea for a self contained bb script - jvm jvm install 19 Same idea as nvm for node https://github.com/nvm-sh/nvm#intro

Bob B01:05:19

sdkman is maybe the goto program for this, and it's messy on windows, just like nvm

jeroenvandijk06:05:20

Congratulations! Well deserved!

joakimen06:05:04

Awesome! Will the talks be available online?

mkvlr06:05:52

Yes, unless the speaker doesnโ€™t want that.

๐Ÿ‘ 2
quaeledyn06:05:09

Hello everyone, I have been working on a script doing some DB migrations, and it's been going quite well so far, but I have hit a wall with one requirement, and I'm hoping that someone could take the time to give me a few pointers. I have a SSH public key string, and I need to calculate the MD5 and SHA256 fingerprints. I am able to do it in Bash no problem, but not in Babashka (I've never been very comfortable with for interacting with the shell in Babashka or Clojure), but really that's just a last resort when I can't do what I need natively or using Java interrop. Here's how I can do what I need in Bash for the SHA256 fingerprint: Given a SSH public key string,

KEY="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDieM/AoMdcDtggIQmjZTzr7UWSbuiKS0Miv9/LUWqAcj+UIrb+hhlT1UnQLpmj5LFVOgO8frGSl/f9Ybjo5j9BmR1NgEVI0O9IBsKaP54MYBUbNUVTZToRh6Dtw0rDmNDSRFQQGbNR+15n34GAI7yQeLHjk8xFYhy7a9qKxNuG+7RXG/7L3EeGzXgzx3b11i6V3XwR6z9cWysfb/MLbplawSHeVVgY2XBeAYzngr2/yfrDHWO9X+EPraHqd2WQ1Yq8+v9uBawTZML3aiPVbPHXOWjCauQSgdcAAmPjyfloo3Jgw3vmPaAEtk3fDA90DyewMWyf9jhQ32pVc/eZkbN5 "
Get the fingerprint information from ssh-keygen,
ssh-keygen -lf - <<<"${KEY}"
2048 SHA256:DCMPcoQpscLxl0s/YrknEGoIy2Q+1Zk0AUZJhPltzzM  (RSA)
From which I need the Base64 expression,
echo "$(ssh-keygen -lf - <<<${KEY}|grep -oP '(?<=SHA256:)[^ ]*')="
DCMPcoQpscLxl0s/YrknEGoIy2Q+1Zk0AUZJhPltzzM=
And finally the SHA256 fingerprint in the hexadecimal format I require,
echo "$(ssh-keygen -lf - <<<${KEY}|grep -oP '(?<=SHA256:)[^ ]*')="|base64 -d|od -A n -t x1 -v | tr -d ' \n'
0c230f728429b1c2f1974b3f62b927106a08cb643ed5993401464984f96dcf33
As a sanity check, I can reverse the final value with,
echo "0c230f728429b1c2f1974b3f62b927106a08cb643ed5993401464984f96dcf33"|xxd -r -p|base64
DCMPcoQpscLxl0s/YrknEGoIy2Q+1Zk0AUZJhPltzzM=
Ideally I'd love to just import (what I believe to be) the required Java libraries java.security.KeyPair, java.security.PublicKey, java.security.interfaces.DSAPublicKey, java.security.interfaces.ECPublicKey, java.security.interfaces.RSAPublicKey, and perhaps java.security.NoSuchAlgorithmException, but I don't know how I can do that without going down an enormous rabbit hole. Would someone be kind enough to show me how I could accomplish what I need from my Babashka script? There's not too much data, so performance is not an issue. I just need something that works, and I'm hopeful that I won't have to resort to my fallback fallback position of writing a Bash script and calling it from Babashka! ๐Ÿ˜…

pesterhazy07:05:08

Why not translate the shell command to babashka.process/shell one to one? You can always do it more cleanly with pure java later

pesterhazy07:05:19

I wouldn't bother with pipes. Just pass in data to each subcommand

pesterhazy07:05:05

Then you can optionally translate each one into pure clojure/java

pesterhazy07:05:16

Pro tip: write a unit test so you can refactor with confidence. A shell script is a program like any other, so software engineering practices apply

borkdude07:05:03

sha256 can be done in bb as follows: https://gist.github.com/kubek2k/8446062

borkdude07:05:59

to make this even easier, you can use the clj-commons digest lib: https://github.com/clj-commons/digest/blob/master/test/digest_test.clj

quaeledyn09:05:47

Thanks to you both. I did actually try various approaches in Babashka for encoding, but I was not able to generate the required output. @U06F82LES I'll have another go with shell as you suggest. I've been spoiled by shell pipes and threading macros over the years, but yes, there's no harm in doing things piecemeal, especially as performance is not a concern.

borkdude09:05:06

Maybe you can post the code you have tried with shelling out. It should not be hard, but a common confusion is that you can copy paste bash code in there

quaeledyn09:05:43

I was trying things out in a bb repl which is closed now. All the shell code I was working with (assuming I work with shell) is in the fourth code block, before the sanity check. If you have a Linux shell you should be able to just copy and past that example along with the declaration of the KEY variable the test it out. As awesome as Clojure is, the capabilities of the humble Unix shell is a testament to the genius of its inventors. In Bash, a single line does what I need. If only we could use all the little Unix utilities as libraries in our code instead of all the awkwardness we have to wrestle with!

borkdude09:05:33

I guess I misinterpreted "I've never been very comfortable with for interacting with the shell in Babashka" I interpreted shell as "shelling out", the REPL is never called "the shell" in the context of Clojure, that is blasphemy ;)

pesterhazy13:05:39

Maybe we do need a rough bash2bb translator

pesterhazy13:05:54

How hard can it be? :-)

pesterhazy13:05:06

Does anyone know a parser for bash that understands its quirky quoting rules? That would be half the battle

borkdude13:05:00

you could look at the project https://explainshell.com/

pesterhazy13:05:38

Or maybe this. Json AST sounds prefect https://github.com/vorpaljs/bash-parser

borkdude13:05:07

yeah you could even use #C029PTWD3HR for it ;)

quaeledyn20:05:39

Heh heh, I'm no blasphemer. I was using babashka.process/shell from the repl. ๐Ÿ˜

๐Ÿ˜† 2
quaeledyn01:05:52

Solved by eliminating my miscomprehension of what the Java/Clojure/Babashka shell is actually doing. None of them are actually running a shell! I can get the kind of solution I was after by only using babashka.process/shell to call bash and pass it the command sequence I want.

(defn bash [command]
  (shell {:out :string :err :string} "bash" "-c" command))

(defn ssh-key-sha256 [key-text]
  (-> (bash (str "echo \"$(ssh-keygen -lf - <<<'" key-text "'"
                 "|grep -oP '(?<=SHA256:)[^ ]*')=\""
                 "|base64 -d|od -A n -t x1 -v | tr -d ' \n'")) :out))
Using the key I provided for my example (`(def key-text "ssh-rsa AAA...)`),
clj๊ž‰user๊ž‰> (ssh-key-sha256 key-text)
"0c230f728429b1c2f1974b3f62b927106a08cb643ed5993401464984f96dcf33"
clj๊ž‰user๊ž‰> 
When worlds collide!

quaeledyn01:05:52

Note for my purposes I know that all the key strings are valid, so it's safe for me to just grab the output without worrying about :err.

๐Ÿ‘ 2
borkdude07:05:48

I wonder if I should deprecate the name shell and change it to something else, since shell seems to confuse people, although the docstring clearly says it does not start a new shell, but it stands for "shelling out" ;)

quaeledyn07:05:24

Didn't notice the docstring, but for Linux folks at least, "shell" has definite connotations. exec would be okay, but it's already taken. Why not cmd? Or run maybe?

quaeledyn07:05:56

As they say, naming things is hard ๐Ÿ˜

borkdude07:05:39

yeah, to make things worse, clojure 1.12 now introduces a clojure.java.process/exec function which does something else ;)

borkdude07:05:45

I also though about run

borkdude07:05:23

but run already does something else in babashka.tasks where it is available without referring it, like shell

borkdude07:05:29

it runs a task

borkdude07:05:47

so this would also be confusing over there

quaeledyn07:05:40

You could change shell to be something more like the bash function above, where it passes a string to the user's default shell (e.g. bash). That would be very useful for Babashka scripting I think, and a pretty comfortable fallback for people used to shell programming. As you can see from my example, using the bash function is clean, and allows me to tap into the power of shell programming without having to leave Babashka.

borkdude07:05:14

I don't like this because babashka promotes writing OS-agnostic scripts, not tied to bash

quaeledyn07:05:53

I understand, but it's unavoidable with pretty much all the process facilities, no?

borkdude07:05:56

no, I hardly ever shell out to bash

borkdude07:05:24

I think in all of my projects I have maybe only 1 script where I shell out to sed and I could even rewrite that to pure clojure

quaeledyn07:05:33

Ideally Babashka would be able to look at the external commands and inform the user if they aren't available on the current system, a la "missing dependencies"

quaeledyn07:05:56

Babashka is meant to be an alternative to things like Bash scripts though, right? It's a bigger ask for users if they have to make significant compromises if they choose it over what they are accustomed to.

borkdude07:05:11

bb scripts replace bash scripts, but it does not try to imitate bash syntax, never has. just learn clojure and if you must, use bash as a fallback, but be explicit about it:

(shell "bash -c 'rm -rf /tmp/*')

quaeledyn07:05:48

All those little programs (in Unix-like OS's at least) are kind of like the "standard library" of shell programming, so the goal should be excellent interrop IMHO.

borkdude07:05:38

The combination if babashka.fs, babashka.process, babashka.http-client and babashka.json should get you a long way. bb doesn't try to imitate posix utilities to the letter

borkdude07:05:40

"(in Unix-like OS's at least)" - this is one of the points bb departs from: it does not assume you are on a specific OS, all things are OS-agnostic like in Java

quaeledyn07:05:30

I only turned to Bash when I couldn't find an economical alternative in Babashka, and that's fine with me. Clojure is wonderful and I love using it, but I don't want to jump through hoops when an external command, or sequence of commands helps me get things done.

borkdude07:05:07

well, you don't have to. just run (shell "bash -c 'whatever you want'")

quaeledyn07:05:17

That said, I'm completely happy with my solution for now, and it doesn't require any changes to Babashka at all.

quaeledyn07:05:41

Well, there might be a situation where someone writes something targeting a Linux system (so call out to Bash), and someone else comes along who wants to add support for another OS. If there were something along the lines of #clj and #cljs, but for different execution environments, that might be something useful.

quaeledyn08:05:59

Apart from the ambiguous name shell, I should think you needn't really make any changes. If such interoperability or integration is really useful, someone will come along and contribute something that fits the bill. I suspect that it's a fairly decent rabbit hole that demands some real thought, and not something that can be solved with a little tweak here and there.

quaeledyn08:05:43

I can't think of any [non shell-] programming language that seamlessly integrates POSIX, so it's either a killer feature that people have overlooked for decades, or something that's ultimately not worth it. What we have is probably good enough!

quaeledyn08:05:22

Really appreciate you taking the time to discuss, btw.

borkdude08:05:32

Thanks you too.

Crispin12:05:13

can only load from a file atm, and requires the pair... but might be useful. Can generate keys if thats part of what you need.

quaeledyn07:05:26

Nice! I actually looked into bbsh earlier on. I'll definitely look into it again, see if I can use it to get the plain hex dump of the SHA256 fingerprint.

Crispin07:05:53

I released a new version 0.4.0 and bumped the version of JSch (the underlying java lib) and this new version can load keys directly from vars so I exposed that in pod.epiccastle.bbssh.key-pair/load-bytes

quaeledyn07:05:28

Yes, I read that commit ๐Ÿ˜ The reason I need something so strange is that we are migrating our Git repositories to GitLab and the available migration tool from the GitLab folks only use facilities available through the APIs. One of the non-migrated items is users' SSH keys, and the SHA256 fingerprint of the public key is stored as a binary value in the GitLab database. The MD5 fingerprint is stored as plain text, so at least that bit's easy! It's awesome that Babashka has a way to work with SSH protocols and keys though bbssh and JSch. Lovely work!!

๐Ÿ‘ 2
emilaasa07:05:47

Love the babaska.fs lib, really smooth to use! What do you think about extending the fs api with a file-owner fn that returns the file's owner?

emilaasa08:05:11

Currently I use java.nio.file.Files/getOwner and it works, but since it takes an array of LinkOption and such you have to get a little bit ugly to make it work. With some internal fs fn usage you can get it down to:

(Files/getOwner (fs/path "/home/someguy/")
                (#'fs/->link-opts true))

emilaasa08:05:23

Ah yeah I got the idea from him ๐Ÿ˜„

borkdude08:05:34

Feel free to post an issue + PR

emilaasa08:05:45

Thanks! Will do

emilaasa08:05:13

Btw is it more annoying that I ask here first or that you get an issue asking the same thing?

borkdude08:05:29

No, I like it since sometimes an issue isn't necessary

jumar08:05:39

Sorry, I'm a bit late to the party . Thanks @U6T7M9DBR for taking the lead! O:-)

emilaasa11:05:47

I gave up on the additional tests, but opened another PR that updates the CHANGELOG.md to use owner instead, other than that I feel done unless you want more changes ๐Ÿ™‚

borkdude12:05:44

I'm on very flaky internet right now, on my way to London by train

borkdude12:05:02

and I might have already fixed that by a commit that was in-flight during a broken connection ๐Ÿ˜‚

borkdude13:05:12

released as 0.4.19

emilaasa13:05:34

It was a pleasure working with you borkdude

๐Ÿ’ฏ 2
emilaasa13:05:35

๐Ÿ’ฏ borkdude

lambduhhh15:05:13

yoooo babashka conf!! ๐Ÿ‘€ Turns out Iโ€™ll be over in EU in poland just the week before for Lambda Days and I was thinking of making a Berlin pit stop otw are there any other people coming from out of town? where are you staying?

metal 4
borkdude15:05:57

yooooo! feel free to discuss here or in #C04VAK5U86L :)

2
borkdude15:05:05

would be cool if you could make it!

Mario Giampietri21:05:23

What are your favourite http clients in Babashka land - an why? ๐Ÿ™‚

borkdude21:05:33

The babashka.http-client lib is supposed to be the default http client which covers all the use cases that previously were offered by a combination of babashka.curl + httpkit.client (but both are still available in bb)

borkdude21:05:29

Some other clients are compatible with bb as a dependency

Mario Giampietri21:05:10

that was quick ๐Ÿ™‚ thanks