Skip to content

Commit 01416ee

Browse files
authored
Merge pull request #57 from JupiterOne/KNO-606
update README
2 parents 562f12b + fb317aa commit 01416ee

File tree

1 file changed

+218
-3
lines changed

1 file changed

+218
-3
lines changed

README.md

Lines changed: 218 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,29 @@ the default of "https://api.us.jupiterone.io" is used.
4141

4242
## Method Examples:
4343

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
4567

4668
##### Execute a query:
4769

@@ -162,10 +184,17 @@ j1.update_entity(
162184
# Delete by entity ID
163185
j1.delete_entity(entity_id='<id-of-entity-to-delete>')
164186

165-
# Delete with timestamp
187+
# Delete with timestamp and hard delete option
166188
j1.delete_entity(
167189
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
169198
)
170199
```
171200

@@ -494,6 +523,63 @@ elif result['job']['status'] == 'FAILED':
494523
print(f"Sync job failed: {result['job'].get('error', 'Unknown error')}")
495524
```
496525

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+
497583
##### Fetch Integration Instance Jobs
498584

499585
```python
@@ -618,6 +704,135 @@ for prompt in complex_prompts:
618704
print("---")
619705
```
620706

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+
621836
##### List Alert Rules
622837

623838
```python

0 commit comments

Comments
 (0)