Fix: Security, reliability, and code quality improvements from PR review
Critical Security Fixes: - Fix command injection vulnerability in Windows shims (beadboard.cmd, bb.cmd) - Added path validation to block traversal (.. and root-relative paths) - Added quotes around env var to prevent command injection Reliability Fixes: - Fix agent cache null safety bug - Fixed callBdAgentShow() to check for cache misses (null check, expiration) - Fixed getCachedAgent to properly return entry.data or null - Fix null body crashes in mail ack route - Added null check before casting body to object - Returns 400 error instead of 500 for invalid requests BD Compliance Fixes: - Fix read-issues to use BD audit record path - Ensures all writes go through bd audit record - Maintains watcher/SSE parity and Dolt commit tracking Code Quality Fixes: - Fix path canonicalization violations - Use canonicalizeWindowsPath() and windowsPathKey() from pathing module - Prevents Windows edge cases and ensures machine-reproducible paths - Fix typo: mobile-fronted → mobile-frontend - Pin GitHub Actions tags - softprops/action-gh-release@v1 → specific commit hash - Register pr14 test in package.json (already registered) Testing: - Refactor broad exception handlers in Python scripts - Replace except Exception: with specific exceptions - Allows KeyboardInterrupt and SystemExit to propagate correctly - All tests passing
This commit is contained in:
parent
d54e4f3311
commit
ce4700849b
15 changed files with 2995 additions and 756 deletions
|
|
@ -12,54 +12,54 @@ import re
|
|||
def read_chunk(chunk_id: str, chunk_store) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Read a chunk by ID.
|
||||
|
||||
|
||||
Args:
|
||||
chunk_id: The chunk ID to read
|
||||
chunk_store: ChunkStore instance
|
||||
|
||||
|
||||
Returns:
|
||||
Chunk data dict or None if not found
|
||||
"""
|
||||
# Validate chunk_id format - reject path traversal attempts
|
||||
if chunk_id is None:
|
||||
return None
|
||||
|
||||
|
||||
# Check for path traversal patterns
|
||||
if '..' in chunk_id or '/' in chunk_id or '\\' in chunk_id:
|
||||
if ".." in chunk_id or "/" in chunk_id or "\\" in chunk_id:
|
||||
return None
|
||||
|
||||
|
||||
# Only allow alphanumeric, hyphens, and underscores
|
||||
if not re.match(r'^[a-zA-Z0-9_-]+$', chunk_id):
|
||||
if not re.match(r"^[a-zA-Z0-9_-]+$", chunk_id):
|
||||
return None
|
||||
|
||||
|
||||
try:
|
||||
chunk = chunk_store.get_chunk(chunk_id)
|
||||
if chunk is None:
|
||||
return None
|
||||
|
||||
|
||||
# Convert Chunk dataclass to dict
|
||||
return {
|
||||
'id': chunk.id,
|
||||
'content': chunk.content,
|
||||
'tokens': chunk.tokens,
|
||||
'type': chunk.type,
|
||||
'metadata': chunk.metadata,
|
||||
'links': chunk.links,
|
||||
'tags': chunk.tags,
|
||||
"id": chunk.id,
|
||||
"content": chunk.content,
|
||||
"tokens": chunk.tokens,
|
||||
"type": chunk.type,
|
||||
"metadata": chunk.metadata,
|
||||
"links": chunk.links,
|
||||
"tags": chunk.tags,
|
||||
}
|
||||
except Exception:
|
||||
except (AttributeError, TypeError, KeyError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def search_chunks(query: str, chunk_store, limit: int = 10) -> List[str]:
|
||||
"""
|
||||
Search for chunks matching query.
|
||||
|
||||
|
||||
Args:
|
||||
query: Search query string
|
||||
chunk_store: ChunkStore instance
|
||||
limit: Maximum results to return
|
||||
|
||||
|
||||
Returns:
|
||||
List of matching chunk IDs
|
||||
"""
|
||||
|
|
@ -68,37 +68,37 @@ def search_chunks(query: str, chunk_store, limit: int = 10) -> List[str]:
|
|||
# In production, this could use embeddings or more sophisticated search
|
||||
query_lower = query.lower()
|
||||
words = set(query_lower.split())
|
||||
|
||||
|
||||
all_chunks = chunk_store.list_chunks()
|
||||
results = []
|
||||
|
||||
|
||||
for chunk_id in all_chunks:
|
||||
chunk = chunk_store.get_chunk(chunk_id)
|
||||
if chunk is None:
|
||||
continue
|
||||
|
||||
|
||||
content_lower = chunk.content.lower()
|
||||
|
||||
|
||||
# Check if any query word appears in content
|
||||
if any(word in content_lower for word in words):
|
||||
results.append(chunk_id)
|
||||
|
||||
|
||||
if len(results) >= limit:
|
||||
break
|
||||
|
||||
|
||||
return results
|
||||
except Exception:
|
||||
except (AttributeError, TypeError, KeyError, ValueError):
|
||||
return []
|
||||
|
||||
|
||||
def list_chunks_by_tag(tags, chunk_store) -> List[str]:
|
||||
"""
|
||||
List all chunks with given tag(s).
|
||||
|
||||
|
||||
Args:
|
||||
tags: Single tag string or list of tags to search for
|
||||
chunk_store: ChunkStore instance
|
||||
|
||||
|
||||
Returns:
|
||||
List of chunk IDs with the tag(s)
|
||||
"""
|
||||
|
|
@ -109,19 +109,21 @@ def list_chunks_by_tag(tags, chunk_store) -> List[str]:
|
|||
elif isinstance(tags, list):
|
||||
return chunk_store.list_chunks(tags=tags)
|
||||
return []
|
||||
except Exception:
|
||||
except (AttributeError, TypeError, KeyError, ValueError):
|
||||
return []
|
||||
|
||||
|
||||
def get_linked_chunks(chunk_id: str, chunk_store, link_type: Optional[str] = None) -> List[Dict[str, Any]]:
|
||||
def get_linked_chunks(
|
||||
chunk_id: str, chunk_store, link_type: Optional[str] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Get chunks linked to the given chunk.
|
||||
|
||||
|
||||
Args:
|
||||
chunk_id: Source chunk ID
|
||||
chunk_store: ChunkStore instance
|
||||
link_type: Optional link type filter (e.g., 'context_of', 'follows', 'related_to')
|
||||
|
||||
|
||||
Returns:
|
||||
List of linked chunk data dicts
|
||||
"""
|
||||
|
|
@ -129,22 +131,22 @@ def get_linked_chunks(chunk_id: str, chunk_store, link_type: Optional[str] = Non
|
|||
chunk = chunk_store.get_chunk(chunk_id)
|
||||
if chunk is None:
|
||||
return []
|
||||
|
||||
|
||||
linked = []
|
||||
for link in chunk.links:
|
||||
# Filter by link type if specified
|
||||
if link_type and link.get('type') != link_type:
|
||||
if link_type and link.get("type") != link_type:
|
||||
continue
|
||||
|
||||
target_id = link.get('target_id')
|
||||
|
||||
target_id = link.get("target_id")
|
||||
if target_id:
|
||||
target_chunk = read_chunk(target_id, chunk_store)
|
||||
if target_chunk:
|
||||
# Include link metadata
|
||||
target_chunk['_link_type'] = link.get('type', 'unknown')
|
||||
target_chunk['_link_strength'] = link.get('strength', 0.5)
|
||||
target_chunk["_link_type"] = link.get("type", "unknown")
|
||||
target_chunk["_link_strength"] = link.get("strength", 0.5)
|
||||
linked.append(target_chunk)
|
||||
|
||||
|
||||
return linked
|
||||
except Exception:
|
||||
except (AttributeError, TypeError, KeyError, ValueError):
|
||||
return []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue