-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Add comprehensive question/insight management methods to Python API client
Description
The JupiterOne Python API client lacks built-in methods for question (insight) operations, forcing users to write direct GraphQL mutations for basic question management tasks. While the GraphQL API supports comprehensive question operations, the Python client does not expose these capabilities through convenient methods.
Current Behavior
The Python API client currently has no built-in question/insight management methods. Users must implement all question operations using direct GraphQL mutations.
Current workaround:
def delete_question(question_id: str) -> None:
"""
Helper function to delete a question.
"""
delete_question_mutation = """
mutation DeleteQuestion($id: ID!) {
deleteQuestion(id: $id) {
id
title
description
queries {
query
name
version
__typename
}
compliance {
standard
requirements
controls
__typename
}
variables {
name
required
default
__typename
}
tags
accountId
integrationDefinitionId
showTrend
pollingInterval
__typename
}
}
"""
delete_variables = {"id": question_id}
delete_result = make_graphql_request(delete_question_mutation, delete_variables, "DeleteQuestion")
assert delete_result['data']['deleteQuestion']['id'] == question_id, "Question deletion failed."Users must also manually implement create, update, and list operations using similar complex GraphQL patterns.
Expected Behavior
The Python API client should provide comprehensive question management methods that match the capabilities of the underlying GraphQL API.
Missing Methods
The following methods should be added to the JupiterOneClient class:
1. create_question(title, queries, resource_group_id=None, **kwargs)
question = j1_client.create_question(
title="Security Compliance Check",
queries=[{
"query": "FIND Host WITH open=true",
"name": "OpenHosts",
"version": "v1",
"resultsAre": "INFORMATIVE"
}],
resource_group_id="resource-group-id", # Optional
description="Check for open hosts",
tags=["security", "compliance"]
)2. update_question(question_id, title=None, queries=None, **kwargs)
updated_question = j1_client.update_question(
question_id="question-123",
title="Updated Security Check",
queries=[{
"query": "FIND Host WITH open=true AND severity='HIGH'",
"name": "CriticalOpenHosts",
"version": "v1"
}]
)3. delete_question(question_id)
success = j1_client.delete_question(question_id="question-123")4. list_questions(resource_group_id=None, tags=None)
# List all questions
all_questions = j1_client.list_questions()
# List questions in specific resource group
rg_questions = j1_client.list_questions(resource_group_id="resource-group-id")
# List questions with specific tags
tagged_questions = j1_client.list_questions(tags=["security", "compliance"])5. get_question_details(question_id)
question_details = j1_client.get_question_details(question_id="question-123")6. execute_question(question_id)
results = j1_client.execute_question(question_id="question-123")Code Example
Current state (manual GraphQL required):
# Users must write complex direct GraphQL mutations
create_question_mutation = """
mutation CreateQuestion($question: CreateQuestionInput!) {
createQuestion(question: $question) {
id
title
description
queries {
name
query
version
resultsAre
__typename
}
compliance {
standard
requirements
controls
__typename
}
variables {
name
required
default
__typename
}
accountId
integrationDefinitionId
showTrend
pollingInterval
lastUpdatedTimestamp
__typename
}
}
"""
variables = {
"question": {
"queries": [
{
"query": "FIND jupiterone_account as a return a._accountId",
"resultsAre": "INFORMATIVE",
"name": "Account"
}
],
"title": "TestQuestion"
}
}
# Manual GraphQL request handling
result = make_graphql_request(create_question_mutation, variables, "CreateQuestion")
question_id = result['data']['createQuestion']['id']Desired API experience:
# What we want to be able to do
question = j1_client.create_question(
title="Security Insights",
queries=[{
"query": "FIND Host WITH vulnerabilities!=undefined",
"name": "VulnerableHosts",
"version": "v1",
"resultsAre": "BAD"
}],
resource_group_id="security-rg",
description="Track vulnerable hosts",
tags=["security", "vulnerabilities"]
)
# List and manage questions easily
questions = j1_client.list_questions(tags=["security"])
question_details = j1_client.get_question_details(question['id'])
# Execute and get results
results = j1_client.execute_question(question['id'])
# Update and delete
j1_client.update_question(question['id'], title="Updated Security Insights")
j1_client.delete_question(question['id'])Consistency with Other Methods
Other resource management operations in the client follow consistent patterns:
# Alert rules have comprehensive management
alerts = j1_client.list_alert_rules()
alert = j1_client.create_alert_rule(name="Alert", j1ql="FIND Host", ...)
j1_client.update_alert_rule(rule_id="123", ...)
j1_client.delete_alert_rule(rule_id="123")
# Integration instances have partial management
instances = j1_client.fetch_integration_instances()
integration = j1_client.create_integration_instance(...)
# Questions have NO management methods (this issue)Impact
This limitation affects:
- Developer Experience: Users must write and maintain complex GraphQL code for question operations
- Code Maintainability: Direct GraphQL mutations with complex nested structures are error-prone
- API Consistency: Question operations don't follow the same patterns as other resources
- Resource Group Integration: No built-in support for resource group assignment/filtering
- Insight Workflows: Automated insight creation and management becomes cumbersome
- Compliance Reporting: Difficult to programmatically manage compliance questions
Proposed Solution
Add comprehensive question management methods to the JupiterOneClient class following the established patterns from other resource methods.
Environment
- JupiterOne Python API Client: v1.5.0
- Python: 3.8+
Additional Context
This issue was identified during automated testing where question/insight lifecycle management is required for compliance reporting and security insights. The current approach of writing custom GraphQL mutations creates significant maintenance overhead due to the complexity of question objects.
Questions/insights are commonly used in:
- Automated compliance reporting
- Security posture assessments
- Custom insight dashboards
- Regulatory requirement tracking
- CI/CD pipeline security gates
The complex nested structure of questions (with queries, compliance mappings, variables, etc.) makes this a high-value addition to the API client.
Related Issues
- Dashboard management methods (similar pattern needed)
- Integration instance lifecycle management methods (similar pattern needed)
- Resource group parameter support across all creation methods