diff --git a/backend/src/app/rpc/commands/files_branch.clj b/backend/src/app/rpc/commands/files_branch.clj index db946f09c0..9c26a5faf5 100644 --- a/backend/src/app/rpc/commands/files_branch.clj +++ b/backend/src/app/rpc/commands/files_branch.clj @@ -129,6 +129,21 @@ :actual depth)) changes)) +(def ^:private schema:get-branching-limits + [:map {:title "get-branching-limits"}]) + +(sv/defmethod ::get-branching-limits + "The size limits this instance refuses beyond, so the UI can publish them + before a user meets one. Read from config on every call: the limits have + exactly one home, and a page that states them must not keep its own copy." + {::doc/added "2.16" + ::sm/params schema:get-branching-limits} + [_cfg _params] + (check-branching-enabled!) + {:max-shapes (branching-limit :branching-max-shapes 50000) + :max-pages (branching-limit :branching-max-pages 500) + :max-oplog-changes (branching-limit :branching-max-oplog-changes 100000)}) + ;; --- Audit: what an operation cost and how it ended ;; ;; The generic RPC audit event records who called what with which params. diff --git a/backend/test/backend_tests/rpc_file_branch_test.clj b/backend/test/backend_tests/rpc_file_branch_test.clj index 311bf418c4..2c34bf7961 100644 --- a/backend/test/backend_tests/rpc_file_branch_test.clj +++ b/backend/test/backend_tests/rpc_file_branch_test.clj @@ -1200,6 +1200,28 @@ (t/is (= 1 (:actual data))) (t/is (str/includes? (:hint data) "materialise"))))))))) +(t/deftest published-limits-are-the-ones-the-gates-enforce + (let [profile (th/create-profile* 1 {:is-active true}) + limits (fn [] (th/command! {::th/type :get-branching-limits + ::rpc/profile-id (:id profile)}))] + + (t/testing "the defaults are published" + (with-redefs [cf/flags (conj cf/flags :branching)] + (let [out (limits)] + (t/is (nil? (:error out))) + (t/is (= {:max-shapes 50000 :max-pages 500 :max-oplog-changes 100000} + (:result out)))))) + + (t/testing "and they are read from config, not from the page" + (with-redefs [cf/flags (conj cf/flags :branching) + cf/get (th/config-get-mock {:branching-max-shapes 7})] + (t/is (= 7 (-> (limits) :result :max-shapes))))) + + (t/testing "the query is gated like every other branching command" + (let [data (ex-data (:error (limits)))] + (t/is (= :restriction (:type data))) + (t/is (= :branching-disabled (:code data))))))) + (t/deftest branch-operations-record-duration-and-outcome (with-redefs [cf/flags (conj cf/flags :branching)] (let [profile (th/create-profile* 1 {:is-active true})