GT AI OS Community Edition v2.0.33

Security hardening release addressing CodeQL and Dependabot alerts:

- Fix stack trace exposure in error responses
- Add SSRF protection with DNS resolution checking
- Implement proper URL hostname validation (replaces substring matching)
- Add centralized path sanitization to prevent path traversal
- Fix ReDoS vulnerability in email validation regex
- Improve HTML sanitization in validation utilities
- Fix capability wildcard matching in auth utilities
- Update glob dependency to address CVE
- Add CodeQL suppression comments for verified false positives

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
HackWeasel
2025-12-12 17:04:45 -05:00
commit b9dfb86260
746 changed files with 232071 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
"""
Usage tracking database model
"""
from datetime import datetime
from typing import Dict, Any
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, JSON
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.core.database import Base
class UsageRecord(Base):
"""Usage tracking for billing and monitoring"""
__tablename__ = "usage_records"
id = Column(Integer, primary_key=True, index=True)
tenant_id = Column(Integer, ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False, index=True)
resource_id = Column(Integer, ForeignKey("ai_resources.id", ondelete="CASCADE"), nullable=False, index=True)
user_email = Column(String(255), nullable=False, index=True)
request_type = Column(String(50), nullable=False, index=True) # chat, embedding, image_generation, etc.
tokens_used = Column(Integer, nullable=False, default=0)
cost_cents = Column(Integer, nullable=False, default=0)
request_metadata = Column(JSON, nullable=False, default=dict)
# Timestamp
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True)
# Relationships
tenant = relationship("Tenant", back_populates="usage_records")
ai_resource = relationship("AIResource", back_populates="usage_records")
def __repr__(self):
return f"<UsageRecord(id={self.id}, tenant_id={self.tenant_id}, tokens={self.tokens_used})>"
def to_dict(self) -> Dict[str, Any]:
"""Convert usage record to dictionary"""
return {
"id": self.id,
"tenant_id": self.tenant_id,
"resource_id": self.resource_id,
"user_email": self.user_email,
"request_type": self.request_type,
"tokens_used": self.tokens_used,
"cost_cents": self.cost_cents,
"request_metadata": self.request_metadata,
"created_at": self.created_at.isoformat() if self.created_at else None
}
@property
def cost_dollars(self) -> float:
"""Get cost in dollars"""
return self.cost_cents / 100.0
@classmethod
def calculate_cost(cls, tokens_used: int, resource_type: str, provider: str) -> int:
"""Calculate cost in cents based on usage"""
# Cost calculation logic (example rates)
if provider == "groq":
if resource_type == "llm":
# Groq LLM pricing: ~$0.0001 per 1K tokens
return max(1, int((tokens_used / 1000) * 0.01 * 100)) # Convert to cents
elif resource_type == "embedding":
# Embedding pricing: ~$0.00002 per 1K tokens
return max(1, int((tokens_used / 1000) * 0.002 * 100)) # Convert to cents
# Default fallback cost
return max(1, int((tokens_used / 1000) * 0.001 * 100)) # 0.1 cents per 1K tokens