1use serde::{Deserialize, Serialize};
2
3pub const AMBIENT_CRED_ENV_VARS: &[&str] = &[
17 "AWS_PROFILE",
19 "AWS_DEFAULT_PROFILE",
20 "AWS_CONFIG_FILE",
21 "AWS_SHARED_CREDENTIALS_FILE",
22 "AWS_WEB_IDENTITY_TOKEN_FILE",
23 "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
24 "AWS_CONTAINER_CREDENTIALS_FULL_URI",
25 "GOOGLE_APPLICATION_CREDENTIALS",
27 "GOOGLE_OAUTH_ACCESS_TOKEN",
28 "GOOGLE_CLOUD_PROJECT",
29 "CLOUDSDK_AUTH_ACCESS_TOKEN",
30 "CLOUDSDK_CONFIG",
31 "CLOUDSDK_CORE_PROJECT",
32 "AZURE_CLIENT_SECRET",
34 "AZURE_TENANT_ID",
35];
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ChainStep {
40 pub allow: String,
42 pub resource: Option<String>,
44 pub profile: Option<String>,
46 pub ttl: Option<String>,
48 pub command: Vec<String>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct StepResult {
55 pub step_index: usize,
56 pub allow: String,
57 pub exit_code: i32,
58 pub stdout: String,
59 pub stderr: String,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct ChainResult {
65 pub steps: Vec<StepResult>,
66 pub total_steps: usize,
67 pub completed_steps: usize,
68 pub success: bool,
69}
70
71impl ChainResult {
72 pub fn new(total: usize) -> Self {
73 Self {
74 steps: Vec::new(),
75 total_steps: total,
76 completed_steps: 0,
77 success: true,
78 }
79 }
80
81 pub fn add_step(&mut self, result: StepResult) {
82 if result.exit_code != 0 {
83 self.success = false;
84 }
85 self.completed_steps += 1;
86 self.steps.push(result);
87 }
88}
89
90pub fn parse_step_spec(spec: &str) -> ChainStep {
93 ChainStep {
94 allow: spec.to_string(),
95 resource: None,
96 profile: None,
97 ttl: None,
98 command: Vec::new(),
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_parse_step_spec() {
108 let step = parse_step_spec("s3:GetObject,s3:ListBucket");
109 assert_eq!(step.allow, "s3:GetObject,s3:ListBucket");
110 assert!(step.resource.is_none());
111 assert!(step.command.is_empty());
112 }
113
114 #[test]
115 fn test_chain_result_success() {
116 let mut result = ChainResult::new(2);
117 result.add_step(StepResult {
118 step_index: 0,
119 allow: "s3:GetObject".to_string(),
120 exit_code: 0,
121 stdout: "ok".to_string(),
122 stderr: String::new(),
123 });
124 result.add_step(StepResult {
125 step_index: 1,
126 allow: "lambda:InvokeFunction".to_string(),
127 exit_code: 0,
128 stdout: "ok".to_string(),
129 stderr: String::new(),
130 });
131 assert!(result.success);
132 assert_eq!(result.completed_steps, 2);
133 }
134
135 #[test]
136 fn test_chain_result_failure_stops() {
137 let mut result = ChainResult::new(3);
138 result.add_step(StepResult {
139 step_index: 0,
140 allow: "s3:GetObject".to_string(),
141 exit_code: 0,
142 stdout: "ok".to_string(),
143 stderr: String::new(),
144 });
145 result.add_step(StepResult {
146 step_index: 1,
147 allow: "lambda:InvokeFunction".to_string(),
148 exit_code: 1,
149 stdout: String::new(),
150 stderr: "access denied".to_string(),
151 });
152 assert!(!result.success);
153 assert_eq!(result.completed_steps, 2);
154 }
155
156 #[test]
157 fn test_chain_result_serializable() {
158 let result = ChainResult::new(1);
159 let json = serde_json::to_string(&result).unwrap();
160 assert!(json.contains("\"total_steps\":1"));
161 }
162}