catocli 3.0.18__py3-none-any.whl → 3.0.24__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.
Potentially problematic release.
This version of catocli might be problematic. Click here for more details.
- catocli/Utils/clidriver.py +16 -8
- catocli/Utils/formatter_account_metrics.py +544 -0
- catocli/Utils/formatter_app_stats.py +184 -0
- catocli/Utils/formatter_app_stats_timeseries.py +377 -0
- catocli/Utils/formatter_events_timeseries.py +459 -0
- catocli/Utils/formatter_socket_port_metrics.py +189 -0
- catocli/Utils/formatter_socket_port_metrics_timeseries.py +339 -0
- catocli/Utils/formatter_utils.py +251 -0
- catocli/__init__.py +1 -1
- catocli/clisettings.json +37 -5
- catocli/parsers/customParserApiClient.py +211 -66
- catocli/parsers/mutation_policy/__init__.py +405 -405
- catocli/parsers/mutation_site/__init__.py +15 -15
- catocli/parsers/mutation_sites/__init__.py +15 -15
- catocli/parsers/query_accountMetrics/README.md +90 -0
- catocli/parsers/query_accountMetrics/__init__.py +6 -0
- catocli/parsers/query_appStats/README.md +2 -2
- catocli/parsers/query_appStats/__init__.py +4 -2
- catocli/parsers/query_appStatsTimeSeries/__init__.py +4 -2
- catocli/parsers/query_eventsTimeSeries/README.md +280 -0
- catocli/parsers/query_eventsTimeSeries/__init__.py +6 -0
- catocli/parsers/query_policy/__init__.py +42 -42
- catocli/parsers/query_socketPortMetrics/README.md +44 -0
- catocli/parsers/query_socketPortMetrics/__init__.py +6 -0
- catocli/parsers/query_socketPortMetricsTimeSeries/README.md +83 -0
- catocli/parsers/query_socketPortMetricsTimeSeries/__init__.py +4 -2
- catocli/parsers/utils/export_utils.py +6 -2
- catocli-3.0.24.dist-info/METADATA +184 -0
- {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/RECORD +37 -35
- {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/top_level.txt +0 -1
- models/mutation.xdr.analystFeedback.json +822 -87
- models/query.xdr.stories.json +822 -87
- models/query.xdr.story.json +822 -87
- schema/catolib.py +89 -64
- catocli/Utils/csv_formatter.py +0 -663
- catocli-3.0.18.dist-info/METADATA +0 -124
- scripts/catolib.py +0 -62
- scripts/export_if_rules_to_json.py +0 -188
- scripts/export_wf_rules_to_json.py +0 -111
- scripts/import_wf_rules_to_tfstate.py +0 -331
- {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/WHEEL +0 -0
- {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/entry_points.txt +0 -0
- {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/licenses/LICENSE +0 -0
schema/catolib.py
CHANGED
|
@@ -256,8 +256,8 @@ def processOperation(operationType, operationName):
|
|
|
256
256
|
|
|
257
257
|
childOperations = operation_data.get("childOperations", {}).keys() if "childOperations" in operation_data else []
|
|
258
258
|
|
|
259
|
-
# Process with recursion depth tracking
|
|
260
|
-
parsedOperation = parseOperationWithDepthTracking(operation_data, childOperations, max_depth=50)
|
|
259
|
+
# Process with recursion depth tracking and pass operation name for filtering
|
|
260
|
+
parsedOperation = parseOperationWithDepthTracking(operation_data, childOperations, max_depth=50, operation_path=operationName)
|
|
261
261
|
parsedOperation = getOperationArgs(parsedOperation["type"]["definition"], parsedOperation)
|
|
262
262
|
parsedOperation["path"] = operationName
|
|
263
263
|
|
|
@@ -313,7 +313,7 @@ def processOperation(operationType, operationName):
|
|
|
313
313
|
print(f"Error in processOperation {operationName}: {e}")
|
|
314
314
|
raise
|
|
315
315
|
|
|
316
|
-
def parseOperationWithDepthTracking(curOperation, childOperations, max_depth=50):
|
|
316
|
+
def parseOperationWithDepthTracking(curOperation, childOperations, max_depth=50, operation_path=None):
|
|
317
317
|
"""Parse operation with recursion depth tracking to prevent stack overflow"""
|
|
318
318
|
if not hasattr(thread_local, 'depth'):
|
|
319
319
|
thread_local.depth = 0
|
|
@@ -325,7 +325,7 @@ def parseOperationWithDepthTracking(curOperation, childOperations, max_depth=50)
|
|
|
325
325
|
print(f"WARNING: Max recursion depth {max_depth} reached, truncating...")
|
|
326
326
|
return curOperation
|
|
327
327
|
|
|
328
|
-
return parseOperation(curOperation, childOperations)
|
|
328
|
+
return parseOperation(curOperation, childOperations, operation_path)
|
|
329
329
|
finally:
|
|
330
330
|
thread_local.depth -= 1
|
|
331
331
|
|
|
@@ -405,7 +405,7 @@ def getNestedArgDefinitions(argsAry, parentParamPath, childOperations, parentFie
|
|
|
405
405
|
newArgsList[arg["id_str"]] = arg
|
|
406
406
|
return newArgsList
|
|
407
407
|
|
|
408
|
-
def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields):
|
|
408
|
+
def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields, operation_path=None):
|
|
409
409
|
"""Thread-safe version of interface definitions processing"""
|
|
410
410
|
curInterfaces = {}
|
|
411
411
|
for possibleType in possibleTypesAry:
|
|
@@ -416,13 +416,13 @@ def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperat
|
|
|
416
416
|
curInterface = curInterfaces[interfaceName]
|
|
417
417
|
curParamPath = "" if (parentParamPath == None) else parentParamPath + curInterface["name"] + "___"
|
|
418
418
|
if "fields" in curInterface and curInterface["fields"] != None and curInterface["name"] != "CatoEndpointUser":
|
|
419
|
-
curInterface["fields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["fields"]), curParamPath, childOperations, parentFields, curInterface["name"])
|
|
419
|
+
curInterface["fields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["fields"]), curParamPath, childOperations, parentFields, curInterface["name"], operation_path)
|
|
420
420
|
if "inputFields" in curInterface and curInterface["inputFields"] != None:
|
|
421
|
-
curInterface["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["inputFields"]), curParamPath, childOperations, parentFields, curInterface["name"])
|
|
421
|
+
curInterface["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["inputFields"]), curParamPath, childOperations, parentFields, curInterface["name"], operation_path)
|
|
422
422
|
if "interfaces" in curInterface and curInterface["interfaces"] != None:
|
|
423
|
-
curInterface["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["interfaces"]), parentParamPath, childOperations, parentFields)
|
|
423
|
+
curInterface["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["interfaces"]), parentParamPath, childOperations, parentFields, operation_path)
|
|
424
424
|
if "possibleTypes" in curInterface and curInterface["possibleTypes"] != None:
|
|
425
|
-
curInterface["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["possibleTypes"]), parentParamPath, childOperations, parentFields)
|
|
425
|
+
curInterface["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["possibleTypes"]), parentParamPath, childOperations, parentFields, operation_path)
|
|
426
426
|
|
|
427
427
|
return curInterfaces
|
|
428
428
|
|
|
@@ -728,8 +728,16 @@ def main(args=None):
|
|
|
728
728
|
# Print CSV output directly without JSON formatting
|
|
729
729
|
print(response[0]["__csv_output__"], end='')
|
|
730
730
|
else:
|
|
731
|
-
#
|
|
732
|
-
|
|
731
|
+
# Handle different response formats more robustly
|
|
732
|
+
if isinstance(response, list) and len(response) > 0:
|
|
733
|
+
# Standard format: [data, status, headers]
|
|
734
|
+
print(json.dumps(response[0], sort_keys=True, indent=4))
|
|
735
|
+
elif isinstance(response, dict):
|
|
736
|
+
# Direct dict response
|
|
737
|
+
print(json.dumps(response, sort_keys=True, indent=4))
|
|
738
|
+
else:
|
|
739
|
+
# Fallback: print as-is
|
|
740
|
+
print(json.dumps(response, sort_keys=True, indent=4))
|
|
733
741
|
except KeyboardInterrupt:
|
|
734
742
|
print('Operation cancelled by user (Ctrl+C).')
|
|
735
743
|
exit(130) # Standard exit code for SIGINT
|
|
@@ -752,9 +760,10 @@ def writeOperationParsers(catoApiSchema):
|
|
|
752
760
|
"""Write operation parsers - thread-safe implementation"""
|
|
753
761
|
parserMapping = {"query":{},"mutation":{}}
|
|
754
762
|
|
|
755
|
-
# Load settings to get
|
|
763
|
+
# Load settings to get format-supported operations
|
|
756
764
|
settings = loadJSON("../catocli/clisettings.json")
|
|
757
765
|
csv_supported_operations = settings.get("queryOperationCsvOutput", {})
|
|
766
|
+
format_overrides = settings.get("queryOperationDefaultFormatOverrides", {})
|
|
758
767
|
|
|
759
768
|
## Write the raw query parser ##
|
|
760
769
|
cliDriverStr =f"""
|
|
@@ -825,9 +834,11 @@ def {parserName}_parse({operationType}_subparsers):
|
|
|
825
834
|
usage=get_help("{operationType}_{operationName}"), formatter_class=CustomSubparserHelpFormatter)
|
|
826
835
|
"""
|
|
827
836
|
if "path" in parser:
|
|
828
|
-
# Check if this operation supports CSV
|
|
837
|
+
# Check if this operation supports format overrides (CSV, etc.)
|
|
829
838
|
operation_path = parserName.replace("_", ".")
|
|
830
|
-
supports_csv = operation_path in csv_supported_operations
|
|
839
|
+
supports_csv = (operation_path in csv_supported_operations or
|
|
840
|
+
(operation_path in format_overrides and
|
|
841
|
+
format_overrides[operation_path].get("enabled", False)))
|
|
831
842
|
|
|
832
843
|
cliDriverStr += f"""
|
|
833
844
|
{parserName}_parser.add_argument('json', nargs='?', default='{{}}', help='Variables in JSON format (defaults to empty object if not provided).')
|
|
@@ -840,11 +851,17 @@ def {parserName}_parse({operationType}_subparsers):
|
|
|
840
851
|
{parserName}_parser.add_argument('-H', '--header', action='append', dest='headers', help='Add custom headers in "Key: Value" format. Can be used multiple times.')
|
|
841
852
|
{parserName}_parser.add_argument('--headers-file', dest='headers_file', help='Load headers from a file. Each line should contain a header in "Key: Value" format.')
|
|
842
853
|
"""
|
|
843
|
-
# Add
|
|
854
|
+
# Add format flags for operations with format overrides
|
|
844
855
|
if supports_csv:
|
|
856
|
+
# Generate appropriate default CSV filename from operation name
|
|
857
|
+
# Use the full operation name instead of stripping parts to ensure clarity
|
|
858
|
+
default_csv_name = f"{operationName.lower()}.csv"
|
|
859
|
+
|
|
845
860
|
cliDriverStr += f"""
|
|
846
|
-
|
|
847
|
-
{parserName}_parser.add_argument('
|
|
861
|
+
|
|
862
|
+
{parserName}_parser.add_argument('-f', '--format', choices=['json', 'csv'], help='Output format (default: formatted json, use -raw for original json)')
|
|
863
|
+
{parserName}_parser.add_argument('-raw', '--raw', dest='raw_output', action='store_true', help='Return raw/original JSON format (bypasses default formatting)')
|
|
864
|
+
{parserName}_parser.add_argument('--csv-filename', dest='csv_filename', help='Override CSV file name (default: {default_csv_name})')
|
|
848
865
|
{parserName}_parser.add_argument('--append-timestamp', dest='append_timestamp', action='store_true', help='Append timestamp to the CSV file name')
|
|
849
866
|
"""
|
|
850
867
|
|
|
@@ -1180,7 +1197,7 @@ catocli {operationCmd} '{example_json_pretty}'
|
|
|
1180
1197
|
|
|
1181
1198
|
print(" - README files written successfully")
|
|
1182
1199
|
|
|
1183
|
-
def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, parentTypeName=None):
|
|
1200
|
+
def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, parentTypeName=None, operation_path=None):
|
|
1184
1201
|
"""Thread-safe version with recursion depth management"""
|
|
1185
1202
|
if not hasattr(thread_local, 'depth'):
|
|
1186
1203
|
thread_local.depth = 0
|
|
@@ -1196,7 +1213,7 @@ def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, p
|
|
|
1196
1213
|
curParamPath = "" if (parentParamPath == None) else parentParamPath + "___"
|
|
1197
1214
|
|
|
1198
1215
|
if curType["ofType"] != None:
|
|
1199
|
-
ofType = getOfType(copy.deepcopy(curType["ofType"]), ofType, parentParamPath, childOperations, parentFields)
|
|
1216
|
+
ofType = getOfType(copy.deepcopy(curType["ofType"]), ofType, parentParamPath, childOperations, parentFields, parentTypeName, operation_path)
|
|
1200
1217
|
else:
|
|
1201
1218
|
ofType["name"] = curType["name"]
|
|
1202
1219
|
|
|
@@ -1210,28 +1227,28 @@ def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, p
|
|
|
1210
1227
|
ofType["indexType"] = "input_object"
|
|
1211
1228
|
ofType["definition"] = copy.deepcopy(catoApiIntrospection["input_objects"][ofType["name"]])
|
|
1212
1229
|
if ofType["definition"]["inputFields"] != None:
|
|
1213
|
-
ofType["definition"]["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["inputFields"]), curParamPath, childOperations, parentFields, ofType["name"])
|
|
1230
|
+
ofType["definition"]["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["inputFields"]), curParamPath, childOperations, parentFields, ofType["name"], operation_path)
|
|
1214
1231
|
elif "UNION" in ofType["kind"]:
|
|
1215
1232
|
ofType["indexType"] = "interface"
|
|
1216
1233
|
ofType["definition"] = copy.deepcopy(catoApiIntrospection["unions"][ofType["name"]])
|
|
1217
1234
|
if ofType["definition"]["possibleTypes"] != None:
|
|
1218
|
-
ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields)
|
|
1235
|
+
ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields, operation_path)
|
|
1219
1236
|
elif "OBJECT" in ofType["kind"]:
|
|
1220
1237
|
ofType["indexType"] = "object"
|
|
1221
1238
|
ofType["definition"] = copy.deepcopy(catoApiIntrospection["objects"][ofType["name"]])
|
|
1222
1239
|
if ofType["definition"]["fields"] != None and childOperations!=None:
|
|
1223
1240
|
ofType["definition"]["fields"] = checkForChildOperation(copy.deepcopy(ofType["definition"]["fields"]), childOperations)
|
|
1224
|
-
ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"])
|
|
1241
|
+
ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"], operation_path)
|
|
1225
1242
|
if ofType["definition"]["interfaces"] != None:
|
|
1226
|
-
ofType["definition"]["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["interfaces"]), curParamPath, childOperations, parentFields)
|
|
1243
|
+
ofType["definition"]["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["interfaces"]), curParamPath, childOperations, parentFields, operation_path)
|
|
1227
1244
|
elif "INTERFACE" in ofType["kind"]:
|
|
1228
1245
|
ofType["indexType"] = "interface"
|
|
1229
1246
|
ofType["definition"] = copy.deepcopy(catoApiIntrospection["interfaces"][ofType["name"]])
|
|
1230
1247
|
if ofType["definition"]["fields"] != None:
|
|
1231
|
-
ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"])
|
|
1248
|
+
ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"], operation_path)
|
|
1232
1249
|
# CRITICAL FIX: Also handle possibleTypes for interfaces (like MergedIncident)
|
|
1233
1250
|
if ofType["definition"]["possibleTypes"] != None:
|
|
1234
|
-
ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields)
|
|
1251
|
+
ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields, operation_path)
|
|
1235
1252
|
elif "ENUM" in ofType["kind"]:
|
|
1236
1253
|
ofType["indexType"] = "enum"
|
|
1237
1254
|
ofType["definition"] = copy.deepcopy(catoApiIntrospection["enums"][ofType["name"]])
|
|
@@ -1240,17 +1257,54 @@ def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, p
|
|
|
1240
1257
|
finally:
|
|
1241
1258
|
thread_local.depth -= 1
|
|
1242
1259
|
|
|
1243
|
-
def
|
|
1244
|
-
"""
|
|
1260
|
+
def should_exclude_field(field_name, field_type, operation_path, parent_path):
|
|
1261
|
+
"""
|
|
1262
|
+
Determine if a field should be excluded from model generation for query.policy and mutation.policy operations.
|
|
1263
|
+
|
|
1264
|
+
Excludes:
|
|
1265
|
+
- subPolicyId field (type: ID) from rules.rule.section and sections.section
|
|
1266
|
+
- access field from sections with EntityAccess type containing action field (enum: RBACAction)
|
|
1267
|
+
"""
|
|
1268
|
+
# Only apply filtering to query.policy and mutation.policy operations
|
|
1269
|
+
if not operation_path or not (operation_path.startswith("query.policy") or operation_path.startswith("mutation.policy")):
|
|
1270
|
+
return False
|
|
1271
|
+
|
|
1272
|
+
# Exclude subPolicyId field from specific sections (handles nested paths like firewall.rule.section)
|
|
1273
|
+
if (field_name == "subPolicyId" and
|
|
1274
|
+
field_type.get("name") == "ID" and
|
|
1275
|
+
parent_path and (
|
|
1276
|
+
parent_path.endswith(".section.subPolicyId") and
|
|
1277
|
+
("rules.rule" in parent_path or "sections.section" in parent_path or
|
|
1278
|
+
"rule.rule.section" in parent_path or # For mutations like addRule.rule.rule.section
|
|
1279
|
+
"section.section" in parent_path or # For mutations like addSection.section.section
|
|
1280
|
+
"firewall.rule.section" in parent_path) # For socketLan mutations like addRule.rule.rule.firewall.rule.section
|
|
1281
|
+
)):
|
|
1282
|
+
return True
|
|
1283
|
+
|
|
1284
|
+
# Exclude access field from sections with EntityAccess type
|
|
1285
|
+
if (field_name == "access" and
|
|
1286
|
+
field_type.get("name") == "EntityAccess" and
|
|
1287
|
+
parent_path and ("sections.access" in parent_path or
|
|
1288
|
+
parent_path.endswith(".access") and "section" in parent_path)):
|
|
1289
|
+
return True
|
|
1290
|
+
|
|
1291
|
+
return False
|
|
1292
|
+
|
|
1293
|
+
def getNestedFieldDefinitions(fieldsAry, parentParamPath, childOperations, parentFields, parentTypeName=None, operation_path=None):
|
|
1294
|
+
"""Thread-safe version with field exclusion logic for policy operations"""
|
|
1245
1295
|
newFieldsList = {}
|
|
1246
1296
|
for field in fieldsAry:
|
|
1247
1297
|
if isinstance(field, str):
|
|
1248
1298
|
field = fieldsAry[field]
|
|
1249
1299
|
curParamPath = field["name"] if (parentParamPath == None) else (parentParamPath.replace("___",".") + field["name"])
|
|
1250
|
-
field["type"] = getOfType(field["type"], { "non_null": False, "kind": [], "name": None }, curParamPath, childOperations, parentFields, parentTypeName)
|
|
1300
|
+
field["type"] = getOfType(field["type"], { "non_null": False, "kind": [], "name": None }, curParamPath, childOperations, parentFields, parentTypeName, operation_path)
|
|
1251
1301
|
field["path"] = curParamPath
|
|
1252
1302
|
field["id_str"] = curParamPath.replace(".","___")
|
|
1253
1303
|
|
|
1304
|
+
# Check if this field should be excluded from policy operations
|
|
1305
|
+
if should_exclude_field(field["name"], field["type"], operation_path, curParamPath):
|
|
1306
|
+
continue # Skip this field
|
|
1307
|
+
|
|
1254
1308
|
if isinstance(field["type"]["kind"], list):
|
|
1255
1309
|
field["required"] = True if field["type"]["kind"][0] == "NON_NULL" else False
|
|
1256
1310
|
else:
|
|
@@ -1316,21 +1370,21 @@ def send(api_key, query, variables={}, operationName=None):
|
|
|
1316
1370
|
# writeCliDriver, writeOperationParsers, writeReadmes, etc.)
|
|
1317
1371
|
# For space reasons, I'm not including them all here, but they should be copied over
|
|
1318
1372
|
|
|
1319
|
-
def parseOperation(curOperation, childOperations):
|
|
1373
|
+
def parseOperation(curOperation, childOperations, operation_path=None):
|
|
1320
1374
|
if "operationArgs" not in curOperation:
|
|
1321
1375
|
curOperation["operationArgs"] = {}
|
|
1322
1376
|
curOperation["fieldTypes"] = {}
|
|
1323
|
-
curOfType = getOfType(curOperation["type"], { "non_null": False, "kind": [], "name": None }, None, childOperations, None)
|
|
1377
|
+
curOfType = getOfType(curOperation["type"], { "non_null": False, "kind": [], "name": None }, None, childOperations, None, None, operation_path)
|
|
1324
1378
|
curOperation["type"] = copy.deepcopy(curOfType)
|
|
1325
1379
|
if curOfType["name"] in catoApiIntrospection["objects"]:
|
|
1326
1380
|
curOperation["args"] = getNestedArgDefinitions(curOperation["args"], None, childOperations, None)
|
|
1327
1381
|
curOperation["type"]["definition"] = copy.deepcopy(catoApiIntrospection["objects"][curOperation["type"]["name"]])
|
|
1328
1382
|
if "fields" in curOperation["type"]["definition"] and curOperation["type"]["definition"]["fields"] != None:
|
|
1329
1383
|
curOperation["type"]["definition"]["fields"] = checkForChildOperation(copy.deepcopy(curOperation["type"]["definition"]["fields"]), childOperations)
|
|
1330
|
-
curOperation["type"]["definition"]["fields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["fields"], None, childOperations, [], curOperation["type"]["name"]))
|
|
1384
|
+
curOperation["type"]["definition"]["fields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["fields"], None, childOperations, [], curOperation["type"]["name"], operation_path))
|
|
1331
1385
|
if "inputFields" in curOperation["type"]["definition"] and curOperation["type"]["definition"]["inputFields"] != None:
|
|
1332
1386
|
parentFields = curOperation["type"]["definition"]["inputFields"].keys()
|
|
1333
|
-
curOperation["type"]["definition"]["inputFields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["inputFields"], None, childOperations, parentFields, curOperation["type"]["name"]))
|
|
1387
|
+
curOperation["type"]["definition"]["inputFields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["inputFields"], None, childOperations, parentFields, curOperation["type"]["name"], operation_path))
|
|
1334
1388
|
return curOperation
|
|
1335
1389
|
|
|
1336
1390
|
def checkForChildOperation(fieldsAry, childOperations):
|
|
@@ -1455,7 +1509,7 @@ def renderInputFieldVal(arg):
|
|
|
1455
1509
|
|
|
1456
1510
|
return value
|
|
1457
1511
|
|
|
1458
|
-
def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields):
|
|
1512
|
+
def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields, operation_path=None):
|
|
1459
1513
|
"""Get nested interface definitions - returns expanded possibleTypes array with complete field definitions"""
|
|
1460
1514
|
expandedTypes = []
|
|
1461
1515
|
for possibleType in possibleTypesAry:
|
|
@@ -1472,7 +1526,8 @@ def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperat
|
|
|
1472
1526
|
parentParamPath,
|
|
1473
1527
|
childOperations,
|
|
1474
1528
|
parentFields,
|
|
1475
|
-
possibleType["name"]
|
|
1529
|
+
possibleType["name"],
|
|
1530
|
+
operation_path
|
|
1476
1531
|
)
|
|
1477
1532
|
expandedTypes.append(expandedType)
|
|
1478
1533
|
else:
|
|
@@ -1700,33 +1755,3 @@ catocli {subOperationCmd} '{example_json_pretty}'
|
|
|
1700
1755
|
# Only recurse if subOperation is a dict and doesn't have a "path" key
|
|
1701
1756
|
if isinstance(subOperation, dict) and "path" not in subOperation:
|
|
1702
1757
|
renderSubReadme(subOperation, operationType, subOperationPath)
|
|
1703
|
-
|
|
1704
|
-
def main():
|
|
1705
|
-
# Main execution function with threading support
|
|
1706
|
-
options = initParser()
|
|
1707
|
-
|
|
1708
|
-
# Load the introspection schema
|
|
1709
|
-
print("Loading schema...")
|
|
1710
|
-
schema = loadJSON("./introspection.json")
|
|
1711
|
-
|
|
1712
|
-
print("Starting multi-threaded schema parsing...")
|
|
1713
|
-
start_time = time.time()
|
|
1714
|
-
|
|
1715
|
-
# Parse the schema using multi-threading
|
|
1716
|
-
parseSchema(schema)
|
|
1717
|
-
|
|
1718
|
-
end_time = time.time()
|
|
1719
|
-
print(f"\n• Schema processing completed in {end_time - start_time:.2f} seconds")
|
|
1720
|
-
|
|
1721
|
-
print("\n• Generating CLI components...")
|
|
1722
|
-
writeCliDriver(catoApiSchema)
|
|
1723
|
-
writeOperationParsers(catoApiSchema)
|
|
1724
|
-
writeReadmes(catoApiSchema)
|
|
1725
|
-
|
|
1726
|
-
total_operations = len(catoApiSchema["query"]) + len(catoApiSchema["mutation"])
|
|
1727
|
-
print(f"\n• Successfully generated {total_operations} operation models")
|
|
1728
|
-
print(f" - Query operations: {len(catoApiSchema['query'])}")
|
|
1729
|
-
print(f" - Mutation operations: {len(catoApiSchema['mutation'])}")
|
|
1730
|
-
|
|
1731
|
-
if __name__ == "__main__":
|
|
1732
|
-
main()
|