zuka
zuka/src/brand.rs

worklyn / zukapublic

Agent-first git hosting. One Rust binary: git over HTTP and SSH, a REST API, MCP, CI, and multi-tenant isolation.

Get a copy: git clone https://zuka.worklyn.com/worklyn/zuka.git
zuka/src/brand.rs
RSbrand.rs8.0 KBDownload
1// Product identity, in one place.
2//
3// Everything that carries the product's name — the environment-variable prefix, the
4// default data directory, the problem-type URIs, the auth realm, the git config
5// namespace, the CI filename, the hook shim, user-facing message prefixes — derives
6// from `NAME` rather than repeating it as a literal.
7//
8// This module has already earned itself: the product was renamed once, and the edit
9// was one line in `Cargo.toml` plus a directory move. Before it existed the name was
10// fifty string literals across the tree — the kind of change that is technically
11// easy and practically never done.
12
13use std::sync::OnceLock;
14
15/// The product name. Taken from the crate so the two cannot disagree.
16pub const NAME: &str = env!("CARGO_PKG_NAME");
17
18/// The version a person reads.
19///
20/// Major and minor come from Cargo.toml and are set deliberately. The third
21/// component is the CI build number, which grows on its own — see `build.rs`.
22pub const VERSION: &str = env!("ZUKA_BUILD_VERSION");
23
24/// Commit this binary was built from, from `build.rs`.
25pub const COMMIT: &str = env!("ZUKA_BUILD_COMMIT");
26
27/// The identity upgrade detection compares: version plus commit.
28///
29/// Not the version alone. A forgotten bump would make an old tenant look current,
30/// and the failure mode of that is a security patch silently not landing — which is
31/// exactly the case the automatic upgrade exists for.
32pub fn build() -> &'static str {
33 static BUILD: OnceLock<String> = OnceLock::new();
34 BUILD.get_or_init(|| format!("{VERSION}+{COMMIT}"))
35}
36
37/// Uppercase name, cached. Used to build the environment-variable prefix.
38fn upper() -> &'static str {
39 static UPPER: OnceLock<String> = OnceLock::new();
40 UPPER.get_or_init(|| NAME.to_ascii_uppercase())
41}
42
43/// Prefix on every environment variable this service reads, e.g. `ZUKA_`.
44pub fn env_prefix() -> &'static str {
45 static PREFIX: OnceLock<String> = OnceLock::new();
46 PREFIX.get_or_init(|| format!("{}_", upper()))
47}
48
49/// Full name of a namespaced environment variable.
50pub fn env_name(leaf: &str) -> String {
51 format!("{}{leaf}", env_prefix())
52}
53
54/// Read a namespaced environment variable.
55///
56/// Call sites name the suffix (`"BIND"`), never the whole variable, so the prefix is
57/// defined once.
58pub fn env(leaf: &str) -> Option<String> {
59 std::env::var(env_name(leaf)).ok()
60}
61
62/// Default data directory, `/var/lib/<name>`.
63pub fn default_data_dir() -> &'static str {
64 static DIR: OnceLock<String> = OnceLock::new();
65 DIR.get_or_init(|| format!("/var/lib/{NAME}"))
66}
67
68/// Base for RFC 9457 `type` URIs.
69///
70/// Configurable because a self-hoster should be able to point clients at their own
71/// documentation rather than at ours. The slugs after the base are the stable part of
72/// the contract; the origin is not.
73pub fn problem_base() -> &'static str {
74 static BASE: OnceLock<String> = OnceLock::new();
75 BASE.get_or_init(|| {
76 env("PROBLEM_BASE")
77 .map(|v| v.trim_end_matches('/').to_string())
78 .unwrap_or_else(|| format!("https://{NAME}.dev/problems"))
79 })
80}
81
82/// Full problem `type` URI for a slug.
83pub fn problem_uri(slug: &str) -> String {
84 format!("{}/{slug}", problem_base())
85}
86
87/// HTTP Basic authentication realm.
88pub fn realm() -> &'static str {
89 NAME
90}
91
92/// Prefix for messages printed at a user's terminal by git or ssh.
93pub fn say(message: impl std::fmt::Display) -> String {
94 format!("{NAME}: {message}")
95}
96
97/// Filename of the in-repository CI spec, `.<name>.toml`.
98pub fn ci_filename() -> &'static str {
99 static FILE: OnceLock<String> = OnceLock::new();
100 FILE.get_or_init(|| format!(".{NAME}.toml"))
101}
102
103/// An HTTP header in this product's namespace, e.g. `x-zuka-identity`.
104pub fn header_name(leaf: &str) -> &'static str {
105 // Leaked deliberately: header names are `&'static str` throughout hyper, and
106 // there are a handful of them for the life of the process.
107 Box::leak(format!("x-{NAME}-{leaf}").into_boxed_str())
108}
109
110/// A git config key in this product's namespace, e.g. `zuka.protected`.
111///
112/// Settings live in the repository's own git config rather than in our metadata so
113/// the hooks can read them with no data directory, no environment and no lookup —
114/// and so they travel with the repository if it is copied.
115pub fn git_config_key(leaf: &str) -> String {
116 format!("{NAME}.{leaf}")
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn the_env_prefix_is_derived_from_the_crate_name() {
125 assert_eq!(env_prefix(), format!("{}_", NAME.to_ascii_uppercase()));
126 assert_eq!(env_name("BIND"), format!("{}BIND", env_prefix()));
127 }
128
129 #[test]
130 fn derived_identifiers_all_track_the_name() {
131 assert!(default_data_dir().ends_with(NAME));
132 assert_eq!(ci_filename(), format!(".{NAME}.toml"));
133 assert_eq!(header_name("identity"), format!("x-{NAME}-identity"));
134 assert_eq!(git_config_key("protected"), format!("{NAME}.protected"));
135 assert_eq!(realm(), NAME);
136 assert_eq!(say("hello"), format!("{NAME}: hello"));
137 }
138
139 #[test]
140 fn the_build_identity_carries_both_the_version_and_the_commit() {
141 // Version alone is not enough: CI bumps it, and a forgotten bump would make
142 // an old tenant look current.
143 let build = build();
144 assert!(build.starts_with(VERSION), "{build}");
145 assert!(build.contains('+'), "{build}");
146 assert!(
147 build.len() > VERSION.len() + 1,
148 "the commit must be present: {build}"
149 );
150 }
151
152 #[test]
153 fn a_problem_uri_is_the_base_plus_the_slug() {
154 let uri = problem_uri("not-found");
155 assert!(uri.starts_with(problem_base()));
156 assert!(uri.ends_with("/not-found"));
157 }
158
159 /// No Rust source outside this module may contain the product name as a
160 /// literal.
161 ///
162 /// This is the guard that makes the rename claim true rather than aspirational.
163 /// It has already caught one leak — an auth realm hardcoded in a header — that
164 /// a manual rename test surfaced only by inspecting the wire.
165 #[test]
166 fn the_name_appears_in_no_other_source_file() {
167 let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
168 let mut offenders = Vec::new();
169
170 let mut stack = vec![root];
171 while let Some(dir) = stack.pop() {
172 for entry in std::fs::read_dir(&dir).expect("read src") {
173 let path = entry.expect("dir entry").path();
174 if path.is_dir() {
175 stack.push(path);
176 continue;
177 }
178 if path.extension().and_then(|e| e.to_str()) != Some("rs") {
179 continue;
180 }
181 if path.file_name().and_then(|f| f.to_str()) == Some("brand.rs") {
182 continue;
183 }
184 let body = std::fs::read_to_string(&path).expect("read source");
185 for (n, line) in body.lines().enumerate() {
186 if line.to_ascii_lowercase().contains(NAME) {
187 offenders.push(format!(
188 "{}:{}: {}",
189 path.file_name().unwrap().to_string_lossy(),
190 n + 1,
191 line.trim()
192 ));
193 }
194 }
195 }
196 }
197
198 assert!(
199 offenders.is_empty(),
200 "the product name is hardcoded outside brand.rs; derive it instead:\n{}",
201 offenders.join("\n")
202 );
203 }
204
205 #[test]
206 fn nothing_here_hardcodes_the_current_name() {
207 // If the crate is renamed, every derived value must follow. This fails if
208 // someone reintroduces a literal.
209 for derived in [
210 default_data_dir().to_string(),
211 ci_filename().to_string(),
212 git_config_key("x"),
213 realm().to_string(),
214 say("x"),
215 ] {
216 assert!(
217 derived.contains(NAME),
218 "{derived:?} does not track the crate name"
219 );
220 }
221 }
222}