regscale-cli 6.21.0.0__py3-none-any.whl → 6.21.2.0__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.
- regscale/_version.py +1 -1
- regscale/core/app/application.py +7 -0
- regscale/integrations/commercial/__init__.py +9 -10
- regscale/integrations/commercial/amazon/common.py +79 -2
- regscale/integrations/commercial/aws/cli.py +183 -9
- regscale/integrations/commercial/aws/scanner.py +544 -9
- regscale/integrations/commercial/cpe.py +18 -1
- regscale/integrations/commercial/import_all/import_all_cmd.py +2 -2
- regscale/integrations/commercial/microsoft_defender/__init__.py +0 -0
- regscale/integrations/commercial/{defender.py → microsoft_defender/defender.py} +38 -612
- regscale/integrations/commercial/microsoft_defender/defender_api.py +286 -0
- regscale/integrations/commercial/microsoft_defender/defender_constants.py +80 -0
- regscale/integrations/commercial/microsoft_defender/defender_scanner.py +168 -0
- regscale/integrations/commercial/qualys/__init__.py +24 -86
- regscale/integrations/commercial/qualys/containers.py +2 -0
- regscale/integrations/commercial/qualys/scanner.py +7 -2
- regscale/integrations/commercial/sonarcloud.py +110 -71
- regscale/integrations/commercial/tenablev2/jsonl_scanner.py +2 -1
- regscale/integrations/commercial/wizv2/async_client.py +10 -3
- regscale/integrations/commercial/wizv2/click.py +105 -26
- regscale/integrations/commercial/wizv2/constants.py +249 -1
- regscale/integrations/commercial/wizv2/data_fetcher.py +401 -0
- regscale/integrations/commercial/wizv2/finding_processor.py +295 -0
- regscale/integrations/commercial/wizv2/issue.py +2 -2
- regscale/integrations/commercial/wizv2/parsers.py +3 -2
- regscale/integrations/commercial/wizv2/policy_compliance.py +3057 -0
- regscale/integrations/commercial/wizv2/policy_compliance_helpers.py +564 -0
- regscale/integrations/commercial/wizv2/scanner.py +19 -25
- regscale/integrations/commercial/wizv2/utils.py +258 -85
- regscale/integrations/commercial/wizv2/variables.py +4 -3
- regscale/integrations/compliance_integration.py +1607 -0
- regscale/integrations/public/fedramp/fedramp_five.py +93 -8
- regscale/integrations/public/fedramp/markdown_parser.py +7 -1
- regscale/integrations/scanner_integration.py +57 -6
- regscale/models/__init__.py +1 -1
- regscale/models/app_models/__init__.py +1 -0
- regscale/models/integration_models/cisa_kev_data.json +103 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/{integrations/commercial/wizv2/models.py → models/integration_models/wizv2.py} +4 -12
- regscale/models/regscale_models/file.py +4 -0
- regscale/models/regscale_models/issue.py +151 -8
- regscale/models/regscale_models/regscale_model.py +4 -2
- regscale/models/regscale_models/security_plan.py +1 -1
- regscale/utils/graphql_client.py +3 -1
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.2.0.dist-info}/METADATA +9 -9
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.2.0.dist-info}/RECORD +52 -44
- tests/regscale/core/test_version_regscale.py +5 -3
- tests/regscale/integrations/test_wiz_policy_compliance_affected_controls.py +154 -0
- tests/regscale/test_authorization.py +0 -65
- tests/regscale/test_init.py +0 -96
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.2.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.2.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.2.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
3
|
+
"""Wiz v2 Integration Models (RegScale pattern)."""
|
|
4
4
|
|
|
5
|
-
# standard python imports
|
|
6
5
|
from enum import Enum
|
|
7
6
|
from typing import Optional
|
|
7
|
+
from datetime import datetime
|
|
8
8
|
|
|
9
9
|
from pydantic import BaseModel, Field
|
|
10
|
-
from datetime import datetime
|
|
11
10
|
|
|
12
11
|
from regscale.models import regscale_models
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class AssetCategory(Enum):
|
|
16
|
-
"""Map Wiz assetTypes with RegScale assetCategories"""
|
|
15
|
+
"""Map Wiz assetTypes with RegScale assetCategories."""
|
|
17
16
|
|
|
18
17
|
SERVICE_USAGE_TECHNOLOGY = regscale_models.AssetCategory.Hardware
|
|
19
18
|
GATEWAY = regscale_models.AssetCategory.Hardware
|
|
@@ -90,6 +89,7 @@ class ComplianceReport(BaseModel):
|
|
|
90
89
|
control_id: Optional[str] = Field(None, alias="Control ID")
|
|
91
90
|
compliance_check: Optional[str] = Field(None, alias="Compliance Check Name (Wiz Subcategory)")
|
|
92
91
|
control_description: Optional[str] = Field(None, alias="Control Description")
|
|
92
|
+
issue_finding_id: Optional[str] = Field(None, alias="Issue/Finding ID")
|
|
93
93
|
severity: Optional[str] = Field(None, alias="Severity")
|
|
94
94
|
result: str = Field(..., alias="Result")
|
|
95
95
|
framework: Optional[str] = Field(None, alias="Framework")
|
|
@@ -102,11 +102,3 @@ class ComplianceReport(BaseModel):
|
|
|
102
102
|
resource_id: str = Field(..., alias="Resource ID")
|
|
103
103
|
resource_region: Optional[str] = Field(None, alias="Resource Region")
|
|
104
104
|
resource_cloud_platform: Optional[str] = Field(None, alias="Resource Cloud Platform")
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
# # Attempt to create an instance of the model again
|
|
108
|
-
# example_row = data.iloc[0].to_dict()
|
|
109
|
-
# example_compliance_report = ComplianceReport(**example_row)
|
|
110
|
-
#
|
|
111
|
-
# # Display the instance
|
|
112
|
-
# example_compliance_report.dict()
|
|
@@ -375,6 +375,10 @@ class File(BaseModel):
|
|
|
375
375
|
except KeyError:
|
|
376
376
|
if file_type == ".xlsx":
|
|
377
377
|
file_type_header = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
378
|
+
elif file_type == ".docx":
|
|
379
|
+
file_type_header = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
380
|
+
elif file_type == ".pptx":
|
|
381
|
+
file_type_header = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
378
382
|
elif file_type == ".nessus":
|
|
379
383
|
file_type_header = "text/xml"
|
|
380
384
|
elif file_type == ".gz":
|
|
@@ -447,8 +447,9 @@ class Issue(RegScaleModel):
|
|
|
447
447
|
return "High"
|
|
448
448
|
return ""
|
|
449
449
|
|
|
450
|
-
@
|
|
450
|
+
@classmethod
|
|
451
451
|
def get_due_date(
|
|
452
|
+
cls,
|
|
452
453
|
severity: Union[IssueSeverity, str],
|
|
453
454
|
config: dict,
|
|
454
455
|
key: str,
|
|
@@ -481,18 +482,37 @@ class Issue(RegScaleModel):
|
|
|
481
482
|
severity = IssueSeverity.NotAssigned.value
|
|
482
483
|
|
|
483
484
|
if severity == IssueSeverity.Critical.value:
|
|
484
|
-
days =
|
|
485
|
+
days = cls._get_days_for_values(["critical"], config, key)
|
|
486
|
+
start_date = start_date + datetime.timedelta(days=days)
|
|
485
487
|
elif severity == IssueSeverity.High.value:
|
|
486
|
-
days =
|
|
488
|
+
days = cls._get_days_for_values(["high"], config, key)
|
|
487
489
|
elif severity == IssueSeverity.Moderate.value:
|
|
488
|
-
days =
|
|
490
|
+
days = cls._get_days_for_values(["moderate", "medium"], config, key)
|
|
489
491
|
elif severity == IssueSeverity.Low.value:
|
|
490
|
-
days =
|
|
492
|
+
days = cls._get_days_for_values(["low", "minor"], config, key)
|
|
491
493
|
else:
|
|
492
494
|
days = 60
|
|
493
495
|
due_date = start_date + datetime.timedelta(days=days)
|
|
494
496
|
return due_date.strftime(dt_format)
|
|
495
497
|
|
|
498
|
+
@staticmethod
|
|
499
|
+
def _get_days_for_values(possible_values: List[str], config: dict, key: str, default: Optional[int] = 30) -> int:
|
|
500
|
+
"""
|
|
501
|
+
Get the number of days for the given possible values from the configuration.
|
|
502
|
+
|
|
503
|
+
:param List[str] possible_values: List of possible values to check
|
|
504
|
+
:param dict config: Application config
|
|
505
|
+
:param str key: The key to use for init.yaml from the issues section to determine the due date
|
|
506
|
+
:param Optional[int] default: Default number of days to return if no values match, defaults to 30
|
|
507
|
+
:return: Number of days for the first matching value, or 0 if none match
|
|
508
|
+
:rtype: int
|
|
509
|
+
"""
|
|
510
|
+
for value in possible_values:
|
|
511
|
+
days = config["issues"].get(key, {}).get(value, 0)
|
|
512
|
+
if days > 0:
|
|
513
|
+
return days
|
|
514
|
+
return default
|
|
515
|
+
|
|
496
516
|
@staticmethod
|
|
497
517
|
def assign_severity(value: Optional[Any] = None) -> str:
|
|
498
518
|
"""
|
|
@@ -518,11 +538,11 @@ class Issue(RegScaleModel):
|
|
|
518
538
|
else:
|
|
519
539
|
severity = severity_levels["low"]
|
|
520
540
|
elif isinstance(value, str):
|
|
521
|
-
if value.lower() in ["low", "lowest"]:
|
|
541
|
+
if value.lower() in ["low", "lowest", "minor"]:
|
|
522
542
|
severity = severity_levels["low"]
|
|
523
|
-
elif value.lower() in ["medium", "moderate"]:
|
|
543
|
+
elif value.lower() in ["medium", "moderate", "major"]:
|
|
524
544
|
severity = severity_levels["moderate"]
|
|
525
|
-
elif value.lower() in ["high", "critical", "highest"]:
|
|
545
|
+
elif value.lower() in ["high", "critical", "highest", "critical", "blocker"]:
|
|
526
546
|
severity = severity_levels["high"]
|
|
527
547
|
elif value in list(severity_levels.values()):
|
|
528
548
|
severity = value
|
|
@@ -1270,6 +1290,129 @@ class Issue(RegScaleModel):
|
|
|
1270
1290
|
raise ValueError(f"riskAdjustment must be one of {allowed_values}")
|
|
1271
1291
|
return v
|
|
1272
1292
|
|
|
1293
|
+
# New method to determine and set isPoam based on NIST/FedRAMP criteria
|
|
1294
|
+
def set_is_poam(
|
|
1295
|
+
self,
|
|
1296
|
+
config: Optional[Dict[str, Any]] = None,
|
|
1297
|
+
standard: str = "fedramp",
|
|
1298
|
+
current_date: Optional[datetime.datetime] = None,
|
|
1299
|
+
) -> None:
|
|
1300
|
+
"""
|
|
1301
|
+
Sets the isPoam field based on NIST 800-53 or FedRAMP criteria, preserving historical POAM status.
|
|
1302
|
+
|
|
1303
|
+
Criteria:
|
|
1304
|
+
- Preserves isPoam=True for imported data, even if closed, for reporting purposes.
|
|
1305
|
+
- For new issues:
|
|
1306
|
+
- Skips if false positive, operational requirement, or deviation rationale exists.
|
|
1307
|
+
- FedRAMP: High/Critical issues are POAMs if open; scan-based issues are POAMs if overdue; non-scan issues are POAMs if open.
|
|
1308
|
+
- NIST: POAM for any open deficiency unless accepted as residual risk.
|
|
1309
|
+
- Uses config thresholds (e.g., {'critical': 30, 'high': 90, 'medium': 90, 'low': 365, 'status': 'Open'}).
|
|
1310
|
+
|
|
1311
|
+
Args:
|
|
1312
|
+
config: Optional dictionary with severity thresholds and status from init.yaml.
|
|
1313
|
+
Defaults to FedRAMP: {'critical': 30, 'high': 30, 'medium': 90, 'low': 180, 'status': 'Open'}.
|
|
1314
|
+
For NIST, uses {'critical': 30, 'high': 90, 'medium': 90, 'low': 180, 'status': 'Open'}.
|
|
1315
|
+
standard: 'fedramp' (default) or 'nist'.
|
|
1316
|
+
current_date: Optional datetime for calculation (defaults to current time).
|
|
1317
|
+
|
|
1318
|
+
Returns:
|
|
1319
|
+
None: Sets the isPoam attribute directly.
|
|
1320
|
+
"""
|
|
1321
|
+
# Use current time if not provided
|
|
1322
|
+
current_date = current_date or datetime.datetime.now()
|
|
1323
|
+
|
|
1324
|
+
# Preserve historical POAM status for imported data
|
|
1325
|
+
if self.isPoam:
|
|
1326
|
+
return
|
|
1327
|
+
|
|
1328
|
+
# Define open statuses
|
|
1329
|
+
open_statuses = {
|
|
1330
|
+
IssueStatus.Open,
|
|
1331
|
+
IssueStatus.Delayed,
|
|
1332
|
+
IssueStatus.PendingVerification,
|
|
1333
|
+
IssueStatus.VendorDependency,
|
|
1334
|
+
IssueStatus.PendingApproval,
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
# Skip if issue is accepted as residual risk
|
|
1338
|
+
if self.falsePositive or self.operationalRequirement or self.deviationRationale:
|
|
1339
|
+
self.isPoam = False
|
|
1340
|
+
return
|
|
1341
|
+
|
|
1342
|
+
# Load default thresholds based on standard if config is not provided
|
|
1343
|
+
config = config or (
|
|
1344
|
+
{"critical": 30, "high": 30, "medium": 90, "low": 180, "status": "Open"}
|
|
1345
|
+
if standard == "fedramp"
|
|
1346
|
+
else {"critical": 30, "high": 90, "medium": 90, "low": 180, "status": "Open"}
|
|
1347
|
+
)
|
|
1348
|
+
|
|
1349
|
+
# Map severity to remediation days
|
|
1350
|
+
severity_map = {
|
|
1351
|
+
IssueSeverity.Critical: config.get("critical", 30),
|
|
1352
|
+
IssueSeverity.High: config.get("high", 90),
|
|
1353
|
+
IssueSeverity.Moderate: config.get("medium", 90),
|
|
1354
|
+
IssueSeverity.Low: config.get("low", 365),
|
|
1355
|
+
IssueSeverity.NotAssigned: config.get("low", 365),
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
# Normalize severity
|
|
1359
|
+
severity = (
|
|
1360
|
+
IssueSeverity(self.severityLevel)
|
|
1361
|
+
if self.severityLevel in {s.value for s in IssueSeverity}
|
|
1362
|
+
else IssueSeverity.NotAssigned
|
|
1363
|
+
)
|
|
1364
|
+
threshold_days = severity_map[severity]
|
|
1365
|
+
|
|
1366
|
+
# Get detection date
|
|
1367
|
+
detection_date_str = self.dateFirstDetected or self.dateCreated
|
|
1368
|
+
if not detection_date_str:
|
|
1369
|
+
self.isPoam = False
|
|
1370
|
+
return
|
|
1371
|
+
|
|
1372
|
+
try:
|
|
1373
|
+
detection_date = datetime.datetime.strptime(detection_date_str, "%Y-%m-%dT%H:%M:%S")
|
|
1374
|
+
except ValueError:
|
|
1375
|
+
try:
|
|
1376
|
+
detection_date = datetime.datetime.strptime(detection_date_str, "%Y-%m-%d")
|
|
1377
|
+
except ValueError:
|
|
1378
|
+
self.isPoam = False
|
|
1379
|
+
return
|
|
1380
|
+
|
|
1381
|
+
days_since_detection = (current_date - detection_date).days
|
|
1382
|
+
|
|
1383
|
+
# Define scan sources
|
|
1384
|
+
scan_sources = {"Vulnerability Assessment", "FDCC/USGCB", "Penetration Test"}
|
|
1385
|
+
is_scan = self.identification in scan_sources
|
|
1386
|
+
|
|
1387
|
+
# Apply standard-specific logic
|
|
1388
|
+
if standard == "fedramp":
|
|
1389
|
+
# FedRAMP: High/Critical are always POAMs if open
|
|
1390
|
+
if severity in {IssueSeverity.High, IssueSeverity.Critical}:
|
|
1391
|
+
self.isPoam = self.status in open_statuses
|
|
1392
|
+
# Scan-based: POAM if overdue
|
|
1393
|
+
elif is_scan:
|
|
1394
|
+
self.isPoam = days_since_detection > threshold_days
|
|
1395
|
+
# Non-scan: POAM if open
|
|
1396
|
+
else:
|
|
1397
|
+
self.isPoam = self.status in open_statuses
|
|
1398
|
+
|
|
1399
|
+
# Handle vendor dependencies
|
|
1400
|
+
if self.vendorDependency and self.vendorLastUpdate:
|
|
1401
|
+
try:
|
|
1402
|
+
vendor_date = datetime.datetime.strptime(self.vendorLastUpdate, "%Y-%m-%dT%H:%M:%S")
|
|
1403
|
+
days_since_vendor = (current_date - vendor_date).days
|
|
1404
|
+
self.isPoam = days_since_vendor > threshold_days
|
|
1405
|
+
except ValueError:
|
|
1406
|
+
pass # Fall back to detection date logic
|
|
1407
|
+
|
|
1408
|
+
else: # NIST 800-53
|
|
1409
|
+
# NIST: POAM for any open deficiency
|
|
1410
|
+
self.isPoam = self.status in open_statuses
|
|
1411
|
+
|
|
1412
|
+
# Apply status filter from config if specified
|
|
1413
|
+
if "status" in config:
|
|
1414
|
+
self.isPoam = self.isPoam and self.status == config["status"]
|
|
1415
|
+
|
|
1273
1416
|
|
|
1274
1417
|
def build_issue_dict_from_query(a: Dict[str, Any]) -> Dict[str, Any]:
|
|
1275
1418
|
"""
|
|
@@ -1279,7 +1279,9 @@ class RegScaleModel(BaseModel, ABC):
|
|
|
1279
1279
|
exc_info=True,
|
|
1280
1280
|
)
|
|
1281
1281
|
if response and not response.ok:
|
|
1282
|
-
logger.error(
|
|
1282
|
+
logger.error(
|
|
1283
|
+
f"Response Error: Code #{response.status_code}: {response.reason}\n{response.text}", exc_info=True
|
|
1284
|
+
)
|
|
1283
1285
|
if response is None:
|
|
1284
1286
|
error_msg = "Response was None"
|
|
1285
1287
|
logger.error(error_msg)
|
|
@@ -1522,7 +1524,7 @@ class RegScaleModel(BaseModel, ABC):
|
|
|
1522
1524
|
:return: A list of objects
|
|
1523
1525
|
:rtype: List[T]
|
|
1524
1526
|
"""
|
|
1525
|
-
response = cls._get_api_handler().get(endpoint=cls.get_endpoint("list"))
|
|
1527
|
+
response = cls._get_api_handler().get(endpoint=cls.get_endpoint("list").format(module_slug=cls._module_slug))
|
|
1526
1528
|
if response.ok:
|
|
1527
1529
|
return cast(List[T], [cls.get_object(object_id=sp["id"]) for sp in response.json()])
|
|
1528
1530
|
else:
|
regscale/utils/graphql_client.py
CHANGED
|
@@ -5,6 +5,8 @@ A module for making paginated GraphQL queries.
|
|
|
5
5
|
import logging
|
|
6
6
|
from typing import List, Dict, Optional, Any
|
|
7
7
|
|
|
8
|
+
import graphql
|
|
9
|
+
|
|
8
10
|
from regscale.core.app.utils.app_utils import create_progress_object, error_and_exit
|
|
9
11
|
|
|
10
12
|
logger = logging.getLogger(__name__)
|
|
@@ -90,7 +92,7 @@ class PaginatedGraphQLClient:
|
|
|
90
92
|
return result
|
|
91
93
|
except Exception as e:
|
|
92
94
|
logger.error(f"An error occurred while executing the query: {str(e)}", exc_info=True)
|
|
93
|
-
logger.error(f"Query: {self.query}")
|
|
95
|
+
logger.error(f"Query: {graphql.print_ast(self.query)}")
|
|
94
96
|
error_and_exit(f"Variable: {variables}")
|
|
95
97
|
|
|
96
98
|
def fetch_results(self, variables: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: regscale-cli
|
|
3
|
-
Version: 6.21.
|
|
3
|
+
Version: 6.21.2.0
|
|
4
4
|
Summary: Command Line Interface (CLI) for bulk processing/loading data into RegScale
|
|
5
5
|
Home-page: https://github.com/RegScale/regscale-cli
|
|
6
6
|
Author: Travis Howerton
|
|
@@ -56,7 +56,7 @@ Requires-Dist: pydantic ~=2.11.0
|
|
|
56
56
|
Requires-Dist: pypandoc
|
|
57
57
|
Requires-Dist: pypandoc-binary
|
|
58
58
|
Requires-Dist: pytest
|
|
59
|
-
Requires-Dist: python-dateutil ~=2.
|
|
59
|
+
Requires-Dist: python-dateutil ~=2.9.0
|
|
60
60
|
Requires-Dist: python-docx
|
|
61
61
|
Requires-Dist: python-jwt ==4.1.0
|
|
62
62
|
Requires-Dist: pyxnat ==1.5.*
|
|
@@ -137,7 +137,7 @@ Requires-Dist: pydantic ~=2.11.0 ; extra == 'airflow'
|
|
|
137
137
|
Requires-Dist: pypandoc ; extra == 'airflow'
|
|
138
138
|
Requires-Dist: pypandoc-binary ; extra == 'airflow'
|
|
139
139
|
Requires-Dist: pytest ; extra == 'airflow'
|
|
140
|
-
Requires-Dist: python-dateutil ~=2.
|
|
140
|
+
Requires-Dist: python-dateutil ~=2.9.0 ; extra == 'airflow'
|
|
141
141
|
Requires-Dist: python-docx ; extra == 'airflow'
|
|
142
142
|
Requires-Dist: python-jwt ==4.1.0 ; extra == 'airflow'
|
|
143
143
|
Requires-Dist: pyxnat ==1.5.* ; extra == 'airflow'
|
|
@@ -222,7 +222,7 @@ Requires-Dist: pydantic ~=2.11.0 ; extra == 'airflow-azure'
|
|
|
222
222
|
Requires-Dist: pypandoc ; extra == 'airflow-azure'
|
|
223
223
|
Requires-Dist: pypandoc-binary ; extra == 'airflow-azure'
|
|
224
224
|
Requires-Dist: pytest ; extra == 'airflow-azure'
|
|
225
|
-
Requires-Dist: python-dateutil ~=2.
|
|
225
|
+
Requires-Dist: python-dateutil ~=2.9.0 ; extra == 'airflow-azure'
|
|
226
226
|
Requires-Dist: python-docx ; extra == 'airflow-azure'
|
|
227
227
|
Requires-Dist: python-jwt ==4.1.0 ; extra == 'airflow-azure'
|
|
228
228
|
Requires-Dist: pyxnat ==1.5.* ; extra == 'airflow-azure'
|
|
@@ -307,7 +307,7 @@ Requires-Dist: pyodbc ; extra == 'airflow-sqlserver'
|
|
|
307
307
|
Requires-Dist: pypandoc ; extra == 'airflow-sqlserver'
|
|
308
308
|
Requires-Dist: pypandoc-binary ; extra == 'airflow-sqlserver'
|
|
309
309
|
Requires-Dist: pytest ; extra == 'airflow-sqlserver'
|
|
310
|
-
Requires-Dist: python-dateutil ~=2.
|
|
310
|
+
Requires-Dist: python-dateutil ~=2.9.0 ; extra == 'airflow-sqlserver'
|
|
311
311
|
Requires-Dist: python-docx ; extra == 'airflow-sqlserver'
|
|
312
312
|
Requires-Dist: python-jwt ==4.1.0 ; extra == 'airflow-sqlserver'
|
|
313
313
|
Requires-Dist: pyxnat ==1.5.* ; extra == 'airflow-sqlserver'
|
|
@@ -397,7 +397,7 @@ Requires-Dist: pydantic ~=2.11.0 ; extra == 'all'
|
|
|
397
397
|
Requires-Dist: pypandoc ; extra == 'all'
|
|
398
398
|
Requires-Dist: pypandoc-binary ; extra == 'all'
|
|
399
399
|
Requires-Dist: pytest ; extra == 'all'
|
|
400
|
-
Requires-Dist: python-dateutil ~=2.
|
|
400
|
+
Requires-Dist: python-dateutil ~=2.9.0 ; extra == 'all'
|
|
401
401
|
Requires-Dist: python-docx ; extra == 'all'
|
|
402
402
|
Requires-Dist: python-jwt ==4.1.0 ; extra == 'all'
|
|
403
403
|
Requires-Dist: pyxnat ==1.5.* ; extra == 'all'
|
|
@@ -460,7 +460,7 @@ Requires-Dist: pydantic ~=2.11.0 ; extra == 'ansible'
|
|
|
460
460
|
Requires-Dist: pypandoc ; extra == 'ansible'
|
|
461
461
|
Requires-Dist: pypandoc-binary ; extra == 'ansible'
|
|
462
462
|
Requires-Dist: pytest ; extra == 'ansible'
|
|
463
|
-
Requires-Dist: python-dateutil ~=2.
|
|
463
|
+
Requires-Dist: python-dateutil ~=2.9.0 ; extra == 'ansible'
|
|
464
464
|
Requires-Dist: python-docx ; extra == 'ansible'
|
|
465
465
|
Requires-Dist: python-jwt ==4.1.0 ; extra == 'ansible'
|
|
466
466
|
Requires-Dist: pyxnat ==1.5.* ; extra == 'ansible'
|
|
@@ -539,7 +539,7 @@ Requires-Dist: pytest-rerunfailures ; extra == 'dev'
|
|
|
539
539
|
Requires-Dist: pytest-timeout ; extra == 'dev'
|
|
540
540
|
Requires-Dist: pytest-xdist ; extra == 'dev'
|
|
541
541
|
Requires-Dist: pytest >=5 ; extra == 'dev'
|
|
542
|
-
Requires-Dist: python-dateutil ~=2.
|
|
542
|
+
Requires-Dist: python-dateutil ~=2.9.0 ; extra == 'dev'
|
|
543
543
|
Requires-Dist: python-docx ; extra == 'dev'
|
|
544
544
|
Requires-Dist: python-jwt ==4.1.0 ; extra == 'dev'
|
|
545
545
|
Requires-Dist: pyxnat ==1.5.* ; extra == 'dev'
|
|
@@ -612,7 +612,7 @@ Requires-Dist: pydantic ~=2.11.0 ; extra == 'server'
|
|
|
612
612
|
Requires-Dist: pypandoc ; extra == 'server'
|
|
613
613
|
Requires-Dist: pypandoc-binary ; extra == 'server'
|
|
614
614
|
Requires-Dist: pytest ; extra == 'server'
|
|
615
|
-
Requires-Dist: python-dateutil ~=2.
|
|
615
|
+
Requires-Dist: python-dateutil ~=2.9.0 ; extra == 'server'
|
|
616
616
|
Requires-Dist: python-docx ; extra == 'server'
|
|
617
617
|
Requires-Dist: python-jwt ==4.1.0 ; extra == 'server'
|
|
618
618
|
Requires-Dist: pyxnat ==1.5.* ; extra == 'server'
|