iam-policy-validator 1.13.1__py3-none-any.whl → 1.14.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {iam_policy_validator-1.13.1.dist-info → iam_policy_validator-1.14.1.dist-info}/METADATA +1 -1
  2. {iam_policy_validator-1.13.1.dist-info → iam_policy_validator-1.14.1.dist-info}/RECORD +45 -39
  3. iam_validator/__version__.py +1 -1
  4. iam_validator/checks/action_condition_enforcement.py +6 -0
  5. iam_validator/checks/action_resource_matching.py +12 -12
  6. iam_validator/checks/action_validation.py +1 -0
  7. iam_validator/checks/condition_key_validation.py +2 -0
  8. iam_validator/checks/condition_type_mismatch.py +3 -0
  9. iam_validator/checks/full_wildcard.py +1 -0
  10. iam_validator/checks/mfa_condition_check.py +2 -0
  11. iam_validator/checks/policy_structure.py +9 -0
  12. iam_validator/checks/policy_type_validation.py +11 -0
  13. iam_validator/checks/principal_validation.py +5 -0
  14. iam_validator/checks/resource_validation.py +4 -0
  15. iam_validator/checks/sensitive_action.py +1 -0
  16. iam_validator/checks/service_wildcard.py +6 -3
  17. iam_validator/checks/set_operator_validation.py +3 -0
  18. iam_validator/checks/sid_uniqueness.py +2 -0
  19. iam_validator/checks/trust_policy_validation.py +3 -0
  20. iam_validator/checks/utils/__init__.py +16 -0
  21. iam_validator/checks/utils/action_parser.py +149 -0
  22. iam_validator/checks/wildcard_action.py +1 -0
  23. iam_validator/checks/wildcard_resource.py +231 -4
  24. iam_validator/commands/analyze.py +19 -1
  25. iam_validator/commands/completion.py +6 -2
  26. iam_validator/commands/validate.py +231 -12
  27. iam_validator/core/aws_service/fetcher.py +21 -9
  28. iam_validator/core/codeowners.py +245 -0
  29. iam_validator/core/config/check_documentation.py +390 -0
  30. iam_validator/core/config/config_loader.py +199 -0
  31. iam_validator/core/config/defaults.py +25 -0
  32. iam_validator/core/constants.py +1 -0
  33. iam_validator/core/diff_parser.py +8 -4
  34. iam_validator/core/finding_fingerprint.py +131 -0
  35. iam_validator/core/formatters/sarif.py +370 -128
  36. iam_validator/core/ignore_processor.py +309 -0
  37. iam_validator/core/ignored_findings.py +400 -0
  38. iam_validator/core/models.py +54 -4
  39. iam_validator/core/policy_loader.py +313 -4
  40. iam_validator/core/pr_commenter.py +223 -22
  41. iam_validator/core/report.py +22 -6
  42. iam_validator/integrations/github_integration.py +881 -123
  43. {iam_policy_validator-1.13.1.dist-info → iam_policy_validator-1.14.1.dist-info}/WHEEL +0 -0
  44. {iam_policy_validator-1.13.1.dist-info → iam_policy_validator-1.14.1.dist-info}/entry_points.txt +0 -0
  45. {iam_policy_validator-1.13.1.dist-info → iam_policy_validator-1.14.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,131 @@
1
+ """Finding fingerprint generation for stable issue identification.
2
+
3
+ This module provides a way to generate unique, deterministic identifiers
4
+ for validation findings that survive code changes within a PR. These
5
+ fingerprints are used to track which findings have been ignored by CODEOWNERS.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ from dataclasses import dataclass
12
+ from typing import TYPE_CHECKING
13
+
14
+ if TYPE_CHECKING:
15
+ from iam_validator.core.models import ValidationIssue
16
+
17
+
18
+ def compute_finding_hash(
19
+ file_path: str,
20
+ check_id: str | None,
21
+ issue_type: str,
22
+ statement_sid: str | None,
23
+ statement_index: int,
24
+ action: str | None = None,
25
+ resource: str | None = None,
26
+ condition_key: str | None = None,
27
+ ) -> str:
28
+ """Compute a deterministic 16-character hash for a finding.
29
+
30
+ This is a standalone function to avoid cyclic imports when called
31
+ from models.py.
32
+
33
+ Args:
34
+ file_path: Relative path to the policy file
35
+ check_id: Check that found the issue
36
+ issue_type: Type of issue
37
+ statement_sid: Statement ID if available
38
+ statement_index: Statement index
39
+ action: Specific action (optional)
40
+ resource: Specific resource (optional)
41
+ condition_key: Condition key (optional)
42
+
43
+ Returns:
44
+ 16-character hex string uniquely identifying this finding
45
+ """
46
+ # Use SID if available, otherwise fall back to index
47
+ statement_id = statement_sid if statement_sid else f"idx:{statement_index}"
48
+
49
+ components = [
50
+ file_path,
51
+ check_id or "",
52
+ issue_type,
53
+ statement_id,
54
+ action or "",
55
+ resource or "",
56
+ condition_key or "",
57
+ ]
58
+ combined = "|".join(components)
59
+ return hashlib.sha256(combined.encode()).hexdigest()[:16]
60
+
61
+
62
+ @dataclass(frozen=True, slots=True)
63
+ class FindingFingerprint:
64
+ """Unique identifier for a validation finding across runs.
65
+
66
+ The fingerprint is based on stable attributes of the finding that
67
+ are unlikely to change when code is modified within the same PR.
68
+ Uses frozen=True for immutability and slots=True for memory efficiency.
69
+
70
+ Attributes:
71
+ file_path: Relative path to the policy file
72
+ check_id: Check that found the issue (e.g., "sensitive_action")
73
+ issue_type: Type of issue (e.g., "invalid_action")
74
+ statement_sid: Statement ID if available (more stable than index)
75
+ statement_index: Fallback when no SID is present
76
+ action: Specific action (for action-related issues)
77
+ resource: Specific resource (for resource-related issues)
78
+ condition_key: Specific condition key (for condition issues)
79
+ """
80
+
81
+ file_path: str
82
+ check_id: str
83
+ issue_type: str
84
+ statement_sid: str | None
85
+ statement_index: int
86
+ action: str | None
87
+ resource: str | None
88
+ condition_key: str | None
89
+
90
+ def to_hash(self) -> str:
91
+ """Generate deterministic 16-character hash for storage.
92
+
93
+ The hash is based on all fingerprint components joined with a
94
+ delimiter. Uses SHA-256 truncated to 16 characters for a good
95
+ balance between uniqueness and storage efficiency.
96
+
97
+ Returns:
98
+ 16-character hex string uniquely identifying this finding
99
+ """
100
+ return compute_finding_hash(
101
+ file_path=self.file_path,
102
+ check_id=self.check_id,
103
+ issue_type=self.issue_type,
104
+ statement_sid=self.statement_sid,
105
+ statement_index=self.statement_index,
106
+ action=self.action,
107
+ resource=self.resource,
108
+ condition_key=self.condition_key,
109
+ )
110
+
111
+ @classmethod
112
+ def from_issue(cls, issue: ValidationIssue, file_path: str) -> FindingFingerprint:
113
+ """Create fingerprint from a ValidationIssue.
114
+
115
+ Args:
116
+ issue: The validation issue to fingerprint
117
+ file_path: Relative path to the policy file
118
+
119
+ Returns:
120
+ FindingFingerprint instance for the issue
121
+ """
122
+ return cls(
123
+ file_path=file_path,
124
+ check_id=issue.check_id or "",
125
+ issue_type=issue.issue_type,
126
+ statement_sid=issue.statement_sid,
127
+ statement_index=issue.statement_index,
128
+ action=issue.action,
129
+ resource=issue.resource,
130
+ condition_key=issue.condition_key,
131
+ )