git_checks/
reject_symlinks.rs1use derive_builder::Builder;
10use git_checks_core::impl_prelude::*;
11
12#[derive(Builder, Debug, Default, Clone, Copy)]
14#[builder(field(private))]
15pub struct RejectSymlinks {}
16
17impl RejectSymlinks {
18 pub fn builder() -> RejectSymlinksBuilder {
20 Default::default()
21 }
22}
23
24impl ContentCheck for RejectSymlinks {
25 fn name(&self) -> &str {
26 "reject-symlinks"
27 }
28
29 fn check(
30 &self,
31 _: &CheckGitContext,
32 content: &dyn Content,
33 ) -> Result<CheckResult, Box<dyn Error>> {
34 let mut result = CheckResult::new();
35
36 for diff in content.diffs() {
37 match diff.status {
38 StatusChange::Added | StatusChange::Modified(_) => (),
39 _ => continue,
40 }
41
42 if diff.new_mode == "120000" {
43 result.add_error(format!(
44 "{}adds a symlink at `{}` which is not allowed.",
45 commit_prefix(content),
46 diff.name,
47 ));
48 }
49 }
50
51 Ok(result)
52 }
53}
54
55#[cfg(feature = "config")]
56pub(crate) mod config {
57 use git_checks_config::{register_checks, CommitCheckConfig, IntoCheck, TopicCheckConfig};
58 use serde::Deserialize;
59 #[cfg(test)]
60 use serde_json::json;
61
62 use crate::RejectSymlinks;
63
64 #[derive(Deserialize, Debug)]
71 pub struct RejectSymlinksConfig {}
72
73 impl IntoCheck for RejectSymlinksConfig {
74 type Check = RejectSymlinks;
75
76 fn into_check(self) -> Self::Check {
77 Default::default()
78 }
79 }
80
81 register_checks! {
82 RejectSymlinksConfig {
83 "reject_symlinks" => CommitCheckConfig,
84 "reject_symlinks/topic" => TopicCheckConfig,
85 },
86 }
87
88 #[test]
89 fn test_reject_symlinks_config_empty() {
90 let json = json!({});
91 let check: RejectSymlinksConfig = serde_json::from_value(json).unwrap();
92
93 let _ = check.into_check();
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use git_checks_core::{Check, TopicCheck};
100
101 use crate::test::*;
102 use crate::RejectSymlinks;
103
104 const BAD_TOPIC: &str = "00ffdf352196c16a453970de022a8b4343610ccf";
105 const DELETE_TOPIC: &str = "59ebc7302ce05ec21e396e508be99f8dc2924c2d";
106 const FIX_TOPIC: &str = "d93ffc2e8b782ba8dce2278dd86fda0df80f454b";
107
108 #[test]
109 fn test_reject_symlinks_builder_default() {
110 assert!(RejectSymlinks::builder().build().is_ok());
111 }
112
113 #[test]
114 fn test_reject_symlinks_name_commit() {
115 let check = RejectSymlinks::default();
116 assert_eq!(Check::name(&check), "reject-symlinks");
117 }
118
119 #[test]
120 fn test_reject_symlinks_name_topic() {
121 let check = RejectSymlinks::default();
122 assert_eq!(TopicCheck::name(&check), "reject-symlinks");
123 }
124
125 #[test]
126 fn test_reject_symlinks() {
127 let check = RejectSymlinks::default();
128 let result = run_check("test_reject_symlinks", BAD_TOPIC, check);
129 test_result_errors(result, &[
130 "commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `absolute-link` \
131 which is not allowed.",
132 "commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `broken-link` \
133 which is not allowed.",
134 "commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `inside-link` \
135 which is not allowed.",
136 "commit 00ffdf352196c16a453970de022a8b4343610ccf adds a symlink at `outside-link` \
137 which is not allowed.",
138 ]);
139 }
140
141 #[test]
142 fn test_reject_symlinks_topic() {
143 let check = RejectSymlinks::default();
144 let result = run_topic_check("test_reject_symlinks_topic", BAD_TOPIC, check);
145 test_result_errors(
146 result,
147 &[
148 "adds a symlink at `absolute-link` which is not allowed.",
149 "adds a symlink at `broken-link` which is not allowed.",
150 "adds a symlink at `inside-link` which is not allowed.",
151 "adds a symlink at `outside-link` which is not allowed.",
152 ],
153 );
154 }
155
156 #[test]
157 fn test_reject_symlinks_topic_fixed() {
158 let check = RejectSymlinks::default();
159 run_topic_check_ok("test_reject_symlinks_topic_fixed", FIX_TOPIC, check);
160 }
161
162 #[test]
163 fn test_reject_symlinks_delete_file() {
164 let check = RejectSymlinks::default();
165 let conf = make_check_conf(&check);
166
167 let result = test_check_base(
168 "test_reject_symlinks_delete_file",
169 DELETE_TOPIC,
170 BAD_TOPIC,
171 &conf,
172 );
173 test_result_ok(result);
174 }
175
176 #[test]
177 fn test_reject_symlinks_delete_file_topic() {
178 let check = RejectSymlinks::default();
179 run_topic_check_ok(
180 "test_reject_symlinks_delete_file_topic",
181 DELETE_TOPIC,
182 check,
183 );
184 }
185}