From 162d3b47b2be4adcd9fd40ab45a8c395a36b7b28 Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Thu, 5 Jun 2025 10:30:38 -0300 Subject: [PATCH 1/7] Add config to allow same-layer access between different namespaces --- src/clj_depend/analyzers/layer.clj | 18 ++++--- test/clj_depend/analyzers/layer_test.clj | 65 +++++++++++++++++++++++- 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/clj_depend/analyzers/layer.clj b/src/clj_depend/analyzers/layer.clj index cb275de..ea0a6a3 100644 --- a/src/clj_depend/analyzers/layer.clj +++ b/src/clj_depend/analyzers/layer.clj @@ -15,12 +15,18 @@ (defn ^:private violate? [config - {:keys [layer dependency-layer]}] - (and (not= layer dependency-layer) - (and (not (nil? layer)) - (not (nil? dependency-layer))) - (or (dependency-layer-cannot-be-accessed-by-layer? config dependency-layer layer) - (layer-cannot-access-dependency-layer? config layer dependency-layer)))) + {:keys [namespace dependency-namespace layer dependency-layer]}] + (let [same-namespace? (= namespace dependency-namespace) + same-layer? (= layer dependency-layer) + allow-same-layer-access-between-different-namespaces? (get-in config [:layers layer :allow-same-layer-access-between-different-namespaces?] true)] + (cond + same-namespace? false + (and same-layer? (not allow-same-layer-access-between-different-namespaces?)) true + (and (not= layer dependency-layer) + (some? layer) + (some? dependency-layer)) + (or (dependency-layer-cannot-be-accessed-by-layer? config dependency-layer layer) + (layer-cannot-access-dependency-layer? config layer dependency-layer))))) (defn ^:private namespace-in-source-paths? [namespace dependencies-by-namespace] diff --git a/test/clj_depend/analyzers/layer_test.clj b/test/clj_depend/analyzers/layer_test.clj index 6d7ace4..85cc1e9 100644 --- a/test/clj_depend/analyzers/layer_test.clj +++ b/test/clj_depend/analyzers/layer_test.clj @@ -91,4 +91,67 @@ (testing "when a namespace that is not in the source-paths and that matches the defined-by regular expression of a layer that is not allowed to be accessed" (let [violations (analyzers.layer/analyze config 'foo.b.bar {'foo.b.bar #{'foo.a.bar}})] (testing "then no violations should have been returned" - (is (empty? violations)))))))) + (is (empty? violations))))))) + + (testing "Given a configuration with allow-same-layer-access-between-different-namespaces? enabled (default behavior)" + (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*"}}}] + + (testing "when a namespace in the same layer depends on another namespace in the same layer" + (let [violations (analyzers.layer/analyze config + 'my-app.controller.foo + {'my-app.controller.foo #{'my-app.controller.bar}})] + (testing "then no violations should be returned" + (is (= [] + violations))))) + + (testing "when a namespace depends on itself" + (let [violations (analyzers.layer/analyze config + 'my-app.controller.foo + {'my-app.controller.foo #{'my-app.controller.foo}})] + (testing "then no violations should be returned" + (is (= [] + violations))))))) + + (testing "Given a configuration with allow-same-layer-access-between-different-namespaces? disabled" + (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*" + :allow-same-layer-access-between-different-namespaces? false}}}] + + (testing "when a namespace in the same layer depends on another namespace in the same layer" + (let [violations (analyzers.layer/analyze config + 'my-app.controller.foo + {'my-app.controller.foo #{'my-app.controller.bar}})] + (testing "then a violation should be returned" + (is (= [{:namespace 'my-app.controller.foo + :dependency-namespace 'my-app.controller.bar + :layer :controller + :dependency-layer :controller + :message "\"my-app.controller.foo\" should not depend on \"my-app.controller.bar\" (layer \":controller\" on \":controller\")"}] + violations))))) + + (testing "when a namespace depends on itself" + (let [violations (analyzers.layer/analyze config + 'my-app.controller.foo + {'my-app.controller.foo #{'my-app.controller.foo}})] + (testing "then no violations should be returned" + (is (= [] + violations))))))) + + (testing "Given a configuration with allow-same-layer-access-between-different-namespaces? explicitly enabled" + (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*" + :allow-same-layer-access-between-different-namespaces? true}}}] + + (testing "when a namespace in the same layer depends on another namespace in the same layer" + (let [violations (analyzers.layer/analyze config + 'my-app.controller.foo + {'my-app.controller.foo #{'my-app.controller.bar}})] + (testing "then no violations should be returned" + (is (= [] + violations))))) + + (testing "when a namespace depends on itself" + (let [violations (analyzers.layer/analyze config + 'my-app.controller.foo + {'my-app.controller.foo #{'my-app.controller.foo}})] + (testing "then no violations should be returned" + (is (= [] + violations)))))))) From aa3037e1d3a3344d35ff48f5379fbc245e2293ff Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Mon, 16 Jun 2025 10:11:06 -0300 Subject: [PATCH 2/7] change name --- src/clj_depend/analyzers/layer.clj | 4 ++-- test/clj_depend/analyzers/layer_test.clj | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/clj_depend/analyzers/layer.clj b/src/clj_depend/analyzers/layer.clj index ea0a6a3..abc5c62 100644 --- a/src/clj_depend/analyzers/layer.clj +++ b/src/clj_depend/analyzers/layer.clj @@ -18,10 +18,10 @@ {:keys [namespace dependency-namespace layer dependency-layer]}] (let [same-namespace? (= namespace dependency-namespace) same-layer? (= layer dependency-layer) - allow-same-layer-access-between-different-namespaces? (get-in config [:layers layer :allow-same-layer-access-between-different-namespaces?] true)] + access-peer-ns? (get-in config [:layers layer :access-peer-ns?] true)] (cond same-namespace? false - (and same-layer? (not allow-same-layer-access-between-different-namespaces?)) true + (and same-layer? (not access-peer-ns?)) true (and (not= layer dependency-layer) (some? layer) (some? dependency-layer)) diff --git a/test/clj_depend/analyzers/layer_test.clj b/test/clj_depend/analyzers/layer_test.clj index 85cc1e9..323944e 100644 --- a/test/clj_depend/analyzers/layer_test.clj +++ b/test/clj_depend/analyzers/layer_test.clj @@ -93,7 +93,7 @@ (testing "then no violations should have been returned" (is (empty? violations))))))) - (testing "Given a configuration with allow-same-layer-access-between-different-namespaces? enabled (default behavior)" + (testing "Given a configuration with access-peer-ns? enabled (default behavior)" (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*"}}}] (testing "when a namespace in the same layer depends on another namespace in the same layer" @@ -112,9 +112,9 @@ (is (= [] violations))))))) - (testing "Given a configuration with allow-same-layer-access-between-different-namespaces? disabled" + (testing "Given a configuration with access-peer-ns? disabled" (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*" - :allow-same-layer-access-between-different-namespaces? false}}}] + :access-peer-ns? false}}}] (testing "when a namespace in the same layer depends on another namespace in the same layer" (let [violations (analyzers.layer/analyze config @@ -136,9 +136,9 @@ (is (= [] violations))))))) - (testing "Given a configuration with allow-same-layer-access-between-different-namespaces? explicitly enabled" + (testing "Given a configuration with access-peer-ns? explicitly enabled" (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*" - :allow-same-layer-access-between-different-namespaces? true}}}] + :access-peer-ns? true}}}] (testing "when a namespace in the same layer depends on another namespace in the same layer" (let [violations (analyzers.layer/analyze config From f722d342b83609819da7643d24284bae7ba7532d Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Mon, 16 Jun 2025 10:11:11 -0300 Subject: [PATCH 3/7] update docs --- docs/config.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index 50c2bf0..45485d3 100644 --- a/docs/config.md +++ b/docs/config.md @@ -38,12 +38,14 @@ A map where each key is a layer and the value is a map, where: - The layer is defined by a regex using the `:defined-by` key or a set of namespaces using the `:namespaces` key. - The accesses allowed by it declared using the `:accesses-layers` key, or the accesses that are allowed to the layer using the `:accessed-by-layers` key. Since both keys accept a set of layers. - `:only-ns-in-source-paths` optional, only considers namespaces in source paths as part of a layer. Available values: `true`, `false` with default value of `false`. +- `:access-peer-ns?` optional, controls whether namespaces within the same layer can access each other. Available values: `true`, `false` with default value of `true`. When `false`, namespaces in the same layer cannot depend on other namespaces in the same layer (except themselves). Config example: ```clojure {,,, :layers {:controller {:defined-by ".*\\.controller\\..*" - :accesses-layers #{:logic :model}} + :accesses-layers #{:logic :model} + :access-peer-ns? false} :logic {:defined-by ".*\\.logic\\..*" :accesses-layers #{:model}} :model {:defined-by ".*\\.model\\..*" From 079dcdc1de37b6630bfc40d2936bef852f02d3c2 Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Mon, 16 Jun 2025 10:12:59 -0300 Subject: [PATCH 4/7] update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccb7c25..0ee8fae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # CHANGELOG ## Unreleased +* [#21](https://github.com/fabiodomingues/clj-depend/issues/22): Restrict namespaces to access others namespaces on the same layer ## 0.11.1 (2025-05-26) -* [#61](https://github.com/fabiodomingues/clj-depend/issues/61): Fix reflection warnings. +* [#61](https://github.com/fabiodomingues/clj-depend/issues/61): Fix reflection warnings. ## 0.11.0 (2024-04-19) * [#56](https://github.com/fabiodomingues/clj-depend/issues/56): Added the `:only-ns-in-source-paths` attribute for when it is necessary to consider only namespaces in source paths as part of a layer. From 3d84646d810c2dd4f0285dc4753be9ed60071fae Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Mon, 16 Jun 2025 10:20:04 -0300 Subject: [PATCH 5/7] Update CHANGELOG.md Co-authored-by: Fabio Domingues --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ee8fae..271f0ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # CHANGELOG ## Unreleased -* [#21](https://github.com/fabiodomingues/clj-depend/issues/22): Restrict namespaces to access others namespaces on the same layer +* [#22](https://github.com/fabiodomingues/clj-depend/issues/22): Restrict namespaces to access others namespaces on the same layer ## 0.11.1 (2025-05-26) * [#61](https://github.com/fabiodomingues/clj-depend/issues/61): Fix reflection warnings. From 576cda44018e235364b2b0a9747507081c52d941 Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Mon, 16 Jun 2025 10:21:42 -0300 Subject: [PATCH 6/7] remove question mark from the config --- docs/config.md | 4 ++-- src/clj_depend/analyzers/layer.clj | 2 +- test/clj_depend/analyzers/layer_test.clj | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/config.md b/docs/config.md index 45485d3..ec70415 100644 --- a/docs/config.md +++ b/docs/config.md @@ -38,14 +38,14 @@ A map where each key is a layer and the value is a map, where: - The layer is defined by a regex using the `:defined-by` key or a set of namespaces using the `:namespaces` key. - The accesses allowed by it declared using the `:accesses-layers` key, or the accesses that are allowed to the layer using the `:accessed-by-layers` key. Since both keys accept a set of layers. - `:only-ns-in-source-paths` optional, only considers namespaces in source paths as part of a layer. Available values: `true`, `false` with default value of `false`. -- `:access-peer-ns?` optional, controls whether namespaces within the same layer can access each other. Available values: `true`, `false` with default value of `true`. When `false`, namespaces in the same layer cannot depend on other namespaces in the same layer (except themselves). +- `:access-peer-ns` optional, controls whether namespaces within the same layer can access each other. Available values: `true`, `false` with default value of `true`. When `false`, namespaces in the same layer cannot depend on other namespaces in the same layer (except themselves). Config example: ```clojure {,,, :layers {:controller {:defined-by ".*\\.controller\\..*" :accesses-layers #{:logic :model} - :access-peer-ns? false} + :access-peer-ns false} :logic {:defined-by ".*\\.logic\\..*" :accesses-layers #{:model}} :model {:defined-by ".*\\.model\\..*" diff --git a/src/clj_depend/analyzers/layer.clj b/src/clj_depend/analyzers/layer.clj index abc5c62..9b31da4 100644 --- a/src/clj_depend/analyzers/layer.clj +++ b/src/clj_depend/analyzers/layer.clj @@ -18,7 +18,7 @@ {:keys [namespace dependency-namespace layer dependency-layer]}] (let [same-namespace? (= namespace dependency-namespace) same-layer? (= layer dependency-layer) - access-peer-ns? (get-in config [:layers layer :access-peer-ns?] true)] + access-peer-ns? (get-in config [:layers layer :access-peer-ns] true)] (cond same-namespace? false (and same-layer? (not access-peer-ns?)) true diff --git a/test/clj_depend/analyzers/layer_test.clj b/test/clj_depend/analyzers/layer_test.clj index 323944e..9262110 100644 --- a/test/clj_depend/analyzers/layer_test.clj +++ b/test/clj_depend/analyzers/layer_test.clj @@ -114,7 +114,7 @@ (testing "Given a configuration with access-peer-ns? disabled" (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*" - :access-peer-ns? false}}}] + :access-peer-ns false}}}] (testing "when a namespace in the same layer depends on another namespace in the same layer" (let [violations (analyzers.layer/analyze config @@ -138,7 +138,7 @@ (testing "Given a configuration with access-peer-ns? explicitly enabled" (let [config {:layers {:controller {:defined-by ".*\\.controller\\..*" - :access-peer-ns? true}}}] + :access-peer-ns true}}}] (testing "when a namespace in the same layer depends on another namespace in the same layer" (let [violations (analyzers.layer/analyze config From 0180cf712165f7d43b7fbcf293c37f13b374b461 Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Mon, 16 Jun 2025 10:22:50 -0300 Subject: [PATCH 7/7] remove part of the new config description --- docs/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index ec70415..fb57f01 100644 --- a/docs/config.md +++ b/docs/config.md @@ -38,7 +38,7 @@ A map where each key is a layer and the value is a map, where: - The layer is defined by a regex using the `:defined-by` key or a set of namespaces using the `:namespaces` key. - The accesses allowed by it declared using the `:accesses-layers` key, or the accesses that are allowed to the layer using the `:accessed-by-layers` key. Since both keys accept a set of layers. - `:only-ns-in-source-paths` optional, only considers namespaces in source paths as part of a layer. Available values: `true`, `false` with default value of `false`. -- `:access-peer-ns` optional, controls whether namespaces within the same layer can access each other. Available values: `true`, `false` with default value of `true`. When `false`, namespaces in the same layer cannot depend on other namespaces in the same layer (except themselves). +- `:access-peer-ns` optional, controls whether namespaces within the same layer can access each other. Available values: `true`, `false` with default value of `true`. When `false`, namespaces in the same layer cannot depend on other namespaces in the same layer. Config example: ```clojure