Skip to content

Commit 750e6e9

Browse files
committed
add keyword search and tag filtering to list_questions()
1 parent 4a097e8 commit 750e6e9

File tree

5 files changed

+502
-22
lines changed

5 files changed

+502
-22
lines changed

examples/08_questions_management.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,40 @@ def list_questions_example(j1):
315315
if len(questions) > 5:
316316
print(f"\n... and {len(questions) - 5} more questions")
317317

318+
# Demonstrate filtering capabilities
319+
print("\n=== Filtering Examples ===")
320+
321+
# Search by content
322+
print("\n1. Searching for security-related questions:")
323+
security_questions = j1.list_questions(search_query="security")
324+
print(f" Found {len(security_questions)} questions with 'security' in title/description")
325+
if security_questions:
326+
print(f" Example: {security_questions[0]['title']}")
327+
328+
# Filter by tags
329+
print("\n2. Filtering by compliance tags:")
330+
compliance_questions = j1.list_questions(tags=["compliance"])
331+
print(f" Found {len(compliance_questions)} questions tagged with 'compliance'")
332+
if compliance_questions:
333+
print(f" Example: {compliance_questions[0]['title']}")
334+
335+
# Combine search and tags
336+
print("\n3. Combining search and tags:")
337+
security_compliance = j1.list_questions(
338+
search_query="encryption",
339+
tags=["security", "compliance"]
340+
)
341+
print(f" Found {len(security_compliance)} questions matching both criteria")
342+
if security_compliance:
343+
print(f" Example: {security_compliance[0]['title']}")
344+
345+
# Search for specific compliance standards
346+
print("\n4. Searching for CIS compliance questions:")
347+
cis_questions = j1.list_questions(search_query="CIS")
348+
print(f" Found {len(cis_questions)} questions related to CIS")
349+
if cis_questions:
350+
print(f" Example: {cis_questions[0]['title']}")
351+
318352
except Exception as e:
319353
print(f"Error listing questions: {e}")
320354

examples/README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ python 08_questions_management.py
204204

205205
### 📊 Questions Management
206206
- Question creation with J1QL queries
207-
- Question listing and analysis
207+
- Question listing and analysis with filtering options
208+
- Search questions by title/description using `search_query` parameter
209+
- Filter questions by tags using `tags` parameter
208210
- Compliance metadata management
209211
- Question categorization and filtering
210212
- Question lifecycle management
@@ -280,11 +282,25 @@ j1 = JupiterOneClient(
280282
```
281283

282284
### Questions Analysis
283-
Examples show how to analyze questions data:
285+
Examples show how to analyze questions data with filtering:
284286
```python
285287
# List all questions
286288
questions = j1.list_questions()
287289

290+
# Search questions by content
291+
security_questions = j1.list_questions(search_query="security")
292+
encryption_questions = j1.list_questions(search_query="encryption")
293+
294+
# Filter questions by tags
295+
compliance_questions = j1.list_questions(tags=["compliance"])
296+
cis_questions = j1.list_questions(tags=["cis", "aws"])
297+
298+
# Combine search and tags
299+
security_compliance = j1.list_questions(
300+
search_query="encryption",
301+
tags=["security", "compliance"]
302+
)
303+
288304
# Analyze by compliance standards
289305
compliance_standards = {}
290306
for question in questions:

examples/examples.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -575,22 +575,26 @@
575575
print(f"Total questions found: {len(list_questions_r)}")
576576
print(json.dumps(list_questions_r[:2], indent=1)) # Show first 2 questions
577577

578-
# list_questions with filtering (if supported)
579-
# Note: The current implementation doesn't support filtering parameters,
580-
# but the GraphQL schema shows support for searchQuery, tags, etc.
581-
print("\nlist_questions() - Sample question details:")
582-
if list_questions_r:
583-
sample_question = list_questions_r[0]
584-
print(f" Title: {sample_question.get('title', 'No title')}")
585-
print(f" ID: {sample_question.get('id', 'No ID')}")
586-
print(f" Description: {sample_question.get('description', 'No description')}")
587-
print(f" Tags: {sample_question.get('tags', [])}")
588-
print(f" Number of queries: {len(sample_question.get('queries', []))}")
589-
if sample_question.get('queries'):
590-
for i, query in enumerate(sample_question['queries']):
591-
print(f" Query {i+1}: {query.get('name', 'Unnamed')} - {query.get('query', 'No query')[:50]}...")
592-
else:
593-
print(" No questions found in the account")
578+
# list_questions with search query
579+
print("\nlist_questions() - With search query:")
580+
security_questions = j1.list_questions(search_query="security")
581+
print(f"Security-related questions found: {len(security_questions)}")
582+
if security_questions:
583+
print(f" First security question: {security_questions[0].get('title', 'No title')}")
584+
585+
# list_questions with tags filter
586+
print("\nlist_questions() - With tags filter:")
587+
compliance_questions = j1.list_questions(tags=["compliance"])
588+
print(f"Compliance-tagged questions found: {len(compliance_questions)}")
589+
if compliance_questions:
590+
print(f" First compliance question: {compliance_questions[0].get('title', 'No title')}")
591+
592+
# list_questions with combined search and tags
593+
print("\nlist_questions() - With search and tags:")
594+
security_compliance = j1.list_questions(search_query="encryption", tags=["security", "compliance"])
595+
print(f"Security/compliance encryption questions found: {len(security_compliance)}")
596+
if security_compliance:
597+
print(f" First matching question: {security_compliance[0].get('title', 'No title')}")
594598

595599
# list_questions - analyze question types and compliance
596600
print("\nlist_questions() - Analysis:")

jupiterone/client.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,12 +1246,44 @@ def fetch_downloaded_evaluation_results(self, download_url: str = None):
12461246

12471247
return e
12481248

1249-
def list_questions(self):
1250-
"""List all defined Questions configured in J1 Account Questions Library"""
1249+
def list_questions(self, search_query: str = None, tags: List[str] = None):
1250+
"""List all defined Questions configured in J1 Account Questions Library
1251+
1252+
Args:
1253+
search_query (str, optional): Search query to filter questions by title or description
1254+
tags (List[str], optional): List of tags to filter questions by
1255+
1256+
Returns:
1257+
List[Dict]: List of question objects
1258+
1259+
Example:
1260+
# List all questions
1261+
all_questions = j1_client.list_questions()
1262+
1263+
# Search for security-related questions
1264+
security_questions = j1_client.list_questions(search_query="security")
1265+
1266+
# Filter by specific tags
1267+
compliance_questions = j1_client.list_questions(tags=["compliance", "cis"])
1268+
1269+
# Combine search and tags
1270+
security_compliance = j1_client.list_questions(
1271+
search_query="encryption",
1272+
tags=["security", "compliance"]
1273+
)
1274+
"""
12511275
results = []
12521276

1277+
# Build variables for the GraphQL query
1278+
variables = {}
1279+
if search_query:
1280+
variables["searchQuery"] = search_query
1281+
if tags:
1282+
variables["tags"] = tags
1283+
12531284
data = {
12541285
"query": QUESTIONS,
1286+
"variables": variables,
12551287
"flags": {
12561288
"variableResultSize": True
12571289
}
@@ -1267,10 +1299,16 @@ def list_questions(self):
12671299
cursor = r["data"]["questions"]["pageInfo"]["endCursor"]
12681300

12691301
# cursor query until last page fetched
1302+
# Preserve existing variables and add cursor
1303+
cursor_variables = variables.copy()
1304+
cursor_variables["cursor"] = cursor
1305+
12701306
data = {
12711307
"query": QUESTIONS,
1272-
"variables": {"cursor": cursor},
1273-
"flags": {"variableResultSize": True},
1308+
"variables": cursor_variables,
1309+
"flags": {
1310+
"variableResultSize": True
1311+
},
12741312
}
12751313

12761314
r = requests.post(

0 commit comments

Comments
 (0)