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
//! The capability token that gates every side-effecting operation in callisto.
//!
//! Before this existed, "respect `--dry-run`" was a convention: each command
//! handler was expected to remember to consult a bool before writing. Four
//! separate commands forgot -- `version` and `add` (fixed earlier), then
//! `pre enter`/`pre exit` and `init`, neither of which read the flag at all.
//! The bug class is not specific to this codebase; cargo's own `--dry-run`
//! tracker carries the same shape of defect. A convention that must be
//! remembered at every new write site will eventually be forgotten at one.
//!
//! [`ApplyPermit`] converts that convention into a type obligation. Write
//! primitives (`atomic_write`, manifest persistence, tag creation, registry
//! publishing, git staging) take `&ApplyPermit`, and the only way to obtain
//! one outside of tests is [`ApplyPermit::granted_unless_dry_run`], which
//! returns `None` for a dry run. A command handler that forgets the check now
//! has nothing to pass, and fails to compile.
/// Proof that the caller is authorized to perform real side effects.
///
/// Hold one of these and you may write to disk, create git refs, or publish to
/// a registry. The private unit field means no other module -- inside this
/// crate or outside it -- can construct one via a struct literal; the
/// constructors below are the entire surface.
///
/// # Examples
///
/// ```
/// use callisto_model::ApplyPermit;
///
/// // A dry run yields no permit, so no write primitive can be called.
/// assert!(ApplyPermit::granted_unless_dry_run(true).is_none());
///
/// // A real run yields one, which is then threaded into write primitives.
/// let permit = ApplyPermit::granted_unless_dry_run(false).expect("not a dry run");
/// # let _ = permit;
/// ```