1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! **The parts every gunnar binary shares, regardless of which half it is.**
//!
//! The command line ([`cli`]), the logging ladder ([`logging`]), the build
//! identity ([`BUILD_REF`], [`ssh_server_id`]) and the one address the control
//! plane defaults to ([`DEFAULT_CONTROL_ADDR`]) are needed by a pure-server
//! build, a pure-client build and the all-in-one alike. They lived in
//! `gunnar-cli` while it was the only binary crate; they moved here when the
//! server implementation became its own crate, so that `gunnar-cli` and
//! `gunnar-server` can both depend on this and neither has to depend on the
//! other.
//!
//! Nothing here is an *implementation* of a verb. The `Command` enum names the
//! verbs and parses their arguments; dispatching them into `gunnar-server`'s
//! server code or `gunnar-cli`'s client code stays in those crates.
/// Where a listener binds — an address, or an interface resolved at boot.
/// A box's own background duty as named jera jobs (A32-14).
/// Where the metered appliance's verifying key comes from — a file, or the
/// key itself, spelled inline on a kernel command line.
/// Every INFO+ line as a value, for the appliance console dashboard.
/// `gunnar/<version>`, the string this binary identifies itself with.
pub const AGENT: &str = concat!;
/// The build this binary is, as `build.rs` stamped it: the builder's passed
/// ref (`GUNNAR_BUILD_REF`, then the Build Thing's `NORDISK_BUILD_REF`), else
/// `git describe --tags --always --dirty=-modified --abbrev=7`, else `unknown`.
pub const BUILD_REF: &str = env!;
/// Where the control plane listens unless told otherwise.
///
/// **Loopback, and it should stay there.** `gunnar serve` binds
/// `127.0.0.1:50051` by default for defence in depth, so the default target of
/// `gunnar control …` is the server on this host. Reaching a remote one is an
/// explicit `--at`.
///
/// It lives here, and not in `gunnar-cli`'s `control` module, because `cli.rs`
/// names it as the default of every control verb's `--at` and `cli.rs` is here.
pub const DEFAULT_CONTROL_ADDR: &str = "127.0.0.1:50051";
/// **The SSH identification string, carrying the commit this server is.**
///
/// `SshConfig::default()` produces `SSH-2.0-gunnar_0.1.0`, which names a manifest
/// field. That is enough on a machine where you can run `gunnar --version`, and
/// it is *all there is* on the appliance: the OS-less ISO has no shell, no init
/// but gunnar itself, and no way in but this listener. MEASURED 2026-08-05, the
/// forge-built appliance ISO booting under QEMU/OVMF:
///
/// ```text
/// BOOTED AND LISTENING in 5.911152673s — banner "SSH-2.0-gunnar_0.1.0"
/// ```
///
/// Two ISOs built from different commits are indistinguishable over the wire
/// there, and the only other identity on offer is the file's mtime. So the build
/// reference goes on the banner, which is the first thing the appliance says and
/// the one thing it says before authenticating.
///
/// # Where it goes, and why not in the version field
///
/// RFC 4253 §4.2 is `SSH-protoversion-softwareversion SP comments`, and
/// *softwareversion* may contain no space and no minus — `git describe` output
/// has both (`v1.0-4-g008d74b`). So it goes in the optional **comments** field,
/// after the space, which is exactly where OpenSSH puts its distribution string
/// (`SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.5`). Nothing parses the comments, and
/// the kex hash covers the whole string either way, so this is a legal
/// identification string for every client and a readable one for a person.
///
/// An unstamped build (`unknown`, i.e. no `.git` at compile time) adds nothing
/// rather than advertising the word "unknown" to the network.
/// Install the tracing subscriber once, honouring `RUST_LOG`.
///
/// `info` by default rather than `warn`. The things an operator most needs to
/// see on a gunnar server are all logged at `info`: the bound addresses, the
/// gRPC authentication mode, the `gunnar::audit` trail of who called what, and
/// one line per connection and one per transfer with its
/// applied outputs. A default of `warn` would hide every one of them.
///
/// # The targets, and how to filter them
///
/// Every line gunnar emits is on a `gunnar::` target, listed once in
/// `gunnar_core::observe::TARGETS`:
///
/// ```text
/// gunnar::audit who called the control plane, and what was decided
/// gunnar::ssh connections: accepted, authenticated, refused
/// gunnar::git transfers: upload-pack, receive-pack, objects, bytes
/// gunnar::policy the push gate: which gate refused which reference
/// gunnar::store ref transactions, CAS contention, repack
/// gunnar::metrics the counter heartbeat
/// ```
///
/// ```text
/// RUST_LOG=warn,gunnar::audit=info,gunnar::git=info # a quiet production box
/// RUST_LOG=gunnar::ssh=debug,gunnar::policy=debug # one incident, in detail
/// ```
///
/// Each connection carries a request id on its span, so every line underneath,
/// including the ones `gunnar-wire` and `gunnar-policy` emit from inside a
/// transfer, is greppable by `conn=<id>` without any of them repeating the
/// principal or the repository.