sraverify 0.1.1__py3-none-any.whl → 0.1.3__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.
- sraverify/core/logging.py +37 -3
- sraverify/main.py +3 -4
- sraverify/services/organizations/__init__.py +25 -0
- sraverify/services/organizations/base.py +176 -0
- sraverify/services/organizations/checks/__init__.py +3 -0
- sraverify/services/organizations/checks/sra_organizations_01.py +84 -0
- sraverify/services/organizations/checks/sra_organizations_02.py +123 -0
- sraverify/services/organizations/checks/sra_organizations_03.py +123 -0
- sraverify/services/organizations/checks/sra_organizations_04.py +123 -0
- sraverify/services/organizations/checks/sra_organizations_05.py +92 -0
- sraverify/services/organizations/checks/sra_organizations_06.py +125 -0
- sraverify/services/organizations/checks/sra_organizations_07.py +128 -0
- sraverify/services/organizations/checks/sra_organizations_08.py +167 -0
- sraverify/services/organizations/checks/sra_organizations_09.py +167 -0
- sraverify/services/organizations/client.py +153 -0
- {sraverify-0.1.1.dist-info → sraverify-0.1.3.dist-info}/METADATA +1 -1
- {sraverify-0.1.1.dist-info → sraverify-0.1.3.dist-info}/RECORD +22 -9
- {sraverify-0.1.1.dist-info → sraverify-0.1.3.dist-info}/LICENSE +0 -0
- {sraverify-0.1.1.dist-info → sraverify-0.1.3.dist-info}/NOTICE +0 -0
- {sraverify-0.1.1.dist-info → sraverify-0.1.3.dist-info}/WHEEL +0 -0
- {sraverify-0.1.1.dist-info → sraverify-0.1.3.dist-info}/entry_points.txt +0 -0
- {sraverify-0.1.1.dist-info → sraverify-0.1.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check if log archive account is in Security OU.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, List, Any
|
|
5
|
+
from sraverify.services.organizations.base import OrganizationsCheck
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_ORGANIZATIONS_09(OrganizationsCheck):
|
|
9
|
+
"""Check if log archive account is in Security OU."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize log archive account in Security OU check."""
|
|
13
|
+
super().__init__(resource_type="AWS::Organizations::Account")
|
|
14
|
+
self.check_id = "SRA-ORGANIZATIONS-09"
|
|
15
|
+
self.check_name = "Log Archive account is in Security OU"
|
|
16
|
+
self.description = (
|
|
17
|
+
"This check verifies that the log archive account is located in the Security organizational unit. "
|
|
18
|
+
"According to AWS SRA best practices, the log archive account should be placed in the Security OU "
|
|
19
|
+
"to ensure proper isolation and governance of centralized logging infrastructure."
|
|
20
|
+
)
|
|
21
|
+
self.severity = "HIGH"
|
|
22
|
+
self.check_logic = (
|
|
23
|
+
"Get the Security OU under the organization root, then list all accounts in the Security OU. "
|
|
24
|
+
"Check passes if the log archive account (provided via --log-archive-account CLI parameter) "
|
|
25
|
+
"is found in the Security OU."
|
|
26
|
+
)
|
|
27
|
+
self._log_archive_accounts = [] # Will be populated from CLI --log-archive-account parameter
|
|
28
|
+
|
|
29
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
30
|
+
"""
|
|
31
|
+
Execute the check.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
List of findings
|
|
35
|
+
"""
|
|
36
|
+
# Organizations is a global service, use "global" as region
|
|
37
|
+
region = "global"
|
|
38
|
+
|
|
39
|
+
# Check if log archive account is provided
|
|
40
|
+
if not self._log_archive_accounts:
|
|
41
|
+
self.findings.append(self.create_finding(
|
|
42
|
+
status="FAIL",
|
|
43
|
+
region=region,
|
|
44
|
+
resource_id=None,
|
|
45
|
+
actual_value="Log archive account ID not provided",
|
|
46
|
+
remediation="Run check with --log-archive-account parameter to specify the log archive account ID",
|
|
47
|
+
checked_value="Log Archive account in Security OU"
|
|
48
|
+
))
|
|
49
|
+
return self.findings
|
|
50
|
+
|
|
51
|
+
# Get organization roots
|
|
52
|
+
roots_response = self.get_roots()
|
|
53
|
+
if "Error" in roots_response:
|
|
54
|
+
error_message = roots_response["Error"].get("Message", "Unknown error")
|
|
55
|
+
self.findings.append(self.create_finding(
|
|
56
|
+
status="ERROR",
|
|
57
|
+
region=region,
|
|
58
|
+
resource_id=None,
|
|
59
|
+
actual_value=f"Error: {error_message}",
|
|
60
|
+
remediation="Check IAM permissions for Organizations API access",
|
|
61
|
+
checked_value="Log Archive account in Security OU"
|
|
62
|
+
))
|
|
63
|
+
return self.findings
|
|
64
|
+
|
|
65
|
+
roots = roots_response.get("Roots", [])
|
|
66
|
+
if not roots:
|
|
67
|
+
self.findings.append(self.create_finding(
|
|
68
|
+
status="ERROR",
|
|
69
|
+
region=region,
|
|
70
|
+
resource_id=None,
|
|
71
|
+
actual_value="No organization root found",
|
|
72
|
+
remediation="Ensure AWS Organizations is enabled and properly configured",
|
|
73
|
+
checked_value="Log Archive account in Security OU"
|
|
74
|
+
))
|
|
75
|
+
return self.findings
|
|
76
|
+
|
|
77
|
+
root = roots[0]
|
|
78
|
+
root_id = root.get("Id", "")
|
|
79
|
+
|
|
80
|
+
# Get OUs under the root to find Security OU
|
|
81
|
+
ous_response = self.get_ous_for_parent(root_id)
|
|
82
|
+
if "Error" in ous_response:
|
|
83
|
+
error_message = ous_response["Error"].get("Message", "Unknown error")
|
|
84
|
+
self.findings.append(self.create_finding(
|
|
85
|
+
status="ERROR",
|
|
86
|
+
region=region,
|
|
87
|
+
resource_id=root_id,
|
|
88
|
+
actual_value=f"Error: {error_message}",
|
|
89
|
+
remediation="Check IAM permissions for Organizations API access",
|
|
90
|
+
checked_value="Log Archive account in Security OU"
|
|
91
|
+
))
|
|
92
|
+
return self.findings
|
|
93
|
+
|
|
94
|
+
ous = ous_response.get("OrganizationalUnits", [])
|
|
95
|
+
|
|
96
|
+
# Find Security OU
|
|
97
|
+
security_ou = None
|
|
98
|
+
for ou in ous:
|
|
99
|
+
if ou.get("Name") == "Security":
|
|
100
|
+
security_ou = ou
|
|
101
|
+
break
|
|
102
|
+
|
|
103
|
+
if not security_ou:
|
|
104
|
+
self.findings.append(self.create_finding(
|
|
105
|
+
status="FAIL",
|
|
106
|
+
region=region,
|
|
107
|
+
resource_id=root_id,
|
|
108
|
+
actual_value="Security OU not found under organization root",
|
|
109
|
+
remediation=(
|
|
110
|
+
"Create a Security organizational unit under the organization root and move the "
|
|
111
|
+
"log archive account into it. Navigate to AWS Organizations in the console, create the "
|
|
112
|
+
"Security OU, then move the log archive account to the Security OU."
|
|
113
|
+
),
|
|
114
|
+
checked_value="Log Archive account in Security OU"
|
|
115
|
+
))
|
|
116
|
+
return self.findings
|
|
117
|
+
|
|
118
|
+
security_ou_id = security_ou.get("Id", "")
|
|
119
|
+
|
|
120
|
+
# Get accounts in Security OU
|
|
121
|
+
accounts_response = self.get_accounts_for_parent(security_ou_id)
|
|
122
|
+
if "Error" in accounts_response:
|
|
123
|
+
error_message = accounts_response["Error"].get("Message", "Unknown error")
|
|
124
|
+
self.findings.append(self.create_finding(
|
|
125
|
+
status="ERROR",
|
|
126
|
+
region=region,
|
|
127
|
+
resource_id=security_ou_id,
|
|
128
|
+
actual_value=f"Error: {error_message}",
|
|
129
|
+
remediation="Check IAM permissions for Organizations API access",
|
|
130
|
+
checked_value="Log Archive account in Security OU"
|
|
131
|
+
))
|
|
132
|
+
return self.findings
|
|
133
|
+
|
|
134
|
+
accounts = accounts_response.get("Accounts", [])
|
|
135
|
+
account_ids_in_security_ou = [acc.get("Id") for acc in accounts]
|
|
136
|
+
|
|
137
|
+
# Check if log archive account(s) are in Security OU
|
|
138
|
+
for log_archive_account_id in self._log_archive_accounts:
|
|
139
|
+
if log_archive_account_id in account_ids_in_security_ou:
|
|
140
|
+
# Find account name for better reporting
|
|
141
|
+
account_name = next(
|
|
142
|
+
(acc.get("Name", "Unknown") for acc in accounts if acc.get("Id") == log_archive_account_id),
|
|
143
|
+
"Unknown"
|
|
144
|
+
)
|
|
145
|
+
self.findings.append(self.create_finding(
|
|
146
|
+
status="PASS",
|
|
147
|
+
region=region,
|
|
148
|
+
resource_id=log_archive_account_id,
|
|
149
|
+
actual_value=f"Log archive account {log_archive_account_id} ({account_name}) is in Security OU",
|
|
150
|
+
remediation="No remediation needed",
|
|
151
|
+
checked_value="Log Archive account in Security OU"
|
|
152
|
+
))
|
|
153
|
+
else:
|
|
154
|
+
self.findings.append(self.create_finding(
|
|
155
|
+
status="FAIL",
|
|
156
|
+
region=region,
|
|
157
|
+
resource_id=log_archive_account_id,
|
|
158
|
+
actual_value=f"Log archive account {log_archive_account_id} is not in Security OU",
|
|
159
|
+
remediation=(
|
|
160
|
+
f"Move the log archive account {log_archive_account_id} to the Security OU. "
|
|
161
|
+
"Navigate to AWS Organizations in the console, select the log archive account, "
|
|
162
|
+
"and move it to the Security OU."
|
|
163
|
+
),
|
|
164
|
+
checked_value="Log Archive account in Security OU"
|
|
165
|
+
))
|
|
166
|
+
|
|
167
|
+
return self.findings
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Organizations client for interacting with AWS Organizations service.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, List, Optional, Any
|
|
5
|
+
import boto3
|
|
6
|
+
from botocore.exceptions import ClientError
|
|
7
|
+
from sraverify.core.logging import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OrganizationsClient:
|
|
11
|
+
"""Client for interacting with AWS Organizations service."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, session: Optional[boto3.Session] = None):
|
|
14
|
+
"""
|
|
15
|
+
Initialize Organizations client.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
session: AWS session to use (if None, a new session will be created)
|
|
19
|
+
"""
|
|
20
|
+
self.session = session or boto3.Session()
|
|
21
|
+
# Organizations is a global service, always use us-east-1
|
|
22
|
+
self.client = self.session.client('organizations', region_name='us-east-1')
|
|
23
|
+
|
|
24
|
+
def describe_organization(self) -> Dict[str, Any]:
|
|
25
|
+
"""
|
|
26
|
+
Get organization details.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Dictionary with Organization key containing organization details,
|
|
30
|
+
or Error key if an error occurred.
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
response = self.client.describe_organization()
|
|
34
|
+
return response
|
|
35
|
+
except ClientError as e:
|
|
36
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
37
|
+
error_message = e.response.get('Error', {}).get('Message', str(e))
|
|
38
|
+
logger.error(f"Error describing organization: {error_message}")
|
|
39
|
+
return {
|
|
40
|
+
"Error": {
|
|
41
|
+
"Code": error_code,
|
|
42
|
+
"Message": error_message
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def list_roots(self) -> Dict[str, Any]:
|
|
47
|
+
"""
|
|
48
|
+
List organization roots with pagination support.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Dictionary with Roots key containing list of roots,
|
|
52
|
+
or Error key if an error occurred.
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
roots = []
|
|
56
|
+
paginator = self.client.get_paginator('list_roots')
|
|
57
|
+
for page in paginator.paginate():
|
|
58
|
+
roots.extend(page.get('Roots', []))
|
|
59
|
+
return {"Roots": roots}
|
|
60
|
+
except ClientError as e:
|
|
61
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
62
|
+
error_message = e.response.get('Error', {}).get('Message', str(e))
|
|
63
|
+
logger.error(f"Error listing roots: {error_message}")
|
|
64
|
+
return {
|
|
65
|
+
"Error": {
|
|
66
|
+
"Code": error_code,
|
|
67
|
+
"Message": error_message
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
def list_organizational_units_for_parent(self, parent_id: str) -> Dict[str, Any]:
|
|
72
|
+
"""
|
|
73
|
+
List organizational units under a parent with pagination support.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
parent_id: The ID of the parent root or OU
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Dictionary with OrganizationalUnits key containing list of OUs,
|
|
80
|
+
or Error key if an error occurred.
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
ous = []
|
|
84
|
+
paginator = self.client.get_paginator('list_organizational_units_for_parent')
|
|
85
|
+
for page in paginator.paginate(ParentId=parent_id):
|
|
86
|
+
ous.extend(page.get('OrganizationalUnits', []))
|
|
87
|
+
return {"OrganizationalUnits": ous}
|
|
88
|
+
except ClientError as e:
|
|
89
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
90
|
+
error_message = e.response.get('Error', {}).get('Message', str(e))
|
|
91
|
+
logger.error(f"Error listing OUs for parent {parent_id}: {error_message}")
|
|
92
|
+
return {
|
|
93
|
+
"Error": {
|
|
94
|
+
"Code": error_code,
|
|
95
|
+
"Message": error_message
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
def list_policies(self, policy_type: str = "SERVICE_CONTROL_POLICY") -> Dict[str, Any]:
|
|
100
|
+
"""
|
|
101
|
+
List policies by type with pagination support.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
policy_type: Type of policy to list (default: SERVICE_CONTROL_POLICY)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Dictionary with Policies key containing list of policies,
|
|
108
|
+
or Error key if an error occurred.
|
|
109
|
+
"""
|
|
110
|
+
try:
|
|
111
|
+
policies = []
|
|
112
|
+
paginator = self.client.get_paginator('list_policies')
|
|
113
|
+
for page in paginator.paginate(Filter=policy_type):
|
|
114
|
+
policies.extend(page.get('Policies', []))
|
|
115
|
+
return {"Policies": policies}
|
|
116
|
+
except ClientError as e:
|
|
117
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
118
|
+
error_message = e.response.get('Error', {}).get('Message', str(e))
|
|
119
|
+
logger.error(f"Error listing policies of type {policy_type}: {error_message}")
|
|
120
|
+
return {
|
|
121
|
+
"Error": {
|
|
122
|
+
"Code": error_code,
|
|
123
|
+
"Message": error_message
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
def list_accounts_for_parent(self, parent_id: str) -> Dict[str, Any]:
|
|
128
|
+
"""
|
|
129
|
+
List accounts under a parent (root or OU) with pagination support.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
parent_id: The ID of the parent root or OU
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Dictionary with Accounts key containing list of accounts,
|
|
136
|
+
or Error key if an error occurred.
|
|
137
|
+
"""
|
|
138
|
+
try:
|
|
139
|
+
accounts = []
|
|
140
|
+
paginator = self.client.get_paginator('list_accounts_for_parent')
|
|
141
|
+
for page in paginator.paginate(ParentId=parent_id):
|
|
142
|
+
accounts.extend(page.get('Accounts', []))
|
|
143
|
+
return {"Accounts": accounts}
|
|
144
|
+
except ClientError as e:
|
|
145
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
146
|
+
error_message = e.response.get('Error', {}).get('Message', str(e))
|
|
147
|
+
logger.error(f"Error listing accounts for parent {parent_id}: {error_message}")
|
|
148
|
+
return {
|
|
149
|
+
"Error": {
|
|
150
|
+
"Code": error_code,
|
|
151
|
+
"Message": error_message
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
sraverify/__init__.py,sha256=6gfuKM0QW6xcFPeN782mbPiCK8PEolaXL05Mbdli32Y,1201
|
|
2
|
-
sraverify/main.py,sha256=
|
|
2
|
+
sraverify/main.py,sha256=Ohfe-jymToqLpdsMnDm_q73MwQ-5DnkEU4cd98aczHI,14461
|
|
3
3
|
sraverify/checks/__init__.py,sha256=I12r97y4IJH00Y2yUgxK_VJn1eANva19v0FMdydnGvA,2033
|
|
4
4
|
sraverify/checks/accessanalyzer/SRA_IAA_1.py,sha256=hsVfgo-ia7uvNs4PNdk2ikTAxVUOmViQ8KeTJXJ7Ljg,8205
|
|
5
5
|
sraverify/checks/accessanalyzer/SRA_IAA_2.py,sha256=mcDEhQdqu4w9e_Egdtcc0iTKHSnpm4VMf_R559Wi5pQ,8251
|
|
@@ -24,7 +24,7 @@ sraverify/checks/config/SRA-CONFIG-1.py,sha256=DT2Nce99vFHBuFjVDyLYQc2VCcBmziXlj
|
|
|
24
24
|
sraverify/checks/config/__init__.py,sha256=ZcR-cj0dQNGFi_TKwOREXGr3Onju9VtFsds8rtbBg6s,55
|
|
25
25
|
sraverify/core/__init__.py,sha256=zoDY1Q-oGF9IVGD5f07yJ4d1KuWKQq3IqEDmetOFdok,54
|
|
26
26
|
sraverify/core/check.py,sha256=MDjjHV3mFYprEeHCEadzme3A0UHUpLEbLJ4wGpi0rSU,8559
|
|
27
|
-
sraverify/core/logging.py,sha256=
|
|
27
|
+
sraverify/core/logging.py,sha256=xG7ySsfu45IEApS1nLMn118iXdt-pOJyM-d7y4AofWA,2329
|
|
28
28
|
sraverify/core/session.py,sha256=vbLyGEhFJ8thU9BHgN80MexZLoJMKlZDFIcGwKECblo,1507
|
|
29
29
|
sraverify/lib/__init__.py,sha256=ENiW27PYy5d_2BeoIxdxckFmW9KcrVX1dp97smmVx0c,55
|
|
30
30
|
sraverify/lib/audit_info.py,sha256=c6O4I9mJFjxzHFLROQ_1PcR0lQmT_tA0JQMtCNUlS2s,1553
|
|
@@ -164,6 +164,19 @@ sraverify/services/macie/checks/sra_macie_07.py,sha256=QMNS6lds_9yzM3IAwVUBM0utG
|
|
|
164
164
|
sraverify/services/macie/checks/sra_macie_08.py,sha256=2CX2r8JZ58OgkpO2VpCtA32mtsItxbRRC-8k2NQuiN8,3631
|
|
165
165
|
sraverify/services/macie/checks/sra_macie_09.py,sha256=ivKtS2ZX9AfpJ4iQyie1f5bM_Y0FolnWM2zppilLNw0,4701
|
|
166
166
|
sraverify/services/macie/checks/sra_macie_10.py,sha256=CpsIR43yxXtcEOo0NdlTUdSZSa_2g-jSSQ_Y6on5biM,3406
|
|
167
|
+
sraverify/services/organizations/__init__.py,sha256=CSnyU3J9e985U7W4HSAHwQA2Q5UXzxjEhCALzKpxcRE,1402
|
|
168
|
+
sraverify/services/organizations/base.py,sha256=BWR656oIIhvSCnSMRb6GUWfvo7BAaXpLGwxIG30VWAM,6578
|
|
169
|
+
sraverify/services/organizations/client.py,sha256=xyIm34ei5jRtSMxLPInGLSjzutryiu_xpKCm8wy_KB4,5860
|
|
170
|
+
sraverify/services/organizations/checks/__init__.py,sha256=y6QCfZhmcKUPml_LUuIiDOiAFjwKr4Bibog9JxPxazQ,58
|
|
171
|
+
sraverify/services/organizations/checks/sra_organizations_01.py,sha256=lOvLU7f0FL54R6DEnf5trjVEfq8s1ZYcpqYWtarmdgA,3410
|
|
172
|
+
sraverify/services/organizations/checks/sra_organizations_02.py,sha256=ntDmc2MXmCyLgC8S-AxTh-g5t5-q-Yd5PMRZHoc6HOA,5090
|
|
173
|
+
sraverify/services/organizations/checks/sra_organizations_03.py,sha256=QpRwu1_hidgDnhVJvOcrozSGsEZe8XB0gGP8Fe1vFcQ,5143
|
|
174
|
+
sraverify/services/organizations/checks/sra_organizations_04.py,sha256=GNmORLBislFj85JQveiLwpKPSP8NzeuPdJ5hq18mei8,5029
|
|
175
|
+
sraverify/services/organizations/checks/sra_organizations_05.py,sha256=hxXky9D4aclvf3jb3SfchYPwvT6TiV1YUr0uqjx00nk,3814
|
|
176
|
+
sraverify/services/organizations/checks/sra_organizations_06.py,sha256=tZ5kaH5eBsJKaSo7BUdvjndlR08eX9BZf3L8PDOtERM,5622
|
|
177
|
+
sraverify/services/organizations/checks/sra_organizations_07.py,sha256=YG1KwupIGFp2Vw1amt4QIk992OZOsg4GF6ALUnjpKC0,5965
|
|
178
|
+
sraverify/services/organizations/checks/sra_organizations_08.py,sha256=-atpxnq6lSoH8qE50Drpl7Qh-W2BV0rEJBTWU5k5QL8,7120
|
|
179
|
+
sraverify/services/organizations/checks/sra_organizations_09.py,sha256=rAM3m8bNpkK7Bz0R4W6SWbXkAKGM0f5gmX7AGvRMvKk,7345
|
|
167
180
|
sraverify/services/s3/__init__.py,sha256=x0vB4X1I_b66RlKfcJDn7ZvIoTywySHK0vWBvoLDcyY,417
|
|
168
181
|
sraverify/services/s3/base.py,sha256=-3czNyp2vZ_HKQ3xh6gtAG9AHnPpxtDTaIA1OF1I1BQ,2542
|
|
169
182
|
sraverify/services/s3/client.py,sha256=acd3YlcK-FyIvdAg5obcqHG2HdGbJk8WO0BwYHrHvCc,2146
|
|
@@ -252,10 +265,10 @@ sraverify/utils/__init__.py,sha256=IjhsKkC2WOXrINnNksrNX69R5XwTCTO6gVlLkv_guxQ,5
|
|
|
252
265
|
sraverify/utils/banner.py,sha256=zMLBKuw7G8mielJeMXXPaAMnwKy6CpapX-1GVfKyux8,2756
|
|
253
266
|
sraverify/utils/outputs.py,sha256=HlEuy21RgrcTuRjWkFDfrY6GfO1DNVzGMBLOxvemjek,1721
|
|
254
267
|
sraverify/utils/progress.py,sha256=B_Dhaep3inav3SC1ZpKPcH74tgJqf6wmY2ILzAGbOeU,3190
|
|
255
|
-
sraverify-0.1.
|
|
256
|
-
sraverify-0.1.
|
|
257
|
-
sraverify-0.1.
|
|
258
|
-
sraverify-0.1.
|
|
259
|
-
sraverify-0.1.
|
|
260
|
-
sraverify-0.1.
|
|
261
|
-
sraverify-0.1.
|
|
268
|
+
sraverify-0.1.3.dist-info/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
|
|
269
|
+
sraverify-0.1.3.dist-info/METADATA,sha256=kS1he0LIztFx0s2qXGVkfbC2L9FleVFFzD-BW3ka6gk,17007
|
|
270
|
+
sraverify-0.1.3.dist-info/NOTICE,sha256=1CkO1kwu3Q_OHYTj-d-yiBJA_lNN73a4zSntavaD4oc,67
|
|
271
|
+
sraverify-0.1.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
272
|
+
sraverify-0.1.3.dist-info/entry_points.txt,sha256=lewX6FKnqbko4m2xq4N_UiJbzSrghnjoZyD1YdBmoO8,50
|
|
273
|
+
sraverify-0.1.3.dist-info/top_level.txt,sha256=dqkttmF4ZzAyRMF2tDxRuIvDZGjyVIoV9eDqK5sMzYM,10
|
|
274
|
+
sraverify-0.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|