1use serde::{Deserialize, Serialize};
9
10use crate::schema::{NonEmptyString, RunxSchema};
11
12#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
14#[serde(rename_all = "snake_case")]
15pub enum AuthorityKind {
16 ReadOnly,
17 Constructive,
18 Destructive,
19}
20
21#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
23#[serde(rename_all = "snake_case")]
24pub enum ScopeAdmissionStatus {
25 Allow,
26 Deny,
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
31pub enum CredentialEnvelopeKind {
32 #[serde(rename = "runx.credential-envelope.v1")]
33 V1,
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
38pub enum AuthorityProofSchemaVersion {
39 #[serde(rename = "runx.authority-proof.v1")]
40 V1,
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
45#[serde(rename_all = "snake_case")]
46pub enum AuthorityProofCredentialMaterialStatus {
47 NotRequested,
48 NotResolved,
49 Resolved,
50 Denied,
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
55#[serde(rename_all = "snake_case")]
56pub enum AuthorityProofApprovalDecisionValue {
57 Approved,
58 Denied,
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
63pub enum AuthorityProofRedactionStatus {
64 #[serde(rename = "applied")]
65 Applied,
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
70pub enum AuthorityProofRedactionSecretMaterial {
71 #[serde(rename = "omitted")]
72 Omitted,
73}
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
77pub enum AuthorityProofRedactionStream {
78 #[serde(rename = "hashed")]
79 Hashed,
80}
81
82#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
84#[serde(rename_all = "snake_case", deny_unknown_fields)]
85#[runx_schema(spec_id = "https://runx.ai/spec/scope-admission.schema.json")]
86pub struct ScopeAdmission {
87 pub status: ScopeAdmissionStatus,
88 pub requested_scopes: Vec<NonEmptyString>,
89 pub granted_scopes: Vec<NonEmptyString>,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub grant_id: Option<NonEmptyString>,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub reasons: Option<Vec<NonEmptyString>>,
94 #[serde(skip_serializing_if = "Option::is_none")]
95 pub decision_summary: Option<String>,
96}
97
98#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
100#[serde(rename_all = "snake_case", deny_unknown_fields)]
101pub struct CredentialGrantReference {
102 pub grant_id: NonEmptyString,
103 pub scope_family: NonEmptyString,
104 pub authority_kind: AuthorityKind,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub target_repo: Option<NonEmptyString>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub target_locator: Option<NonEmptyString>,
109}
110
111#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
113#[serde(rename_all = "snake_case", deny_unknown_fields)]
114#[runx_schema(spec_id = "https://runx.ai/spec/credential-envelope.schema.json")]
115pub struct CredentialEnvelope {
116 pub kind: CredentialEnvelopeKind,
117 pub grant_id: NonEmptyString,
118 pub provider: NonEmptyString,
119 pub auth_mode: NonEmptyString,
120 pub material_kind: NonEmptyString,
121 pub provider_reference: NonEmptyString,
122 pub scopes: Vec<NonEmptyString>,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub grant_reference: Option<CredentialGrantReference>,
125 pub material_ref: NonEmptyString,
126}
127
128#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
130#[serde(rename_all = "snake_case", deny_unknown_fields)]
131pub struct AuthorityProofRequested {
132 pub connected_auth: bool,
133 pub scopes: Vec<NonEmptyString>,
134 pub mutating: bool,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub scope_family: Option<NonEmptyString>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub authority_kind: Option<AuthorityKind>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub target_repo: Option<NonEmptyString>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 pub target_locator: Option<NonEmptyString>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub sandbox_profile: Option<NonEmptyString>,
145}
146
147#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
149#[serde(rename_all = "snake_case", deny_unknown_fields)]
150pub struct AuthorityProofCredentialMaterial {
151 pub status: AuthorityProofCredentialMaterialStatus,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub grant_id: Option<NonEmptyString>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub provider: Option<NonEmptyString>,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub provider_reference: Option<NonEmptyString>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub scopes: Option<Vec<NonEmptyString>>,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub scope_family: Option<NonEmptyString>,
162 #[serde(skip_serializing_if = "Option::is_none")]
163 pub authority_kind: Option<AuthorityKind>,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 pub target_repo: Option<NonEmptyString>,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub target_locator: Option<NonEmptyString>,
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub grant_reference: Option<CredentialGrantReference>,
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub material_ref_hash: Option<NonEmptyString>,
172}
173
174#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
176#[serde(rename_all = "snake_case", deny_unknown_fields)]
177pub struct AuthorityProofSandboxNetwork {
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub declared: Option<bool>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub enforcement: Option<NonEmptyString>,
182}
183
184#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
186#[serde(rename_all = "snake_case", deny_unknown_fields)]
187pub struct AuthorityProofSandboxFilesystem {
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub enforcement: Option<NonEmptyString>,
190 #[serde(skip_serializing_if = "Option::is_none")]
191 pub readonly_paths: Option<bool>,
192 #[serde(skip_serializing_if = "Option::is_none")]
193 pub writable_paths_enforced: Option<bool>,
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub private_tmp: Option<bool>,
196}
197
198#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
200#[serde(rename_all = "snake_case", deny_unknown_fields)]
201pub struct AuthorityProofSandboxRuntime {
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub enforcer: Option<NonEmptyString>,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub reason: Option<NonEmptyString>,
206}
207
208#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
210#[serde(rename_all = "snake_case", deny_unknown_fields)]
211pub struct AuthorityProofSandbox {
212 pub profile: NonEmptyString,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub cwd_policy: Option<NonEmptyString>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub require_enforcement: Option<bool>,
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub network: Option<AuthorityProofSandboxNetwork>,
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub filesystem: Option<AuthorityProofSandboxFilesystem>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub runtime: Option<AuthorityProofSandboxRuntime>,
223 #[serde(skip_serializing_if = "Option::is_none")]
224 pub approval_required: Option<bool>,
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub approval_approved: Option<bool>,
227}
228
229#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
231#[serde(rename_all = "snake_case", deny_unknown_fields)]
232pub struct AuthorityProofApprovalDecision {
233 pub gate_id: NonEmptyString,
234 pub gate_type: NonEmptyString,
235 pub decision: AuthorityProofApprovalDecisionValue,
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub reason: Option<NonEmptyString>,
238}
239
240#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
242#[serde(rename_all = "snake_case", deny_unknown_fields)]
243pub struct AuthorityProofRedaction {
244 pub status: AuthorityProofRedactionStatus,
245 pub secret_material: AuthorityProofRedactionSecretMaterial,
246 pub stdout: AuthorityProofRedactionStream,
247 pub stderr: AuthorityProofRedactionStream,
248 pub metadata_secret_keys: Vec<NonEmptyString>,
249}
250
251#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
255#[serde(rename_all = "snake_case", deny_unknown_fields)]
256#[runx_schema(spec_id = "https://runx.ai/spec/authority-proof.schema.json")]
257pub struct AuthorityProof {
258 pub schema_version: AuthorityProofSchemaVersion,
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub run_id: Option<NonEmptyString>,
261 pub skill_name: NonEmptyString,
262 pub source_type: NonEmptyString,
263 pub requested: AuthorityProofRequested,
264 pub scope_admission: ScopeAdmission,
265 pub credential_material: AuthorityProofCredentialMaterial,
266 #[serde(skip_serializing_if = "Option::is_none")]
267 pub sandbox: Option<AuthorityProofSandbox>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub approval_gate: Option<AuthorityProofApprovalDecision>,
270 pub redaction: AuthorityProofRedaction,
271}