Fork me on GitHub
#clojure
<
2021-02-12
>
coby00:02:44

Is there a widely-used, well-documented library for implementing role-based access control in Clojure? I imagine it's often pretty domain-specific and mostly just simple checks on maps/sets etc., but wanted to see if there was something nice out there.

lukasz14:02:35

@UH85MNSKE I'm one the look out for one too - sorry if not helpful, but let's compare notes if either of us finds something 😉

1
coby16:02:14

tbh I wasn't gonna look that hard, seems pretty easy to roll your own. But I saved your message to come back to just in case. 🙂

Casey12:02:52

Did ya'll find anything suitable here? I've found • permissions https://github.com/tuhlmann/permissions • and zakon https://github.com/fmnoise/zakon

lukasz15:02:46

Permissions looks really cool, interestingly a part of our system already does something like that so (assuming it works as expected) migration would be almost seamless. Thanks for sharing @U70QFSCG2!

Casey15:02:24

permissions is cljc, so would work in cljs, unlike zakon. though I don't see why zakon couldn't work in cljs.

Casey15:02:40

permissions can be initialized with just data, whereas zakon has a macro. though with that macro, zakon lets you supply arbitrary functions as authorizers. both rely on global state which is less than ideal if you have dynamic roles/permissions stored in a db

lukasz15:02:45

Oh, that wasn't obvious - in what way Permissions depends on global state?

Casey16:02:10

that init-roles bit mutates a global atom

Casey16:02:33

then notice how none of the has-permission? calls pass the available roles, as they are read from the atom

lukasz16:02:47

Oh, that's... not ideal

lukasz16:02:54

Should be easy to fix though and refactor the code to allow for passing a role map rather than sourcing it from a global atom

datran05:02:31

I'm trying to attach some metadata to a defed fn inside of a macro, but nothing quite seems to stick:

(let [doc "docs"
        meta {:arglists '([test])}]
    `(def ^~meta foo ~doc (fn [x] 1)))
;; => error: Metadata must be Symbol,Keyword,String or Map

datran05:02:22

But when I check, it says it's a map:

(let [meta {:arglists '([test])}]
    `[~(type meta)])
;;=>  [clojure.lang.PersistentArrayMap]

datran05:02:18

Am I just barking up the wrong tree here?

phronmophobic05:02:55

try: ~(with-meta 'foo meta)

phronmophobic05:02:18

I think it's trying to apply the metadata '~ to the symbol meta in your example

phronmophobic05:02:22

actually. it's probably trying to add the metadata ~meta to the symbol foo

phronmophobic05:02:23

> (defmacro test-fn-meta []
  `(def ~(with-meta 'foo {:a 1}) (fn [])))
> (test-fn-meta)
#'my.ns/foo
> (meta #'foo)
{:a 1,
 :line 929,
 :column 18,
 :file "*cider-repl examples/browser:localhost:49996(clj)*",
 :name foo,
}

datran05:02:35

ah, that makes perfect sense. I'm adding the meta to the var, I had tried wrapping the fn before but that obviously doesn't do what I'm aiming for

phronmophobic05:02:20

as an improvement, defn allows an optional map between the name and params that will be added to the metadata:

(defmacro test-fn-meta []
  `(defn ~'foo ~{:a 1} [x] 1))

datran05:02:09

I had tried that, but in my (brief) test I couldn't override the :arglists, it just used the ones from the actual arg vector

datran05:02:32

let me try with this method, though

datran05:02:13

ah, that works!

bananadance 2
datran06:02:14

ok, I got everything working the way I wanted in clj, but when I tried using it in cljs I found a weird behavior with arglists:

(defn bar {:b 2 :arglists '([damned lies])}
  [x] 1)
(meta #'bar)
;;=> {:ns user, :name bar, :file "user/main.cljs", :end-column 10, :source "bar", :column 1, :line 1, :b 2, :end-line 1, :arglists ([damned lies]), :doc nil, :test nil}
;; this is just like clj^

(defn foo {:a 1 :arglists '([lies])}
  ([x] 1)
  ([x y] 2))
(meta #'foo)
;;=> {:ns user, :name foo, :file "user/main.cljs", :end-column 10, :top-fn {:variadic? false, :fixed-arity 2, :max-fixed-arity 2, :method-params [[x] [x y]], :arglists ([x] [x y]), :arglists-meta (nil nil)}, :source "foo", :column 1, :line 1, :end-line 1, :arglists ([x] [x y]), :doc "docs", :test nil, :a 1}

phronmophobic06:02:04

according the docs, cljs has no reified vars, https://www.clojurescript.org/about/differences#_vars_and_the_global_environment the truth is a little bit trickier as there's been a few improvements that address some of the use cases of reified vars. overall, I've found it's worth avoiding vars in cljs if possible. That may change as they keep improving cljs

datran06:02:57

It looks like multi-arity functions will override the :arglists supplied in the metadata with the ones it figures out on its own

datran06:02:35

I'm up way too late, so I'll check in later, but this seems weird to me

p-himik15:02:33

There's no function to quickly check if a collection has duplicates, is there?

lukasz15:02:51

frequencies?

rutledgepaulv15:02:04

(apply distinct? [1 2 3 4 2])
=> false
(apply distinct? [1 2 3 4])
=> true

rutledgepaulv15:02:53

would prefer this over frequencies since it will short circuit on first repeat

p-himik15:02:40

That's the one, thanks! I used borkdude's re-find but I didn't guess to try vararg as opposed to a single collection.

jjttjj19:02:32

How can I split a string by (char 1)

;;; works, is there a better way?
(vec (.split (str "asdf" (char 1) "asdf") (str (char 1))))

;;; these don't work
(str/split (str "asdf" (char 1) "asdf")
  #"\u00001"
  ;;#"[\\1]"
  ;;#"\\x01"
  )

dpsutton19:02:50

(let [s "asdf"] (str/split s (re-pattern (str (char 1)))))

dpsutton19:02:06

if i understand what you're after

andy.fingerhut19:02:15

I get the same result for these two subexpressions. You do not?

user=> (= (vec (.split s1 (str (char 1)))) (str/split s1 #"\u0001"))
true

andy.fingerhut19:02:40

And in fact, for your first and third options that you say didn't work for you:

user=> (require '[clojure.string :as str])
nil
user=> (def s1 (str "asdf" (char 1) "asdf"))
user=> (def a1 (vec (.split s1 (str (char 1)))))
#'user/a1
user=> (def a2 (str/split s1 #"\u0001"))
#'user/a2
user=> (def a3 (str/split s1 #"\x01"))
#'user/a3
user=> (= a1 a2 a3)
true

jjttjj19:02:51

ohh I had an extra 0 in the \u0001 str, that one works for me

andy.fingerhut19:02:14

(Note that inside a Clojure string surrounded by "", you need to type \\ to get a single backslash. Inside of #"" you only need to type one backslash to get one backslash in the regex string -- the Clojure reader parses regex strings slightly differently than regular strings, as a convenience to avoid having to type so many double backslashes)

jjttjj19:02:17

Oh yeah \x01 does work with the single backslash

andy.fingerhut19:02:20

but that can lead to more confusion if you weren't aware of it (and I just double-checked -- this fact is documented in official docs here if you search for regex: https://clojure.org/reference/reader)

dpsutton20:02:34

if you have a function that will end up reifying a java.util.Comparator, do you ask the caller to supply a function satisfying the <0,0,>0 contract that a comparator expects and reify it inside the function or do you have the caller just pass you a java.util.Comparator and not worry about it since its clear at the call site that you have that contract?

dpsutton20:02:01

i guess, do you make everyone go through the ceremony of reify'ing or take a function and do the reify in one spot for conveinece to the caller

hiredman21:02:02

functions are Comparators

😮 1
hiredman21:02:26

user=> (instance? java.util.Comparator (fn []))
true
user=>

dpsutton21:02:06

oh get out of town. awesome

danielglauser22:02:08

What Java version do folks recommend or are using for prod? We're looking to upgrade from Java 8 but aren't sure how high is safe to go. Obviously we'll test things out well before we ship, just looking for a recommendation on a target.

R.A. Porter22:02:44

My feeling on Java versions is the same for Clojure projects as it is for Java projects: if you want to play with the non-LTS releases, that’s great; if it’s for production code, stick with the LTS Javas: 11, 17, 23… Not everyone feels the same way, of course. If you’re in the Java space, you might want to play with some of the features but in Clojure dev, I think it’s even less compelling as it’s not like there are significant VM changes occurring.

1
seancorfield22:02:17

I agree. Even though we are using Adopt OpenJDK versions, rather than Oracle's versions, we feel more comfortable with 11 in production and plan to move to 17 at some point. In dev we've been testing against 11, 14, and I'm currently using 15 -- but I can easily run tests against multiple versions just by using an env var (I have four or five different JDKs installed locally).

2
jjttjj23:02:40

Out of curiosity did you run into any issues with 14 or 15?

jjttjj23:02:59

as in did they not "just work"

seancorfield23:02:21

I don't recall hitting any problems when I moved up to JDK 14, except for some minor changes in locale-specific number formatting (which I think were bug fixes -- but they broke a couple of our tests).

seancorfield23:02:51

But locale-specific number formatting has changed a little across several recent JDK versions so that wasn't entirely surprising.

seancorfield23:02:21

The big jump was from 8 to 11 (because of all the changes in 9). Since then it's been pretty smooth sailing.

jjttjj23:02:49

Yeah same here basically (on much smaller codebases)

alexmiller23:02:17

Java 10 or 11 introduced some important changes if you are running in a container (making JVM pay attention to container settings)

alexmiller23:02:34

so if you're doing that, it's almost definitely worth upgrading from 8 to 11

alexmiller23:02:02

as of this year, the clojure community has shifted from majority 8 to 11

seancorfield23:02:13

We still have to maintain JDK 8 compatibility in most of our code because we have a legacy app that we're still slowly rewriting to Clojure and it won't run on JDK 9+ (it's a mix of Clojure and... other stuff... 🙂 ).

alexmiller23:02:51

officially, we test and recommend Clojure only on LTS Java releases. unofficially, I test it with each release and am not aware of any issues on recent versions

1
emccue03:02:52

AFAIK the java team considers each release to be a real release

emccue03:02:52

you can pretty safely just upgrade as soon as new releases are made

emccue03:02:37

its only if you are on a platform that dictates your java version or you plan on paying for paid support that what companies consider LTS in java starts to matter

didibus23:02:43

What's the simplest way to get edn/read-string to throw or some other way to validate if the EDN file contains a valid data-structure but atfer it has junk?

didibus23:02:31

config.edn:

{:a 1
 :b 2}
 :c 3}
So that: (edn/read-string (slurp "config.edn")) ;; ERROR