@@ -41,7 +41,29 @@ the default of "https://api.us.jupiterone.io" is used.
41
41
42
42
## Method Examples:
43
43
44
- ### * See the examples/examples.py for full usage example documentation
44
+ ### * See the examples/ directory for comprehensive usage examples:
45
+
46
+ #### ** Core API Examples**
47
+ - ` examples/01_client_setup_and_queries.py ` - Client setup and basic J1QL queries
48
+ - ` examples/02_entity_management.py ` - Entity creation, updates, and deletion
49
+ - ` examples/03_relationship_management.py ` - Relationship management and traversal
50
+ - ` examples/examples.py ` - General API usage examples and patterns
51
+
52
+ #### ** Integration & Management**
53
+ - ` examples/04_integration_management.py ` - Integration instance management and sync jobs
54
+ - ` examples/05_alert_rules_and_smartclasses.py ` - Alert rules and SmartClass operations
55
+ - ` examples/06_advanced_operations.py ` - Advanced API operations and workflows
56
+
57
+ #### ** Specialized Features**
58
+ - ` examples/07_account_parameters_list_example.py ` - Account parameter management
59
+ - ` examples/08_questions_management.py ` - Complete question management workflows
60
+ - ` examples/09_custom_file_transfer_example.py ` - Custom File Transfer (CFT) integration examples
61
+ - ` examples/create_integration_instance_example.py ` - Integration instance creation examples
62
+
63
+ #### ** Utility & Data Examples**
64
+ - ` examples/J1QLdeferredResponse.py ` - Deferred response query handling
65
+ - ` examples/customFileTransferUploadData.py ` - Custom file transfer data examples
66
+ - ` examples/examples2.py ` - Additional example patterns
45
67
46
68
##### Execute a query:
47
69
@@ -162,10 +184,17 @@ j1.update_entity(
162
184
# Delete by entity ID
163
185
j1.delete_entity(entity_id = ' <id-of-entity-to-delete>' )
164
186
165
- # Delete with timestamp
187
+ # Delete with timestamp and hard delete option
166
188
j1.delete_entity(
167
189
entity_id = ' <id-of-entity-to-delete>' ,
168
- timestamp = int (time.time()) * 1000
190
+ timestamp = int (time.time()) * 1000 ,
191
+ hard_delete = True # Set to False for soft delete
192
+ )
193
+
194
+ # Soft delete (entity marked as deleted but not permanently removed)
195
+ j1.delete_entity(
196
+ entity_id = ' <id-of-entity-to-delete>' ,
197
+ hard_delete = False
169
198
)
170
199
```
171
200
@@ -494,6 +523,63 @@ elif result['job']['status'] == 'FAILED':
494
523
print (f " Sync job failed: { result[' job' ].get(' error' , ' Unknown error' )} " )
495
524
```
496
525
526
+ ##### Custom File Transfer (CFT) Integration Methods
527
+
528
+ ``` python
529
+ # Get a pre-signed URL for file upload
530
+ upload_info = j1.get_cft_upload_url(
531
+ integration_instance_id = ' <id-of-integration-instance>' ,
532
+ filename = ' data.csv' ,
533
+ dataset_id = ' <id-of-dataset>'
534
+ )
535
+ print (f " Upload URL: { upload_info[' uploadUrl' ]} " )
536
+ print (f " Expires at: { upload_info[' expiresAt' ]} " )
537
+
538
+ # Upload a CSV file to the CFT integration
539
+ upload_result = j1.upload_cft_file(
540
+ upload_url = upload_info[' uploadUrl' ],
541
+ file_path = ' /path/to/your/data.csv'
542
+ )
543
+ print (f " Upload status: { upload_result[' status_code' ]} " )
544
+ print (f " Upload success: { upload_result[' success' ]} " )
545
+
546
+ # Invoke the CFT integration to process the uploaded file
547
+ invoke_result = j1.invoke_cft_integration(
548
+ integration_instance_id = ' <id-of-integration-instance>'
549
+ )
550
+ if invoke_result is True :
551
+ print (" CFT integration invoked successfully" )
552
+ elif invoke_result == ' ALREADY_RUNNING' :
553
+ print (" CFT integration is already running" )
554
+ else :
555
+ print (" Failed to invoke CFT integration" )
556
+
557
+ # Complete workflow example
558
+ def upload_and_process_data (j1 , instance_id , dataset_id , file_path ):
559
+ """ Complete workflow for CFT data upload and processing"""
560
+ try :
561
+ # Step 1: Get upload URL
562
+ upload_info = j1.get_cft_upload_url(instance_id, ' data.csv' , dataset_id)
563
+
564
+ # Step 2: Upload file
565
+ upload_result = j1.upload_cft_file(upload_info[' uploadUrl' ], file_path)
566
+ if not upload_result[' success' ]:
567
+ raise Exception (f " Upload failed: { upload_result[' status_code' ]} " )
568
+
569
+ # Step 3: Invoke processing
570
+ invoke_result = j1.invoke_cft_integration(instance_id)
571
+ if invoke_result is True :
572
+ print (" Data uploaded and processing started successfully" )
573
+ else :
574
+ print (f " Processing status: { invoke_result} " )
575
+
576
+ except Exception as e:
577
+ print (f " Error in CFT workflow: { e} " )
578
+
579
+ # Usage
580
+ upload_and_process_data(j1, ' instance-123' , ' dataset-456' , ' /path/to/data.csv' )
581
+ ```
582
+
497
583
##### Fetch Integration Instance Jobs
498
584
499
585
``` python
@@ -618,6 +704,135 @@ for prompt in complex_prompts:
618
704
print (" ---" )
619
705
```
620
706
707
+ ##### Question Management Methods
708
+
709
+ ``` python
710
+ # Create a new question
711
+ question = j1.create_question(
712
+ title = " Security Compliance Check" ,
713
+ queries = [
714
+ {
715
+ " query" : " FIND User WITH mfaEnabled=false" ,
716
+ " name" : " UsersWithoutMFA" ,
717
+ " resultsAre" : " BAD"
718
+ },
719
+ {
720
+ " query" : " FIND Host WITH encrypted=false" ,
721
+ " name" : " UnencryptedHosts" ,
722
+ " resultsAre" : " BAD"
723
+ }
724
+ ],
725
+ description = " Check for security compliance violations" ,
726
+ tags = [" security" , " compliance" ],
727
+ showTrend = True ,
728
+ pollingInterval = " ONE_DAY"
729
+ )
730
+ print (f " Created question: { question[' title' ]} (ID: { question[' id' ]} ) " )
731
+
732
+ # List existing questions
733
+ questions = j1.list_questions()
734
+ print (f " Found { len (questions)} questions " )
735
+
736
+ # Search for specific questions
737
+ security_questions = j1.list_questions(search_query = " security" )
738
+ compliance_questions = j1.list_questions(tags = [" compliance" ])
739
+
740
+ # Get question details
741
+ question_details = j1.get_question_details(question_id = question[' id' ])
742
+ print (f " Question: { question_details[' title' ]} " )
743
+ print (f " Description: { question_details[' description' ]} " )
744
+ print (f " Queries: { len (question_details[' queries' ])} " )
745
+
746
+ # Update an existing question
747
+ updated_question = j1.update_question(
748
+ question_id = question[' id' ],
749
+ title = " Updated Security Compliance Check" ,
750
+ description = " Enhanced security compliance monitoring" ,
751
+ tags = [" security" , " compliance" , " enhanced" ]
752
+ )
753
+ print (f " Updated question: { updated_question[' title' ]} " )
754
+
755
+ # Update specific fields only
756
+ j1.update_question(
757
+ question_id = question[' id' ],
758
+ description = " Updated description only"
759
+ )
760
+
761
+ # Update queries with validation
762
+ updated_queries = [
763
+ {
764
+ " query" : " FIND User WITH mfaEnabled=false AND active=true" ,
765
+ " name" : " ActiveUsersWithoutMFA" ,
766
+ " resultsAre" : " BAD"
767
+ }
768
+ ]
769
+ j1.update_question(
770
+ question_id = question[' id' ],
771
+ queries = updated_queries
772
+ )
773
+
774
+ # Delete a question
775
+ deleted_question = j1.delete_question(question_id = question[' id' ])
776
+ print (f " Deleted question: { deleted_question[' title' ]} " )
777
+
778
+ # Complete workflow example
779
+ def manage_security_questions (j1 ):
780
+ """ Complete workflow for managing security questions"""
781
+ try :
782
+ # Create a comprehensive security question
783
+ security_question = j1.create_question(
784
+ title = " Production Security Audit" ,
785
+ queries = [
786
+ {
787
+ " query" : " FIND Host WITH tag.Environment='production' AND encrypted=false" ,
788
+ " name" : " UnencryptedProdHosts" ,
789
+ " resultsAre" : " BAD"
790
+ },
791
+ {
792
+ " query" : " FIND User WITH privileged=true AND lastLoginOn < date.now - 90 days" ,
793
+ " name" : " InactivePrivilegedUsers" ,
794
+ " resultsAre" : " BAD"
795
+ }
796
+ ],
797
+ description = " Comprehensive production security audit" ,
798
+ tags = [" security" , " production" , " audit" ],
799
+ showTrend = True ,
800
+ pollingInterval = " ONE_DAY"
801
+ )
802
+
803
+ print (f " Created security question: { security_question[' title' ]} " )
804
+
805
+ # Update the question with additional queries
806
+ additional_queries = [
807
+ {
808
+ " query" : " FIND Database WITH backupEnabled=false" ,
809
+ " name" : " DatabasesWithoutBackup" ,
810
+ " resultsAre" : " BAD"
811
+ }
812
+ ]
813
+
814
+ updated_question = j1.update_question(
815
+ question_id = security_question[' id' ],
816
+ queries = additional_queries
817
+ )
818
+
819
+ print (f " Updated question with additional queries " )
820
+
821
+ # List all security questions
822
+ all_security_questions = j1.list_questions(tags = [" security" ])
823
+ print (f " Total security questions: { len (all_security_questions)} " )
824
+
825
+ # Clean up - delete the test question
826
+ j1.delete_question(question_id = security_question[' id' ])
827
+ print (" Test question cleaned up" )
828
+
829
+ except Exception as e:
830
+ print (f " Error in security question workflow: { e} " )
831
+
832
+ # Usage
833
+ manage_security_questions(j1)
834
+ ```
835
+
621
836
##### List Alert Rules
622
837
623
838
``` python
0 commit comments