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
//! Component reference resolution, backed by the shared `act-store`.
//!
//! `ComponentRef` is re-exported from `act-store` (the parsing source of truth).
//! Local refs run in place; remote refs (OCI/HTTP) resolve read-through the
//! store (pulled on first use, then served from disk).
use PathBuf;
use ;
use PathClean;
pub use Ref as ComponentRef;
/// Open the shared component store at its platform default location.
/// Resolve a component reference to a local `.wasm` path.
///
/// Local files are used in place (never copied into the store). Remote refs
/// (OCI/HTTP) are served read-through from the store; `fresh` forces a re-pull.
pub async
/// The stable key a component's credential profile is namespaced under.
///
/// This is *not* `component_ref.to_string()`. For `Http`/`Oci`/`Name` refs
/// `to_string()` is returned unchanged: it is already canonical *as a
/// string* (a parsed URL, a registry ref matched by the OCI regex, a bare
/// name) — but see the caveat below, because canonical as a string is not
/// the same as canonical as an identity. For `Local` it is not even that:
/// `to_string()` is `path.display()` verbatim, so `./notion.wasm`,
/// `notion.wasm` and its absolute form would each open a *different*
/// profile for the same file — `act secret set ./notion.wasm` followed by
/// `act run notion.wasm` would silently miss.
///
/// Relative local paths are joined onto the current directory and
/// lexically cleaned (`path_clean`, no filesystem access — the component
/// need not exist yet, e.g. before a first `act pull`), so every spelling
/// of the same path agrees. Both `act secret set/list/rm` and the runtime's
/// `credential_host` (main.rs) key their profile lookups through this
/// function, so they cannot drift apart.
///
/// # A remote ref's tag is part of the profile identity
///
/// For remote refs the whole ref string is the key, tag and digest included,
/// and this function does nothing to narrow it. So
/// `ghcr.io/actpkg/notion:0.1.0`, `…/notion:0.2.0`, `…/notion`,
/// `…/notion:latest` and `…/notion@sha256:…` are **five distinct profiles**
/// for what an operator thinks of as one component, and provisioning against
/// one while running another gets a bare `not-found`:
///
/// ```text
/// act secret set ghcr.io/actpkg/notion:0.1.0 --key mcp.notion.com …
/// act run ghcr.io/actpkg/notion:0.2.0 # other profile → not-found
/// ```
///
/// This fails closed — a version bump never hands a new artifact the old
/// artifact's credential, which is the safe direction, and it is why phase 1
/// ships as is rather than guessing at an equivalence between refs. What it
/// costs is that every upgrade is a silent re-provisioning event whose only
/// symptom is `not-found`.
///
/// Phase 2 owes one of two remedies, and the choice is deliberately left
/// open here: canonicalise remote refs to the repository without the tag, or
/// keep the key and make the first `not-found` name the profile it looked in
/// (design §5.2's "first-failure message carrying a copy-pasteable
/// command"). Until then this is a documented sharp edge, not a bug.