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
// SPDX-License-Identifier: GPL-3.0-or-later
// Rust guideline compliant 2026-03-30
//! Single-line failure diagnostic for every Gitway binary.
//!
//! When a Gitway binary runs and fails in human (non-JSON) mode, one
//! [`emit`] / [`emit_for`] / [`emit_for_with_config_sources`] call writes
//! a logfmt-style record to stderr:
//!
//! ```text
//! gitway diag ts=2026-04-22T18:43:11Z pid=12345 code=4 reason=PERMISSION_DENIED config_source=~/.ssh/config,/etc/ssh/ssh_config argv=["gitway", "git@github.com", "git-upload-pack", "'org/repo.git'"]
//! ```
//!
//! The point is to turn silent `exit 128` failures — the opaque code git
//! reports when `core.sshCommand` fails — into a single grep-able line
//! that carries enough context to triage: ISO 8601 timestamp, PID, argv,
//! exit code, error reason, and (when relevant) the `ssh_config(5)`
//! file(s) that were consulted (NFR-24, M12.8).
//!
//! JSON mode already carries `timestamp` and `command` in its structured
//! `{"error": {...}}` blob, so callers should skip this helper on that
//! path. Stdout is always left untouched (SFRS Rule 1) — the diagnostic
//! writes exclusively to stderr.
use PathBuf;
use crateAnvilError;
use cratenow_iso8601;
/// Emits the single-line diagnostic record with an explicit exit code and
/// a reason string. Use this from the shim binaries (`gitway-keygen`,
/// `gitway-add`) where the reason codes are selected from a local static
/// table; use [`emit_for`] when an [`AnvilError`] is already in hand.
/// Emits the diagnostic record for an [`AnvilError`], reusing the error's
/// mapped exit code and string error class.
/// Like [`emit_for`], plus a `config_source=` field listing the
/// `ssh_config(5)` files that were consulted during this invocation.
///
/// `config_sources` should be the deduplicated list of files the
/// resolver attempted to read (typically `~/.ssh/config` and, on Unix,
/// `/etc/ssh/ssh_config`). An empty slice produces a line identical to
/// [`emit_for`] — no `config_source=` field is emitted.
///
/// This is the M12.8 entry point for NFR-24: callers that successfully
/// or unsuccessfully consulted `ssh_config` should pass that fact down
/// to the diagnostic so triage tooling can attribute behavior to the
/// right file. The Gitway CLI does this around its top-level
/// [`emit_for`]-equivalent call site (`gitway-cli/src/main.rs`).