From 1a549e721caf2cf0a7ab156ef784252bdf63027a Mon Sep 17 00:00:00 2001 From: Daniel Petranek Date: Wed, 4 Jun 2025 16:33:07 -0500 Subject: [PATCH 1/5] add policy tracking to tracker --- src/fluree/db/track.cljc | 34 ++++++++++++++++----- src/fluree/db/track/policy.cljc | 36 +++++++++++++++++++++++ test/fluree/db/transact/transact_test.clj | 2 +- 3 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 src/fluree/db/track/policy.cljc diff --git a/src/fluree/db/track.cljc b/src/fluree/db/track.cljc index 280c78f285..b9367c5d1c 100644 --- a/src/fluree/db/track.cljc +++ b/src/fluree/db/track.cljc @@ -1,5 +1,6 @@ (ns fluree.db.track (:require [fluree.db.track.fuel :as fuel] + [fluree.db.track.policy :as policy] [fluree.db.track.time :as time])) #?(:clj (set! *warn-on-reflection* true)) @@ -50,22 +51,41 @@ [tracker max-fuel] (assoc tracker :fuel (fuel/init max-fuel))) +(defn init-policy + [tracker] + (assoc tracker :policy (policy/init))) + (defn init "Creates a new fuel tracker w/ optional fuel limit (0 means unlimited)." - ([] - (init {})) - ([{:keys [max-fuel] :as opts}] - (cond-> {} - (track-time? opts) init-time - (track-fuel? opts) (init-fuel max-fuel)))) + [{:keys [max-fuel] :as opts}] + (cond-> {} + (track-time? opts) init-time + (track-fuel? opts) (init-fuel max-fuel) + (track-policy? opts) init-policy)) (defn track-fuel! [tracker error-ch] (when-let [fuel-tracker (:fuel tracker)] (fuel/track! fuel-tracker error-ch))) +(defn register-policies! + [tracker policy-db] + (when-let [policy-tracker (:policy tracker)] + (policy/register-policies! policy-tracker policy-db))) + +(defn policy-exec! + [tracker policy-id] + (when-let [policy-tracker (:policy tracker)] + (policy/track-exec! policy-tracker policy-id))) + +(defn policy-allow! + [tracker policy-id] + (when-let [policy-tracker (:policy tracker)] + (policy/track-allow! policy-tracker policy-id))) + (defn tally [tracker] (cond-> tracker (contains? tracker :time) (update :time time/tally) - (contains? tracker :fuel) (update :fuel fuel/tally))) + (contains? tracker :fuel) (update :fuel fuel/tally) + (contains? tracker :policy) (update :policy policy/tally))) diff --git a/src/fluree/db/track/policy.cljc b/src/fluree/db/track/policy.cljc new file mode 100644 index 0000000000..f6fbfa24e2 --- /dev/null +++ b/src/fluree/db/track/policy.cljc @@ -0,0 +1,36 @@ +(ns fluree.db.track.policy + (:require [clojure.walk :as walk])) + +(defn register-policies! + [tracker policy-db] + (reset! tracker (reduce (fn [state policy-id] + (assoc state policy-id {:executed 0 :allowed 0})) + {} + (concat (->> policy-db :policy :view :class (vals) (mapv :id)) + (->> policy-db :policy :view :property (vals) (mapv :id)) + (->> policy-db :policy :view :default (mapv :id)) + + (->> policy-db :policy :modify :class (vals) (mapv :id)) + (->> policy-db :policy :modify :property (vals) (mapv :id)) + (->> policy-db :policy :modify :default (mapv :id)))))) + + + +(defn init + "Map of `->{:executed :allowed }`, where `:executed` is the + number of times a policy is executed on a flake and `:allowed` is the number of times + it grants access to a flake." + [] + (atom {})) + +(defn track-exec! + [tracker policy-id] + (swap! tracker update-in [policy-id :executed] inc)) + +(defn track-allow! + [tracker policy-id] + (swap! tracker update-in [policy-id :allowed] inc)) + +(defn tally + [tracker] + @tracker) diff --git a/test/fluree/db/transact/transact_test.clj b/test/fluree/db/transact/transact_test.clj index 999da83bef..cdd45eb1ff 100644 --- a/test/fluree/db/transact/transact_test.clj +++ b/test/fluree/db/transact/transact_test.clj @@ -361,7 +361,7 @@ :id :ex/alice :quux/corge "grault"}]} committed @(fluree/transact! conn txn {:meta true})] - (is (= #{:address :db :fuel :hash :ledger-id :size :status :t :time} + (is (= #{:address :db :fuel :hash :ledger-id :size :status :t :time :policy} (set (keys committed)))))) (testing "Throws on invalid txn" From b336ba1697d6f92341a5e2b57be87bea335ff649 Mon Sep 17 00:00:00 2001 From: Daniel Petranek Date: Wed, 4 Jun 2025 16:35:38 -0500 Subject: [PATCH 2/5] initialize policy tracking for transactions and queries We unfortunately cannot register policies in the tracker while wrapping policies, since a db may come in pre-wrapped by a call to `wrap-policy`. We must instead check the db itself for whatever policies it has been wrapped with and initialize tracking of those. --- src/fluree/db/json_ld/policy/rules.cljc | 34 ++++++++++++------------- src/fluree/db/query/api.cljc | 6 ++--- src/fluree/db/transact.cljc | 22 ++++++++-------- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/fluree/db/json_ld/policy/rules.cljc b/src/fluree/db/json_ld/policy/rules.cljc index aa49d39403..2b775bd5b8 100644 --- a/src/fluree/db/json_ld/policy/rules.cljc +++ b/src/fluree/db/json_ld/policy/rules.cljc @@ -4,6 +4,7 @@ [fluree.db.dbproto :as dbproto] [fluree.db.json-ld.iri :as iri] [fluree.db.json-ld.policy :as policy] + [fluree.db.track :as track] [fluree.db.util.async :refer [ wrapper - (assoc-in [:trace id :executed] (atom 0)) - (assoc-in [:trace id :allowed] (atom 0)))] - (cond - (seq (:on-property policy)) - (add-property-restriction policy db wrapper*) + (cond + (seq (:on-property policy)) + (add-property-restriction policy db wrapper) - (or (:s-targets policy) - (:p-targets policy) - (:o-targets policy)) - (add-default-restriction policy wrapper*) + (or (:s-targets policy) + (:p-targets policy) + (:o-targets policy)) + (add-default-restriction policy wrapper) - (seq (:on-class policy)) - (add-class-restriction policy db wrapper*) + (seq (:on-class policy)) + (add-class-restriction policy db wrapper) - (:default? policy) - (add-default-restriction policy wrapper*) + (:default? policy) + (add-default-restriction policy wrapper) - :else - wrapper*)))) + :else + wrapper))) (defn parse-policies [db tracker error-ch policy-values policy-docs] @@ -224,7 +222,7 @@ (async/pipe ch))))) ;; build policy wrapper attached to db containing parsed policies - (async/reduce (build-wrapper db) {:trace {}} policy-ch))) + (async/reduce (build-wrapper db tracker) {:trace {}} policy-ch))) (defn wrap-policy ([db policy-rules policy-values] diff --git a/src/fluree/db/query/api.cljc b/src/fluree/db/query/api.cljc index 56cf6a944d..20fc1500bd 100644 --- a/src/fluree/db/query/api.cljc +++ b/src/fluree/db/query/api.cljc @@ -76,12 +76,10 @@ returns a result or throws an exception." [ds tracker exec-fn] (go-try + (track/register-policies! tracker ds) (try* (let [result ( (assoc tally :status 200, :result result) - policy-report (assoc :policy policy-report))) + (assoc tally :status 200, :result result)) (catch* e (let [data (-> tracker track/tally diff --git a/src/fluree/db/transact.cljc b/src/fluree/db/transact.cljc index e4034ed1f1..9d73f9c33c 100644 --- a/src/fluree/db/transact.cljc +++ b/src/fluree/db/transact.cljc @@ -82,23 +82,21 @@ parsed-context (:context parsed-opts) identity (:identity parsed-opts)] (if (track/track-txn? parsed-opts) - (let [tracker (track/init parsed-opts) - policy-db (if (policy/policy-enforced-opts? parsed-opts) - ( (assoc tally :status 200, :db staged-db) - policy-report (assoc :policy policy-report))) + (assoc tally :status 200, :db staged-db)) (catch* e - (throw (ex-info (ex-message e) - (let [policy-report (policy.rules/enforcement-report policy-db) - tally (track/tally tracker)] - (cond-> (merge (ex-data e) tally) - policy-report (assoc :policy policy-report))) - e))))) + (throw (ex-info (ex-message e) + (let [tally (track/tally tracker)] + (merge (ex-data e) tally)) + e))))) (let [policy-db (if (policy/policy-enforced-opts? parsed-opts) ( Date: Wed, 4 Jun 2025 16:37:35 -0500 Subject: [PATCH 3/5] use tracker to track policy evaluation isntead of db --- src/fluree/db/json_ld/policy/enforce.cljc | 36 ++++++++++------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/fluree/db/json_ld/policy/enforce.cljc b/src/fluree/db/json_ld/policy/enforce.cljc index 735da41b56..cf83aa4c75 100644 --- a/src/fluree/db/json_ld/policy/enforce.cljc +++ b/src/fluree/db/json_ld/policy/enforce.cljc @@ -3,6 +3,7 @@ [fluree.db.dbproto :as dbproto] [fluree.db.json-ld.iri :as iri] [fluree.db.json-ld.policy :as policy :refer [root]] + [fluree.db.track :as track] [fluree.db.util.async :refer [ db :policy :trace)] - (go-try - (loop [[policy & r] policies] - ;; return first truthy response, else false - (if policy - (let [{exec-counter :executed - allowed-counter :allowed} (get tracer (:id policy)) - - query (when-let [query (:query policy)] - (policy-query db sid query)) - result (if query - (seq ( Date: Wed, 4 Jun 2025 16:38:19 -0500 Subject: [PATCH 4/5] update test expectations These expectations were incorrect and reflected the reuse of the db policy tracer. Modify policies are /not/ evaluated during the execution of a query, and the report that stated they were was erroneous. --- test/fluree/db/policy/target_test.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/fluree/db/policy/target_test.clj b/test/fluree/db/policy/target_test.clj index 64f3eadbd6..c7e9313e58 100644 --- a/test/fluree/db/policy/target_test.clj +++ b/test/fluree/db/policy/target_test.clj @@ -169,8 +169,8 @@ (:fuel txn-result))) (is (= ["a:burt-wish1"] (:result result))) - (is (= {"http://a.co/wishlistCreatePolicy" {:executed 1, :allowed 1}, - "http://a.co/wishlistModifyPolicy" {:executed 2, :allowed 2}, + (is (= {"http://a.co/wishlistCreatePolicy" {:executed 0, :allowed 0}, + "http://a.co/wishlistModifyPolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistViewPolicy" {:executed 1, :allowed 1}, "http://a.co/wishlistItemCreatePolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistItemModifyPolicy" {:executed 0, :allowed 0}, @@ -243,10 +243,10 @@ "a:rank" 1}] (:result result))) (is (= {"http://a.co/wishlistCreatePolicy" {:executed 0, :allowed 0}, - "http://a.co/wishlistModifyPolicy" {:executed 1, :allowed 1}, + "http://a.co/wishlistModifyPolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistViewPolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistItemCreatePolicy" {:executed 0, :allowed 0}, - "http://a.co/wishlistItemModifyPolicy" {:executed 3, :allowed 3}, + "http://a.co/wishlistItemModifyPolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistItemViewPolicy" {:executed 3, :allowed 3}, "http://a.co/availableModifyPolicy" {:executed 0, :allowed 0}} (:policy result))) @@ -306,7 +306,7 @@ "http://a.co/wishlistItemCreatePolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistItemModifyPolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistItemViewPolicy" {:executed 3, :allowed 3}, - "http://a.co/availableModifyPolicy" {:executed 2, :allowed 0}} + "http://a.co/availableModifyPolicy" {:executed 1, :allowed 0}} (:policy result))) (is (= 6 (:fuel result))))))) @@ -334,7 +334,7 @@ "http://a.co/wishlistItemCreatePolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistItemModifyPolicy" {:executed 0, :allowed 0}, "http://a.co/wishlistItemViewPolicy" {:executed 3, :allowed 3}, - "http://a.co/availableModifyPolicy" {:executed 2, :allowed 2}} + "http://a.co/availableModifyPolicy" {:executed 1, :allowed 1}} (:policy result))) (is (= 6 (:fuel result))))))))))) From f083b28cd2ac1edfd0d5502ff0fe76237444fe46 Mon Sep 17 00:00:00 2001 From: Daniel Petranek Date: Wed, 2 Jul 2025 16:24:56 -0500 Subject: [PATCH 5/5] fix linter warnings and clean up --- src/fluree/db/json_ld/policy/rules.cljc | 7 +++---- src/fluree/db/query/api.cljc | 1 - src/fluree/db/track/policy.cljc | 5 +---- src/fluree/db/transact.cljc | 10 ++++------ 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/fluree/db/json_ld/policy/rules.cljc b/src/fluree/db/json_ld/policy/rules.cljc index 2b775bd5b8..2a4c10990e 100644 --- a/src/fluree/db/json_ld/policy/rules.cljc +++ b/src/fluree/db/json_ld/policy/rules.cljc @@ -4,7 +4,6 @@ [fluree.db.dbproto :as dbproto] [fluree.db.json-ld.iri :as iri] [fluree.db.json-ld.policy :as policy] - [fluree.db.track :as track] [fluree.db.util.async :refer [> policy-db :policy :modify :property (vals) (mapv :id)) (->> policy-db :policy :modify :default (mapv :id)))))) - - (defn init "Map of `->{:executed :allowed }`, where `:executed` is the number of times a policy is executed on a flake and `:allowed` is the number of times diff --git a/src/fluree/db/transact.cljc b/src/fluree/db/transact.cljc index 9d73f9c33c..86e574dbb4 100644 --- a/src/fluree/db/transact.cljc +++ b/src/fluree/db/transact.cljc @@ -8,7 +8,6 @@ [fluree.db.json-ld.credential :as credential] [fluree.db.json-ld.iri :as iri] [fluree.db.json-ld.policy :as policy] - [fluree.db.json-ld.policy.rules :as policy.rules] [fluree.db.ledger :as ledger] [fluree.db.nameservice :as nameservice] [fluree.db.storage :as storage] @@ -89,14 +88,13 @@ (track/register-policies! tracker policy-db) (try* (let [staged-db (