wowlab_tidy/languages/rust/rules/safety/
hardcoded_url.rs1use crate::{Example, FileCtx, Violation, infra::parse, violation};
2
3#[rustfmt::skip]
4const EXAMPLES: &[Example] = &[
5 Example {
6 label: "hardcoded https URL",
7 code: r#"fn f() { let url = "https://api.example.com/v1"; }"#,
8 pass: false,
9 },
10 Example {
11 label: "hardcoded http URL",
12 code: r#"fn f() { let url = "http://localhost:3000"; }"#,
13 pass: false,
14 },
15 Example {
16 label: "no URL",
17 code: "fn f() { let x = 42; }",
18 pass: true,
19 },
20 Example {
21 label: "URL in doc comment",
22 code: "/// See https://docs.rs/foo for details.",
23 pass: true,
24 },
25 Example {
26 label: "URL in regular comment",
27 code: "// Reference: https://example.com/spec",
28 pass: true,
29 },
30];
31
32crate::line_rule!(
33 hardcoded_url,
34 "Flag hardcoded URLs in source code (should use config/env).",
35 "Hardcoded URLs break when environments change. Use configuration or environment variables for host-specific URLs.",
36 Medium,
37);
38
39fn check_hardcoded_url(ctx: &FileCtx<'_>) -> Vec<Violation> {
40 let mut out = Vec::new();
41
42 for (i, line) in ctx.lines.iter().enumerate() {
43 let trimmed = line.trim();
44
45 if parse::is_comment(trimmed) {
46 continue;
47 }
48
49 if let Some(idx) = parse::find_url(line) {
50 let Some(before) = line.get(..idx) else {
51 continue;
52 };
53 let has_open_quote = before.contains('"');
54
55 if has_open_quote {
56 out.push(violation(
57 ctx.rel,
58 i + 1,
59 "hardcoded URL in source — use configuration or environment variable instead",
60 ));
61 }
62 }
63 }
64
65 out
66}
67
68crate::tidy_test!(check_hardcoded_url, {
69 crate::example_tests!(EXAMPLES, check_hardcoded_url);
70});