tfparser_core/ir/
provider.rs1use std::sync::Arc;
10
11use serde::{Deserialize, Serialize};
12use typed_builder::TypedBuilder;
13
14use crate::ir::{AttributeMap, Expression, Span};
15
16#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypedBuilder)]
21#[non_exhaustive]
22#[serde(rename_all = "camelCase")]
23#[builder(field_defaults(setter(into)))]
24pub struct AssumeRole {
25 pub role_arn_expr: Expression,
27 pub span: Span,
29}
30
31#[derive(Clone, PartialEq, Serialize, Deserialize, TypedBuilder)]
40#[non_exhaustive]
41#[serde(rename_all = "camelCase")]
42#[builder(field_defaults(setter(into)))]
43pub struct ProviderBlock {
44 pub local_name: Arc<str>,
46
47 #[builder(default)]
49 pub alias: Option<Arc<str>>,
50
51 #[builder(default)]
54 pub source_addr: Option<Arc<str>>,
55
56 #[builder(default)]
58 pub region_expr: Option<Expression>,
59
60 #[builder(default)]
62 pub profile_expr: Option<Expression>,
63
64 #[builder(default)]
66 pub assume_role: Option<AssumeRole>,
67
68 #[builder(default)]
70 pub raw: AttributeMap,
71
72 pub span: Span,
74}
75
76impl std::fmt::Debug for ProviderBlock {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("ProviderBlock")
79 .field("local_name", &self.local_name)
80 .field("alias", &self.alias)
81 .field("source_addr", &self.source_addr)
82 .field("region_expr", &self.region_expr.as_ref().map(|_| "<expr>"))
83 .field(
84 "profile_expr",
85 &self.profile_expr.as_ref().map(|_| "<expr>"),
86 )
87 .field(
88 "assume_role",
89 &self.assume_role.as_ref().map(|_| "<assume_role>"),
90 )
91 .field(
92 "raw",
93 &format!("<{} attributes (redacted)>", self.raw.len()),
94 )
95 .field("span", &self.span)
96 .finish()
97 }
98}
99
100#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, TypedBuilder)]
104#[non_exhaustive]
105#[serde(rename_all = "camelCase")]
106#[builder(field_defaults(setter(into)))]
107pub struct ProviderRef {
108 pub local_name: Arc<str>,
110
111 #[builder(default)]
113 pub alias: Option<Arc<str>>,
114
115 pub span: Span,
117}
118
119#[cfg(test)]
120#[allow(clippy::unwrap_used)]
121mod tests {
122 use std::sync::Arc;
123
124 use super::*;
125 use crate::ir::Span;
126
127 #[test]
128 fn test_should_build_minimal_provider_block() {
129 let p = ProviderBlock::builder()
130 .local_name(Arc::<str>::from("aws"))
131 .span(Span::synthetic())
132 .build();
133 assert_eq!(&*p.local_name, "aws");
134 assert!(p.alias.is_none());
135 assert!(p.raw.is_empty());
136 }
137
138 #[test]
139 fn test_should_redact_raw_attrs_in_debug() {
140 let p = ProviderBlock::builder()
141 .local_name(Arc::<str>::from("aws"))
142 .raw(vec![(
143 Arc::<str>::from("secret_access_key"),
144 crate::ir::Expression::Literal(crate::ir::Value::Str(Arc::<str>::from(
145 "very-secret",
146 ))),
147 )])
148 .span(Span::synthetic())
149 .build();
150 let debug = format!("{p:?}");
151 assert!(!debug.contains("very-secret"), "{debug}");
152 assert!(debug.contains("redacted"), "{debug}");
153 }
154
155 #[test]
156 fn test_should_serde_round_trip_provider_ref() {
157 let r = ProviderRef {
158 local_name: Arc::<str>::from("aws"),
159 alias: Some(Arc::<str>::from("main")),
160 span: Span::synthetic(),
161 };
162 let json = serde_json::to_string(&r).unwrap();
163 let back: ProviderRef = serde_json::from_str(&json).unwrap();
164 assert_eq!(r, back);
165 }
166}