pub mod generated;
pub mod registry;
use crate::types::ResolvedType;
#[derive(Debug, Clone)]
pub struct ResourceDefinition {
pub module: &'static str,
pub function: &'static str,
pub required_params: Vec<Param>,
pub optional_params: Vec<Param>,
pub preferred_params: Vec<PreferredParam>,
pub security_params: Vec<SecurityParam>,
pub returns: ResolvedType,
}
impl ResourceDefinition {
pub fn min_args(&self) -> usize {
self.required_params.len()
}
pub fn max_args(&self) -> usize {
self.required_params.len()
+ self.optional_params.len()
+ self.preferred_params.len()
+ self.security_params.len()
}
pub fn all_params(&self) -> Vec<&Param> {
let mut params: Vec<&Param> = self.required_params.iter().collect();
params.extend(self.optional_params.iter());
params.extend(self.preferred_params.iter().map(|pp| &pp.param));
params.extend(self.security_params.iter().map(|sp| &sp.param));
params
}
pub fn get_security_param(&self, name: &str) -> Option<&SecurityParam> {
self.security_params.iter().find(|sp| sp.param.name == name)
}
pub fn get_preferred_param(&self, name: &str) -> Option<&PreferredParam> {
self.preferred_params
.iter()
.find(|pp| pp.param.name == name)
}
pub fn check_security(&self, name: &str, value: &ParamValue) -> Option<&'static str> {
if let Some(sp) = self.get_security_param(name) {
if sp.is_weakened(value) {
return Some(sp.param.name);
}
}
None
}
pub fn check_preferred(
&self,
name: &str,
value: &ParamValue,
) -> Option<(&'static str, &ParamValue)> {
if let Some(pp) = self.get_preferred_param(name) {
if pp.is_overridden(value) {
return Some((pp.param.name, &pp.recommended_default));
}
}
None
}
}
#[derive(Debug, Clone)]
pub struct Param {
pub name: &'static str,
pub param_type: ResolvedType,
}
impl Param {
pub fn new(name: &'static str, param_type: ResolvedType) -> Self {
Self { name, param_type }
}
pub fn string(name: &'static str) -> Self {
Self::new(name, ResolvedType::String)
}
pub fn bool(name: &'static str) -> Self {
Self::new(name, ResolvedType::Bool)
}
pub fn number(name: &'static str) -> Self {
Self::new(name, ResolvedType::Number)
}
pub fn record(name: &'static str) -> Self {
Self::new(name, ResolvedType::Record(std::collections::HashMap::new()))
}
pub fn tags(name: &'static str) -> Self {
Self::new(name, ResolvedType::Tags)
}
}
#[derive(Debug, Clone)]
pub struct PreferredParam {
pub param: Param,
pub recommended_default: ParamValue,
}
impl PreferredParam {
pub fn bool(name: &'static str, recommended: bool) -> Self {
Self {
param: Param::new(name, ResolvedType::Bool),
recommended_default: ParamValue::Bool(recommended),
}
}
pub fn number(name: &'static str, recommended: f64) -> Self {
Self {
param: Param::new(name, ResolvedType::Number),
recommended_default: ParamValue::Number(recommended),
}
}
pub fn is_overridden(&self, value: &ParamValue) -> bool {
&self.recommended_default != value
}
}
#[derive(Debug, Clone)]
pub struct SecurityParam {
pub param: Param,
pub secure_default: ParamValue,
}
impl SecurityParam {
pub fn new(name: &'static str, secure_default: bool, _weakened_when: bool) -> Self {
Self {
param: Param::new(name, ResolvedType::Bool),
secure_default: ParamValue::Bool(secure_default),
}
}
pub fn with_type(
name: &'static str,
param_type: ResolvedType,
secure_default: ParamValue,
) -> Self {
Self {
param: Param::new(name, param_type),
secure_default,
}
}
pub fn is_weakened(&self, value: &ParamValue) -> bool {
match (&self.secure_default, value) {
(ParamValue::None, _) => true,
(ParamValue::Bool(secure), ParamValue::Bool(actual)) => secure != actual,
(ParamValue::String(secure), ParamValue::String(actual)) => secure != actual,
_ => false,
}
}
pub fn presence(name: &'static str) -> Self {
Self {
param: Param::new(name, ResolvedType::String),
secure_default: ParamValue::None,
}
}
pub fn bool_secure_true(name: &'static str) -> Self {
Self::new(name, true, false)
}
pub fn bool_secure_false(name: &'static str) -> Self {
Self::new(name, false, true)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ParamValue {
None,
Bool(bool),
String(String),
Number(f64),
}
impl ParamValue {
pub fn from_bool(b: bool) -> Self {
Self::Bool(b)
}
pub fn from_string(s: impl Into<String>) -> Self {
Self::String(s.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_security_param_weakened() {
let sp = SecurityParam::bool_secure_true("encrypted");
assert!(!sp.is_weakened(&ParamValue::Bool(true)), "true is secure");
assert!(sp.is_weakened(&ParamValue::Bool(false)), "false weakens");
}
#[test]
fn test_security_param_public_access() {
let sp = SecurityParam::bool_secure_false("publicAccess");
assert!(!sp.is_weakened(&ParamValue::Bool(false)), "false is secure");
assert!(sp.is_weakened(&ParamValue::Bool(true)), "true weakens");
}
}