intermittent commit
This commit is contained in:
@@ -496,15 +496,7 @@ def _merge_policy(policy: EffectiveMailProfilePolicy, data: dict[str, Any], *, s
|
||||
normalized = normalize_mail_profile_policy(data)
|
||||
policy.source_policies.append(_mail_policy_source_step(source, source_id, label or source.capitalize(), normalized, baseline=baseline))
|
||||
lower_limits = dict(policy.allow_lower_level_limits)
|
||||
allowed_ids = _meaningful_allow_patterns(normalized.get("allowed_profile_ids") or [])
|
||||
if allowed_ids and lower_limits.get("allowed_profile_ids", True):
|
||||
policy.allowed_profile_id_sets.append(set(allowed_ids))
|
||||
if normalized.get("allow_user_profiles") is False and lower_limits.get("allow_user_profiles", True):
|
||||
policy.allow_user_profiles = False
|
||||
if normalized.get("allow_group_profiles") is False and lower_limits.get("allow_group_profiles", True):
|
||||
policy.allow_group_profiles = False
|
||||
if normalized.get("allow_campaign_profiles") is False and lower_limits.get("allow_campaign_profiles", True):
|
||||
policy.allow_campaign_profiles = False
|
||||
_merge_profile_definition_policy(policy, normalized, lower_limits)
|
||||
_merge_credential_policy(
|
||||
policy.smtp_credentials,
|
||||
normalized.get("smtp_credentials") or {},
|
||||
@@ -519,19 +511,43 @@ def _merge_policy(policy: EffectiveMailProfilePolicy, data: dict[str, Any], *, s
|
||||
lower_limits=lower_limits,
|
||||
inherit_limit_key="imap_credentials.inherit",
|
||||
)
|
||||
_merge_pattern_policy(policy, normalized, lower_limits)
|
||||
_merge_lower_level_limits(policy, normalized, lower_limits)
|
||||
|
||||
|
||||
def _policy_limit_enabled(lower_limits: dict[str, bool], key: str) -> bool:
|
||||
return lower_limits.get(key, True)
|
||||
|
||||
|
||||
def _merge_profile_definition_policy(policy: EffectiveMailProfilePolicy, normalized: dict[str, Any], lower_limits: dict[str, bool]) -> None:
|
||||
allowed_ids = _meaningful_allow_patterns(normalized.get("allowed_profile_ids") or [])
|
||||
if allowed_ids and _policy_limit_enabled(lower_limits, "allowed_profile_ids"):
|
||||
policy.allowed_profile_id_sets.append(set(allowed_ids))
|
||||
if normalized.get("allow_user_profiles") is False and _policy_limit_enabled(lower_limits, "allow_user_profiles"):
|
||||
policy.allow_user_profiles = False
|
||||
if normalized.get("allow_group_profiles") is False and _policy_limit_enabled(lower_limits, "allow_group_profiles"):
|
||||
policy.allow_group_profiles = False
|
||||
if normalized.get("allow_campaign_profiles") is False and _policy_limit_enabled(lower_limits, "allow_campaign_profiles"):
|
||||
policy.allow_campaign_profiles = False
|
||||
|
||||
|
||||
def _merge_pattern_policy(policy: EffectiveMailProfilePolicy, normalized: dict[str, Any], lower_limits: dict[str, bool]) -> None:
|
||||
whitelist = normalized.get("whitelist") or {}
|
||||
blacklist = normalized.get("blacklist") or {}
|
||||
for key in PROFILE_PATTERN_KEYS:
|
||||
allow_patterns = _meaningful_allow_patterns(whitelist.get(key, []))
|
||||
if allow_patterns and lower_limits.get(f"whitelist.{key}", True):
|
||||
if allow_patterns and _policy_limit_enabled(lower_limits, f"whitelist.{key}"):
|
||||
policy.whitelist_groups.setdefault(key, []).append(allow_patterns)
|
||||
deny_patterns = _clean_string_list(blacklist.get(key, []))
|
||||
if deny_patterns and lower_limits.get(f"blacklist.{key}", True):
|
||||
if deny_patterns and _policy_limit_enabled(lower_limits, f"blacklist.{key}"):
|
||||
policy.blacklist_patterns.setdefault(key, []).extend(deny_patterns)
|
||||
|
||||
|
||||
def _merge_lower_level_limits(policy: EffectiveMailProfilePolicy, normalized: dict[str, Any], lower_limits: dict[str, bool]) -> None:
|
||||
local_lower_limits = normalized.get("allow_lower_level_limits") or {}
|
||||
if local_lower_limits:
|
||||
policy.allow_lower_level_limits = {
|
||||
key: lower_limits.get(key, True) and local_lower_limits.get(key, lower_limits.get(key, True))
|
||||
key: _policy_limit_enabled(lower_limits, key) and local_lower_limits.get(key, _policy_limit_enabled(lower_limits, key))
|
||||
for key in MAIL_POLICY_LIMIT_KEYS
|
||||
}
|
||||
|
||||
@@ -1187,49 +1203,81 @@ def update_mail_server_profile(
|
||||
if is_active is not None:
|
||||
profile.is_active = is_active
|
||||
|
||||
next_smtp = smtp or SmtpConfig.model_validate({**(profile.smtp_config or {}), "username": _profile_username(profile, "smtp"), "password": decrypt_secret(profile.smtp_password_encrypted)})
|
||||
if clear_imap:
|
||||
next_imap = None
|
||||
elif imap is not None:
|
||||
next_imap = imap
|
||||
elif profile.imap_config:
|
||||
next_imap = ImapConfig.model_validate({**(profile.imap_config or {}), "username": _profile_username(profile, "imap"), "password": decrypt_secret(profile.imap_password_encrypted)})
|
||||
else:
|
||||
next_imap = None
|
||||
next_smtp, next_imap = _next_profile_transport_state(profile, smtp=smtp, imap=imap, clear_imap=clear_imap)
|
||||
_assert_profile_transport_allowed(session, tenant_id=tenant_id, profile=profile, smtp=next_smtp, imap=next_imap)
|
||||
_apply_profile_transport_update(profile, smtp=smtp, imap=imap, clear_imap=clear_imap)
|
||||
profile.updated_by_user_id = user_id
|
||||
session.add(profile)
|
||||
session.flush()
|
||||
return profile
|
||||
|
||||
|
||||
def _next_profile_transport_state(
|
||||
profile: MailServerProfile,
|
||||
*,
|
||||
smtp: SmtpConfig | None,
|
||||
imap: ImapConfig | None,
|
||||
clear_imap: bool,
|
||||
) -> tuple[SmtpConfig, ImapConfig | None]:
|
||||
next_smtp = smtp or smtp_config_from_profile(profile)
|
||||
if clear_imap:
|
||||
return next_smtp, None
|
||||
if imap is not None:
|
||||
return next_smtp, imap
|
||||
return next_smtp, imap_config_from_profile(profile)
|
||||
|
||||
|
||||
def _assert_profile_transport_allowed(
|
||||
session: Session,
|
||||
*,
|
||||
tenant_id: str,
|
||||
profile: MailServerProfile,
|
||||
smtp: SmtpConfig,
|
||||
imap: ImapConfig | None,
|
||||
) -> None:
|
||||
scope_type = _profile_scope_type(profile)
|
||||
scope_id = _profile_scope_id(profile)
|
||||
if scope_type == "campaign":
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=next_smtp, imap=next_imap, campaign_id=scope_id)
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=smtp, imap=imap, campaign_id=scope_id)
|
||||
elif scope_type == "user":
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=next_smtp, imap=next_imap, owner_user_id=scope_id)
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=smtp, imap=imap, owner_user_id=scope_id)
|
||||
elif scope_type == "group":
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=next_smtp, imap=next_imap, owner_group_id=scope_id)
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=smtp, imap=imap, owner_group_id=scope_id)
|
||||
elif scope_type == "tenant":
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=next_smtp, imap=next_imap)
|
||||
assert_mail_policy_allows_transport(session, tenant_id=tenant_id, smtp=smtp, imap=imap)
|
||||
|
||||
|
||||
def _apply_profile_transport_update(
|
||||
profile: MailServerProfile,
|
||||
*,
|
||||
smtp: SmtpConfig | None,
|
||||
imap: ImapConfig | None,
|
||||
clear_imap: bool,
|
||||
) -> None:
|
||||
if smtp is not None:
|
||||
smtp_payload, smtp_username, smtp_password, username_supplied, password_supplied = _transport_payload(smtp)
|
||||
profile.smtp_config = smtp_payload
|
||||
if username_supplied:
|
||||
profile.smtp_username = smtp_username
|
||||
if password_supplied:
|
||||
profile.smtp_password_encrypted = encrypt_secret(smtp_password)
|
||||
_apply_profile_transport_payload(profile, "smtp", smtp)
|
||||
if clear_imap:
|
||||
profile.imap_config = None
|
||||
profile.imap_username = None
|
||||
profile.imap_password_encrypted = None
|
||||
elif imap is not None:
|
||||
imap_payload, imap_username, imap_password, username_supplied, password_supplied = _transport_payload(imap)
|
||||
profile.imap_config = imap_payload
|
||||
_apply_profile_transport_payload(profile, "imap", imap)
|
||||
|
||||
|
||||
def _apply_profile_transport_payload(profile: MailServerProfile, protocol: str, config: SmtpConfig | ImapConfig) -> None:
|
||||
payload, username, password, username_supplied, password_supplied = _transport_payload(config)
|
||||
if protocol == "smtp":
|
||||
profile.smtp_config = payload
|
||||
if username_supplied:
|
||||
profile.imap_username = imap_username
|
||||
profile.smtp_username = username
|
||||
if password_supplied:
|
||||
profile.imap_password_encrypted = encrypt_secret(imap_password)
|
||||
profile.updated_by_user_id = user_id
|
||||
session.add(profile)
|
||||
session.flush()
|
||||
return profile
|
||||
profile.smtp_password_encrypted = encrypt_secret(password)
|
||||
return
|
||||
profile.imap_config = payload
|
||||
if username_supplied:
|
||||
profile.imap_username = username
|
||||
if password_supplied:
|
||||
profile.imap_password_encrypted = encrypt_secret(password)
|
||||
|
||||
|
||||
def _profile_username(profile: MailServerProfile, protocol: str) -> str | None:
|
||||
@@ -1346,29 +1394,50 @@ def get_mail_profile_policy(
|
||||
|
||||
|
||||
def _validate_policy_against_parent(parent: EffectiveMailProfilePolicy, normalized: dict[str, Any]) -> None:
|
||||
parent_limits = parent.allow_lower_level_limits
|
||||
violations = _policy_parent_lock_violations(parent.allow_lower_level_limits, normalized)
|
||||
if violations:
|
||||
raise MailProfileError(_policy_parent_lock_message(violations[0]))
|
||||
|
||||
|
||||
def _policy_parent_lock_violations(parent_limits: dict[str, bool], normalized: dict[str, Any]) -> list[str]:
|
||||
violations: list[str] = []
|
||||
allowed_ids = _meaningful_allow_patterns(normalized.get("allowed_profile_ids") or [])
|
||||
if allowed_ids and not parent_limits.get("allowed_profile_ids", True):
|
||||
raise MailProfileError("Mail profile allow-list is locked by an ancestor policy")
|
||||
if allowed_ids and not _policy_limit_enabled(parent_limits, "allowed_profile_ids"):
|
||||
violations.append("allowed_profile_ids")
|
||||
for key in ("allow_user_profiles", "allow_group_profiles", "allow_campaign_profiles"):
|
||||
if isinstance(normalized.get(key), bool) and not parent_limits.get(key, True):
|
||||
raise MailProfileError(f"{key} is locked by an ancestor policy")
|
||||
if isinstance(normalized.get(key), bool) and not _policy_limit_enabled(parent_limits, key):
|
||||
violations.append(key)
|
||||
for kind in ("whitelist", "blacklist"):
|
||||
rules = normalized.get(kind) or {}
|
||||
if isinstance(rules, dict):
|
||||
for key in PROFILE_PATTERN_KEYS:
|
||||
if _clean_string_list(rules.get(key, [])) and not parent_limits.get(f"{kind}.{key}", True):
|
||||
raise MailProfileError(f"{kind}.{key} is locked by an ancestor policy")
|
||||
limit_key = f"{kind}.{key}"
|
||||
if _clean_string_list(rules.get(key, [])) and not _policy_limit_enabled(parent_limits, limit_key):
|
||||
violations.append(limit_key)
|
||||
for protocol in ("smtp", "imap"):
|
||||
local = normalized.get(f"{protocol}_credentials") or {}
|
||||
local_inherit = local.get("inherit")
|
||||
if isinstance(local_inherit, bool) and not parent_limits.get(f"{protocol}_credentials.inherit", True):
|
||||
raise MailProfileError(f"{protocol.upper()} credential inheritance is locked by an ancestor policy")
|
||||
limit_key = f"{protocol}_credentials.inherit"
|
||||
if isinstance(local_inherit, bool) and not _policy_limit_enabled(parent_limits, limit_key):
|
||||
violations.append(limit_key)
|
||||
local_lower_limits = normalized.get("allow_lower_level_limits") or {}
|
||||
if isinstance(local_lower_limits, dict):
|
||||
for key, allowed in local_lower_limits.items():
|
||||
if allowed is True and not parent_limits.get(key, True):
|
||||
raise MailProfileError(f"{key} lower-level limiting cannot be re-enabled below a locked ancestor policy")
|
||||
if allowed is True and not _policy_limit_enabled(parent_limits, key):
|
||||
violations.append(f"allow_lower_level_limits.{key}")
|
||||
return violations
|
||||
|
||||
|
||||
def _policy_parent_lock_message(field: str) -> str:
|
||||
if field == "allowed_profile_ids":
|
||||
return "Mail profile allow-list is locked by an ancestor policy"
|
||||
if field.startswith("allow_lower_level_limits."):
|
||||
key = field.removeprefix("allow_lower_level_limits.")
|
||||
return f"{key} lower-level limiting cannot be re-enabled below a locked ancestor policy"
|
||||
if field.endswith("_credentials.inherit"):
|
||||
protocol = field.split("_", 1)[0].upper()
|
||||
return f"{protocol} credential inheritance is locked by an ancestor policy"
|
||||
return f"{field} is locked by an ancestor policy"
|
||||
|
||||
|
||||
def set_mail_profile_policy(
|
||||
|
||||
Reference in New Issue
Block a user