praisonai-code 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- praisonai_code/__init__.py +17 -0
- praisonai_code/cli/__init__.py +12 -0
- praisonai_code/cli/_forward_shim.py +10 -0
- praisonai_code/cli/_paths.py +88 -0
- praisonai_code/cli/_warnings.py +58 -0
- praisonai_code/cli/app.py +757 -0
- praisonai_code/cli/approval_backend.py +272 -0
- praisonai_code/cli/branding.py +94 -0
- praisonai_code/cli/commands/__init__.py +114 -0
- praisonai_code/cli/commands/acp.py +80 -0
- praisonai_code/cli/commands/agent.py +116 -0
- praisonai_code/cli/commands/agents.py +80 -0
- praisonai_code/cli/commands/app.py +139 -0
- praisonai_code/cli/commands/attach.py +95 -0
- praisonai_code/cli/commands/audit.py +102 -0
- praisonai_code/cli/commands/auth.py +508 -0
- praisonai_code/cli/commands/batch.py +848 -0
- praisonai_code/cli/commands/benchmark.py +286 -0
- praisonai_code/cli/commands/browser.py +299 -0
- praisonai_code/cli/commands/call.py +45 -0
- praisonai_code/cli/commands/chat.py +332 -0
- praisonai_code/cli/commands/checkpoint.py +170 -0
- praisonai_code/cli/commands/code.py +276 -0
- praisonai_code/cli/commands/command.py +114 -0
- praisonai_code/cli/commands/commit.py +47 -0
- praisonai_code/cli/commands/completion.py +333 -0
- praisonai_code/cli/commands/config.py +681 -0
- praisonai_code/cli/commands/context.py +414 -0
- praisonai_code/cli/commands/daemon.py +203 -0
- praisonai_code/cli/commands/debug.py +142 -0
- praisonai_code/cli/commands/deploy.py +71 -0
- praisonai_code/cli/commands/diag.py +55 -0
- praisonai_code/cli/commands/docs.py +1575 -0
- praisonai_code/cli/commands/doctor.py +332 -0
- praisonai_code/cli/commands/endpoints.py +51 -0
- praisonai_code/cli/commands/environment.py +179 -0
- praisonai_code/cli/commands/eval.py +131 -0
- praisonai_code/cli/commands/examples.py +953 -0
- praisonai_code/cli/commands/flow.py +436 -0
- praisonai_code/cli/commands/github.py +752 -0
- praisonai_code/cli/commands/hooks.py +74 -0
- praisonai_code/cli/commands/init.py +174 -0
- praisonai_code/cli/commands/knowledge.py +440 -0
- praisonai_code/cli/commands/langextract.py +120 -0
- praisonai_code/cli/commands/langfuse.py +984 -0
- praisonai_code/cli/commands/loop.py +211 -0
- praisonai_code/cli/commands/lsp.py +112 -0
- praisonai_code/cli/commands/managed.py +659 -0
- praisonai_code/cli/commands/mcp.py +763 -0
- praisonai_code/cli/commands/memory.py +298 -0
- praisonai_code/cli/commands/models.py +264 -0
- praisonai_code/cli/commands/n8n.py +326 -0
- praisonai_code/cli/commands/obs.py +19 -0
- praisonai_code/cli/commands/package.py +76 -0
- praisonai_code/cli/commands/paths.py +106 -0
- praisonai_code/cli/commands/permissions.py +272 -0
- praisonai_code/cli/commands/plugins.py +609 -0
- praisonai_code/cli/commands/port.py +530 -0
- praisonai_code/cli/commands/profile.py +466 -0
- praisonai_code/cli/commands/publish.py +193 -0
- praisonai_code/cli/commands/rag.py +913 -0
- praisonai_code/cli/commands/realtime.py +52 -0
- praisonai_code/cli/commands/recipe.py +684 -0
- praisonai_code/cli/commands/registry.py +59 -0
- praisonai_code/cli/commands/replay.py +830 -0
- praisonai_code/cli/commands/research.py +49 -0
- praisonai_code/cli/commands/retrieval.py +377 -0
- praisonai_code/cli/commands/rules.py +71 -0
- praisonai_code/cli/commands/run.py +1573 -0
- praisonai_code/cli/commands/sandbox.py +371 -0
- praisonai_code/cli/commands/schedule.py +529 -0
- praisonai_code/cli/commands/serve.py +690 -0
- praisonai_code/cli/commands/session.py +450 -0
- praisonai_code/cli/commands/setup.py +174 -0
- praisonai_code/cli/commands/skills.py +545 -0
- praisonai_code/cli/commands/standardise.py +711 -0
- praisonai_code/cli/commands/templates.py +54 -0
- praisonai_code/cli/commands/test.py +558 -0
- praisonai_code/cli/commands/todo.py +74 -0
- praisonai_code/cli/commands/tools.py +205 -0
- praisonai_code/cli/commands/traces.py +145 -0
- praisonai_code/cli/commands/tracker.py +852 -0
- praisonai_code/cli/commands/train.py +613 -0
- praisonai_code/cli/commands/ui.py +172 -0
- praisonai_code/cli/commands/up.py +354 -0
- praisonai_code/cli/commands/validate.py +291 -0
- praisonai_code/cli/commands/version.py +101 -0
- praisonai_code/cli/commands/workflow.py +97 -0
- praisonai_code/cli/config_loader.py +437 -0
- praisonai_code/cli/configuration/__init__.py +27 -0
- praisonai_code/cli/configuration/config.schema.json +57 -0
- praisonai_code/cli/configuration/credentials.py +446 -0
- praisonai_code/cli/configuration/loader.py +364 -0
- praisonai_code/cli/configuration/model_resolver.py +161 -0
- praisonai_code/cli/configuration/oauth.py +389 -0
- praisonai_code/cli/configuration/paths.py +224 -0
- praisonai_code/cli/configuration/resolver.py +687 -0
- praisonai_code/cli/configuration/schema.py +317 -0
- praisonai_code/cli/execution/__init__.py +99 -0
- praisonai_code/cli/execution/core.py +208 -0
- praisonai_code/cli/execution/profiler.py +898 -0
- praisonai_code/cli/execution/request.py +85 -0
- praisonai_code/cli/execution/result.py +74 -0
- praisonai_code/cli/fallback_schema.py +416 -0
- praisonai_code/cli/features/__init__.py +278 -0
- praisonai_code/cli/features/_endpoint_registry.py +64 -0
- praisonai_code/cli/features/_search_registry.py +43 -0
- praisonai_code/cli/features/acp.py +236 -0
- praisonai_code/cli/features/action_orchestrator.py +576 -0
- praisonai_code/cli/features/agent_scheduler.py +773 -0
- praisonai_code/cli/features/agent_tools.py +603 -0
- praisonai_code/cli/features/agents.py +397 -0
- praisonai_code/cli/features/at_mentions.py +471 -0
- praisonai_code/cli/features/audit_cli.py +270 -0
- praisonai_code/cli/features/auto_memory.py +182 -0
- praisonai_code/cli/features/auto_mode.py +552 -0
- praisonai_code/cli/features/autonomy_mode.py +546 -0
- praisonai_code/cli/features/background.py +356 -0
- praisonai_code/cli/features/base.py +168 -0
- praisonai_code/cli/features/benchmark.py +1462 -0
- praisonai_code/cli/features/capabilities.py +1326 -0
- praisonai_code/cli/features/checkpoints.py +345 -0
- praisonai_code/cli/features/cli_profiler.py +335 -0
- praisonai_code/cli/features/code_intelligence.py +666 -0
- praisonai_code/cli/features/compaction.py +294 -0
- praisonai_code/cli/features/compare.py +534 -0
- praisonai_code/cli/features/config_hierarchy.py +366 -0
- praisonai_code/cli/features/context_manager.py +597 -0
- praisonai_code/cli/features/cost_tracker.py +514 -0
- praisonai_code/cli/features/csv_test_runner.py +736 -0
- praisonai_code/cli/features/custom_definitions.py +790 -0
- praisonai_code/cli/features/debug.py +810 -0
- praisonai_code/cli/features/deploy.py +605 -0
- praisonai_code/cli/features/diag.py +289 -0
- praisonai_code/cli/features/display_jsonl.py +173 -0
- praisonai_code/cli/features/doctor/__init__.py +63 -0
- praisonai_code/cli/features/doctor/checks/__init__.py +29 -0
- praisonai_code/cli/features/doctor/checks/acp_checks.py +220 -0
- praisonai_code/cli/features/doctor/checks/bot_checks.py +340 -0
- praisonai_code/cli/features/doctor/checks/config_checks.py +373 -0
- praisonai_code/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai_code/cli/features/doctor/checks/env_checks.py +637 -0
- praisonai_code/cli/features/doctor/checks/gateway_checks.py +387 -0
- praisonai_code/cli/features/doctor/checks/lsp_checks.py +231 -0
- praisonai_code/cli/features/doctor/checks/mcp_checks.py +367 -0
- praisonai_code/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai_code/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai_code/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai_code/cli/features/doctor/checks/packaging_checks.py +422 -0
- praisonai_code/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai_code/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai_code/cli/features/doctor/checks/runtime_checks.py +650 -0
- praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +220 -0
- praisonai_code/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai_code/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai_code/cli/features/doctor/checks/skills_checks.py +327 -0
- praisonai_code/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai_code/cli/features/doctor/engine.py +266 -0
- praisonai_code/cli/features/doctor/formatters.py +377 -0
- praisonai_code/cli/features/doctor/handler.py +564 -0
- praisonai_code/cli/features/doctor/models.py +276 -0
- praisonai_code/cli/features/doctor/registry.py +239 -0
- praisonai_code/cli/features/endpoints.py +1016 -0
- praisonai_code/cli/features/eval.py +559 -0
- praisonai_code/cli/features/examples.py +707 -0
- praisonai_code/cli/features/external_agents.py +231 -0
- praisonai_code/cli/features/fast_context.py +410 -0
- praisonai_code/cli/features/file_history.py +320 -0
- praisonai_code/cli/features/flow_display.py +566 -0
- praisonai_code/cli/features/git_attribution.py +159 -0
- praisonai_code/cli/features/git_integration.py +651 -0
- praisonai_code/cli/features/guardrail.py +171 -0
- praisonai_code/cli/features/handoff.py +252 -0
- praisonai_code/cli/features/hooks.py +583 -0
- praisonai_code/cli/features/hybrid_workflow.py +391 -0
- praisonai_code/cli/features/image.py +384 -0
- praisonai_code/cli/features/interactive_core_headless.py +450 -0
- praisonai_code/cli/features/interactive_runtime.py +600 -0
- praisonai_code/cli/features/interactive_test_harness.py +537 -0
- praisonai_code/cli/features/interactive_tools.py +428 -0
- praisonai_code/cli/features/interactive_tui.py +603 -0
- praisonai_code/cli/features/job_workflow.py +906 -0
- praisonai_code/cli/features/jobs.py +632 -0
- praisonai_code/cli/features/knowledge.py +531 -0
- praisonai_code/cli/features/knowledge_cli.py +438 -0
- praisonai_code/cli/features/lite.py +244 -0
- praisonai_code/cli/features/logs.py +200 -0
- praisonai_code/cli/features/lsp_cli.py +225 -0
- praisonai_code/cli/features/lsp_diagnostics.py +185 -0
- praisonai_code/cli/features/mcp.py +344 -0
- praisonai_code/cli/features/message_queue.py +587 -0
- praisonai_code/cli/features/metrics.py +210 -0
- praisonai_code/cli/features/migrate.py +1329 -0
- praisonai_code/cli/features/migration_flow.py +463 -0
- praisonai_code/cli/features/migration_spec.py +276 -0
- praisonai_code/cli/features/n8n.py +703 -0
- praisonai_code/cli/features/observability.py +293 -0
- praisonai_code/cli/features/ollama.py +361 -0
- praisonai_code/cli/features/output_modes.py +155 -0
- praisonai_code/cli/features/output_style.py +273 -0
- praisonai_code/cli/features/package.py +631 -0
- praisonai_code/cli/features/performance.py +308 -0
- praisonai_code/cli/features/persistence.py +636 -0
- praisonai_code/cli/features/profiler/__init__.py +81 -0
- praisonai_code/cli/features/profiler/core.py +558 -0
- praisonai_code/cli/features/profiler/optimizations.py +652 -0
- praisonai_code/cli/features/profiler/suite.py +386 -0
- praisonai_code/cli/features/queue/__init__.py +73 -0
- praisonai_code/cli/features/queue/manager.py +435 -0
- praisonai_code/cli/features/queue/models.py +289 -0
- praisonai_code/cli/features/queue/persistence.py +564 -0
- praisonai_code/cli/features/queue/scheduler.py +529 -0
- praisonai_code/cli/features/queue/worker.py +400 -0
- praisonai_code/cli/features/recipe.py +2187 -0
- praisonai_code/cli/features/recipe_creator.py +996 -0
- praisonai_code/cli/features/recipe_optimizer.py +1364 -0
- praisonai_code/cli/features/recipe_prompts.py +226 -0
- praisonai_code/cli/features/registry.py +229 -0
- praisonai_code/cli/features/repo_map.py +860 -0
- praisonai_code/cli/features/router.py +466 -0
- praisonai_code/cli/features/safe_shell.py +427 -0
- praisonai_code/cli/features/sandbox_cli.py +283 -0
- praisonai_code/cli/features/sandbox_executor.py +536 -0
- praisonai_code/cli/features/sdk_knowledge.py +500 -0
- praisonai_code/cli/features/session.py +222 -0
- praisonai_code/cli/features/session_checkpoints.py +208 -0
- praisonai_code/cli/features/setup/__init__.py +9 -0
- praisonai_code/cli/features/setup/handler.py +355 -0
- praisonai_code/cli/features/setup/templates.py +62 -0
- praisonai_code/cli/features/skills.py +940 -0
- praisonai_code/cli/features/slash_commands.py +692 -0
- praisonai_code/cli/features/telemetry.py +179 -0
- praisonai_code/cli/features/templates.py +1390 -0
- praisonai_code/cli/features/thinking.py +343 -0
- praisonai_code/cli/features/todo.py +334 -0
- praisonai_code/cli/features/tools.py +680 -0
- praisonai_code/cli/features/tui/__init__.py +83 -0
- praisonai_code/cli/features/tui/app.py +871 -0
- praisonai_code/cli/features/tui/cli.py +580 -0
- praisonai_code/cli/features/tui/config.py +150 -0
- praisonai_code/cli/features/tui/debug.py +526 -0
- praisonai_code/cli/features/tui/events.py +99 -0
- praisonai_code/cli/features/tui/mock_provider.py +328 -0
- praisonai_code/cli/features/tui/orchestrator.py +652 -0
- praisonai_code/cli/features/tui/screens/__init__.py +50 -0
- praisonai_code/cli/features/tui/screens/help.py +157 -0
- praisonai_code/cli/features/tui/screens/main.py +568 -0
- praisonai_code/cli/features/tui/screens/queue.py +174 -0
- praisonai_code/cli/features/tui/screens/session.py +124 -0
- praisonai_code/cli/features/tui/screens/settings.py +148 -0
- praisonai_code/cli/features/tui/session_store.py +198 -0
- praisonai_code/cli/features/tui/widgets/__init__.py +56 -0
- praisonai_code/cli/features/tui/widgets/chat.py +263 -0
- praisonai_code/cli/features/tui/widgets/command_popup.py +258 -0
- praisonai_code/cli/features/tui/widgets/composer.py +292 -0
- praisonai_code/cli/features/tui/widgets/file_popup.py +207 -0
- praisonai_code/cli/features/tui/widgets/queue_panel.py +223 -0
- praisonai_code/cli/features/tui/widgets/status.py +181 -0
- praisonai_code/cli/features/tui/widgets/tool_panel.py +307 -0
- praisonai_code/cli/features/wizard.py +289 -0
- praisonai_code/cli/features/workflow.py +802 -0
- praisonai_code/cli/features/yaml_utils.py +321 -0
- praisonai_code/cli/interactive/__init__.py +48 -0
- praisonai_code/cli/interactive/async_tui.py +1218 -0
- praisonai_code/cli/interactive/config.py +139 -0
- praisonai_code/cli/interactive/core.py +618 -0
- praisonai_code/cli/interactive/events.py +131 -0
- praisonai_code/cli/interactive/frontends/__init__.py +31 -0
- praisonai_code/cli/interactive/frontends/rich_frontend.py +462 -0
- praisonai_code/cli/interactive/frontends/textual_frontend.py +157 -0
- praisonai_code/cli/interactive/praison_io.py +502 -0
- praisonai_code/cli/interactive/repl.py +297 -0
- praisonai_code/cli/interactive/split_tui.py +456 -0
- praisonai_code/cli/interactive/tui_app.py +457 -0
- praisonai_code/cli/langfuse_client.py +360 -0
- praisonai_code/cli/main.py +7421 -0
- praisonai_code/cli/output/__init__.py +25 -0
- praisonai_code/cli/output/console.py +456 -0
- praisonai_code/cli/output/event_bridge.py +191 -0
- praisonai_code/cli/schedule_cli.py +54 -0
- praisonai_code/cli/schema_provider.py +23 -0
- praisonai_code/cli/session/__init__.py +16 -0
- praisonai_code/cli/session/resume.py +148 -0
- praisonai_code/cli/session/unified.py +548 -0
- praisonai_code/cli/state/__init__.py +31 -0
- praisonai_code/cli/state/identifiers.py +161 -0
- praisonai_code/cli/state/project_sessions.py +383 -0
- praisonai_code/cli/state/sessions.py +390 -0
- praisonai_code/cli/ui/__init__.py +160 -0
- praisonai_code/cli/ui/config.py +46 -0
- praisonai_code/cli/ui/events.py +61 -0
- praisonai_code/cli/ui/mg_backend.py +342 -0
- praisonai_code/cli/ui/plain.py +133 -0
- praisonai_code/cli/ui/rich_backend.py +162 -0
- praisonai_code/cli/unified_schema.py +655 -0
- praisonai_code/cli/utils/env_utils.py +126 -0
- praisonai_code/cli/utils/project.py +131 -0
- praisonai_code/cli_backends/__init__.py +73 -0
- praisonai_code/cli_backends/claude.py +373 -0
- praisonai_code/cli_backends/registry.py +113 -0
- praisonai_code/runtime/__init__.py +36 -0
- praisonai_code/runtime/__main__.py +81 -0
- praisonai_code/runtime/client.py +131 -0
- praisonai_code/runtime/descriptor.py +209 -0
- praisonai_code/runtime/server.py +356 -0
- praisonai_code-0.0.1.dist-info/METADATA +80 -0
- praisonai_code-0.0.1.dist-info/RECORD +309 -0
- praisonai_code-0.0.1.dist-info/WHEEL +5 -0
- praisonai_code-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Security Audit CLI for PraisonAI.
|
|
3
|
+
|
|
4
|
+
Provides security scanning and audit capabilities.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Dict, Any, List
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SecurityAudit:
|
|
17
|
+
"""Security audit scanner for PraisonAI projects."""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.findings: List[Dict[str, Any]] = []
|
|
21
|
+
|
|
22
|
+
def scan(self, path: str = ".") -> Dict[str, Any]:
|
|
23
|
+
"""Scan a project for security issues.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
path: Path to scan
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Audit results
|
|
30
|
+
"""
|
|
31
|
+
self.findings = []
|
|
32
|
+
|
|
33
|
+
self._check_env_files(path)
|
|
34
|
+
self._check_api_keys_in_code(path)
|
|
35
|
+
self._check_yaml_configs(path)
|
|
36
|
+
self._check_dependencies(path)
|
|
37
|
+
self._check_permissions(path)
|
|
38
|
+
|
|
39
|
+
critical = sum(1 for f in self.findings if f["severity"] == "critical")
|
|
40
|
+
high = sum(1 for f in self.findings if f["severity"] == "high")
|
|
41
|
+
medium = sum(1 for f in self.findings if f["severity"] == "medium")
|
|
42
|
+
low = sum(1 for f in self.findings if f["severity"] == "low")
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
"path": path,
|
|
46
|
+
"findings": self.findings,
|
|
47
|
+
"summary": {
|
|
48
|
+
"total": len(self.findings),
|
|
49
|
+
"critical": critical,
|
|
50
|
+
"high": high,
|
|
51
|
+
"medium": medium,
|
|
52
|
+
"low": low,
|
|
53
|
+
},
|
|
54
|
+
"passed": critical == 0 and high == 0,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
def _check_env_files(self, path: str) -> None:
|
|
58
|
+
"""Check for exposed .env files."""
|
|
59
|
+
env_files = []
|
|
60
|
+
for root, dirs, files in os.walk(path):
|
|
61
|
+
dirs[:] = [d for d in dirs if not d.startswith(".git")]
|
|
62
|
+
for f in files:
|
|
63
|
+
if f == ".env" or f.endswith(".env"):
|
|
64
|
+
env_files.append(os.path.join(root, f))
|
|
65
|
+
|
|
66
|
+
for env_file in env_files:
|
|
67
|
+
gitignore_path = os.path.join(os.path.dirname(env_file), ".gitignore")
|
|
68
|
+
if os.path.exists(gitignore_path):
|
|
69
|
+
with open(gitignore_path, "r") as f:
|
|
70
|
+
gitignore = f.read()
|
|
71
|
+
if ".env" not in gitignore:
|
|
72
|
+
self.findings.append({
|
|
73
|
+
"type": "exposed_env",
|
|
74
|
+
"severity": "critical",
|
|
75
|
+
"file": env_file,
|
|
76
|
+
"message": ".env file not in .gitignore - secrets may be exposed",
|
|
77
|
+
"fix": "Add '.env' to .gitignore",
|
|
78
|
+
})
|
|
79
|
+
else:
|
|
80
|
+
self.findings.append({
|
|
81
|
+
"type": "missing_gitignore",
|
|
82
|
+
"severity": "high",
|
|
83
|
+
"file": env_file,
|
|
84
|
+
"message": "No .gitignore found - .env file may be committed",
|
|
85
|
+
"fix": "Create .gitignore with '.env' entry",
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
def _check_api_keys_in_code(self, path: str) -> None:
|
|
89
|
+
"""Check for hardcoded API keys in code."""
|
|
90
|
+
import re
|
|
91
|
+
|
|
92
|
+
patterns = [
|
|
93
|
+
(r'sk-[a-zA-Z0-9]{48}', "OpenAI API key"),
|
|
94
|
+
(r'sk-ant-[a-zA-Z0-9-]{95}', "Anthropic API key"),
|
|
95
|
+
(r'AIza[a-zA-Z0-9_-]{35}', "Google API key"),
|
|
96
|
+
(r'xoxb-[0-9]+-[0-9]+-[a-zA-Z0-9]+', "Slack bot token"),
|
|
97
|
+
(r'xapp-[0-9]+-[a-zA-Z0-9]+', "Slack app token"),
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
for root, dirs, files in os.walk(path):
|
|
101
|
+
dirs[:] = [d for d in dirs if not d.startswith(".") and d != "__pycache__"]
|
|
102
|
+
for f in files:
|
|
103
|
+
if f.endswith((".py", ".yaml", ".yml", ".json", ".js", ".ts")):
|
|
104
|
+
file_path = os.path.join(root, f)
|
|
105
|
+
try:
|
|
106
|
+
with open(file_path, "r", encoding="utf-8", errors="ignore") as fp:
|
|
107
|
+
content = fp.read()
|
|
108
|
+
|
|
109
|
+
for pattern, key_type in patterns:
|
|
110
|
+
if re.search(pattern, content):
|
|
111
|
+
self.findings.append({
|
|
112
|
+
"type": "hardcoded_key",
|
|
113
|
+
"severity": "critical",
|
|
114
|
+
"file": file_path,
|
|
115
|
+
"message": f"Possible {key_type} found in code",
|
|
116
|
+
"fix": "Move API key to environment variable",
|
|
117
|
+
})
|
|
118
|
+
except Exception:
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
def _check_yaml_configs(self, path: str) -> None:
|
|
122
|
+
"""Check YAML configurations for security issues."""
|
|
123
|
+
for root, dirs, files in os.walk(path):
|
|
124
|
+
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
|
125
|
+
for f in files:
|
|
126
|
+
if f.endswith((".yaml", ".yml")):
|
|
127
|
+
file_path = os.path.join(root, f)
|
|
128
|
+
try:
|
|
129
|
+
import yaml
|
|
130
|
+
with open(file_path, "r") as fp:
|
|
131
|
+
config = yaml.safe_load(fp)
|
|
132
|
+
|
|
133
|
+
if config and isinstance(config, dict):
|
|
134
|
+
if "api_key" in str(config).lower():
|
|
135
|
+
self.findings.append({
|
|
136
|
+
"type": "key_in_config",
|
|
137
|
+
"severity": "high",
|
|
138
|
+
"file": file_path,
|
|
139
|
+
"message": "API key reference found in YAML config",
|
|
140
|
+
"fix": "Use environment variables instead",
|
|
141
|
+
})
|
|
142
|
+
except Exception:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
def _check_dependencies(self, path: str) -> None:
|
|
146
|
+
"""Check for known vulnerable dependencies."""
|
|
147
|
+
requirements_files = ["requirements.txt", "pyproject.toml"]
|
|
148
|
+
|
|
149
|
+
for req_file in requirements_files:
|
|
150
|
+
req_path = os.path.join(path, req_file)
|
|
151
|
+
if os.path.exists(req_path):
|
|
152
|
+
self.findings.append({
|
|
153
|
+
"type": "dependency_check",
|
|
154
|
+
"severity": "low",
|
|
155
|
+
"file": req_path,
|
|
156
|
+
"message": "Run 'pip-audit' to check for vulnerable dependencies",
|
|
157
|
+
"fix": "pip install pip-audit && pip-audit",
|
|
158
|
+
})
|
|
159
|
+
break
|
|
160
|
+
|
|
161
|
+
def _check_permissions(self, path: str) -> None:
|
|
162
|
+
"""Check file permissions."""
|
|
163
|
+
sensitive_files = [".env", "credentials.json", "service-account.json"]
|
|
164
|
+
|
|
165
|
+
for root, dirs, files in os.walk(path):
|
|
166
|
+
dirs[:] = [d for d in dirs if not d.startswith(".git")]
|
|
167
|
+
for f in files:
|
|
168
|
+
if f in sensitive_files:
|
|
169
|
+
file_path = os.path.join(root, f)
|
|
170
|
+
try:
|
|
171
|
+
mode = os.stat(file_path).st_mode
|
|
172
|
+
if mode & 0o077:
|
|
173
|
+
self.findings.append({
|
|
174
|
+
"type": "file_permissions",
|
|
175
|
+
"severity": "medium",
|
|
176
|
+
"file": file_path,
|
|
177
|
+
"message": "Sensitive file has overly permissive permissions",
|
|
178
|
+
"fix": f"chmod 600 {file_path}",
|
|
179
|
+
})
|
|
180
|
+
except Exception:
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def handle_audit_command(args) -> None:
|
|
185
|
+
"""Handle audit CLI command."""
|
|
186
|
+
try:
|
|
187
|
+
from rich.console import Console
|
|
188
|
+
from rich.table import Table
|
|
189
|
+
from rich.panel import Panel
|
|
190
|
+
except ImportError:
|
|
191
|
+
print("Error: Rich library required for audit display")
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
console = Console()
|
|
195
|
+
audit = SecurityAudit()
|
|
196
|
+
|
|
197
|
+
path = getattr(args, "path", ".")
|
|
198
|
+
results = audit.scan(path)
|
|
199
|
+
|
|
200
|
+
console.print(Panel.fit(
|
|
201
|
+
f"[bold]Security Audit Results[/bold]\n"
|
|
202
|
+
f"Path: {results['path']}",
|
|
203
|
+
title="PraisonAI Security Audit",
|
|
204
|
+
))
|
|
205
|
+
console.print()
|
|
206
|
+
|
|
207
|
+
summary = results["summary"]
|
|
208
|
+
if summary["total"] == 0:
|
|
209
|
+
console.print("[green]✓ No security issues found![/green]")
|
|
210
|
+
else:
|
|
211
|
+
table = Table(title="Summary")
|
|
212
|
+
table.add_column("Severity", style="bold")
|
|
213
|
+
table.add_column("Count", justify="right")
|
|
214
|
+
|
|
215
|
+
if summary["critical"] > 0:
|
|
216
|
+
table.add_row("[red]Critical[/red]", str(summary["critical"]))
|
|
217
|
+
if summary["high"] > 0:
|
|
218
|
+
table.add_row("[orange1]High[/orange1]", str(summary["high"]))
|
|
219
|
+
if summary["medium"] > 0:
|
|
220
|
+
table.add_row("[yellow]Medium[/yellow]", str(summary["medium"]))
|
|
221
|
+
if summary["low"] > 0:
|
|
222
|
+
table.add_row("[blue]Low[/blue]", str(summary["low"]))
|
|
223
|
+
|
|
224
|
+
console.print(table)
|
|
225
|
+
console.print()
|
|
226
|
+
|
|
227
|
+
findings_table = Table(title="Findings")
|
|
228
|
+
findings_table.add_column("Severity")
|
|
229
|
+
findings_table.add_column("Type")
|
|
230
|
+
findings_table.add_column("File")
|
|
231
|
+
findings_table.add_column("Message")
|
|
232
|
+
|
|
233
|
+
severity_colors = {
|
|
234
|
+
"critical": "red",
|
|
235
|
+
"high": "orange1",
|
|
236
|
+
"medium": "yellow",
|
|
237
|
+
"low": "blue",
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
for finding in results["findings"]:
|
|
241
|
+
color = severity_colors.get(finding["severity"], "white")
|
|
242
|
+
findings_table.add_row(
|
|
243
|
+
f"[{color}]{finding['severity'].upper()}[/{color}]",
|
|
244
|
+
finding["type"],
|
|
245
|
+
finding["file"],
|
|
246
|
+
finding["message"],
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
console.print(findings_table)
|
|
250
|
+
console.print()
|
|
251
|
+
|
|
252
|
+
if not results["passed"]:
|
|
253
|
+
console.print("[red]✗ Audit failed - critical/high issues found[/red]")
|
|
254
|
+
else:
|
|
255
|
+
console.print("[yellow]âš Audit passed with warnings[/yellow]")
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def add_audit_parser(subparsers) -> None:
|
|
259
|
+
"""Add audit subparser to CLI."""
|
|
260
|
+
audit_parser = subparsers.add_parser(
|
|
261
|
+
"audit",
|
|
262
|
+
help="Run security audit on project",
|
|
263
|
+
)
|
|
264
|
+
audit_parser.add_argument(
|
|
265
|
+
"path",
|
|
266
|
+
nargs="?",
|
|
267
|
+
default=".",
|
|
268
|
+
help="Path to audit (default: current directory)",
|
|
269
|
+
)
|
|
270
|
+
audit_parser.set_defaults(func=handle_audit_command)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Auto Memory Handler for CLI.
|
|
3
|
+
|
|
4
|
+
Provides automatic memory extraction and storage.
|
|
5
|
+
Usage: praisonai "Learn about user preferences" --auto-memory
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, Tuple
|
|
9
|
+
from .base import FlagHandler
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AutoMemoryHandler(FlagHandler):
|
|
13
|
+
"""
|
|
14
|
+
Handler for --auto-memory flag.
|
|
15
|
+
|
|
16
|
+
Automatically extracts and stores important information from conversations.
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
praisonai "Learn about user preferences" --auto-memory
|
|
20
|
+
praisonai "Remember this context" --auto-memory --user-id myuser
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def feature_name(self) -> str:
|
|
25
|
+
return "auto_memory"
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def flag_name(self) -> str:
|
|
29
|
+
return "auto-memory"
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def flag_help(self) -> str:
|
|
33
|
+
return "Enable automatic memory extraction and storage"
|
|
34
|
+
|
|
35
|
+
def check_dependencies(self) -> Tuple[bool, str]:
|
|
36
|
+
"""Check if AutoMemory is available."""
|
|
37
|
+
try:
|
|
38
|
+
import importlib.util
|
|
39
|
+
if importlib.util.find_spec("praisonaiagents") is not None:
|
|
40
|
+
return True, ""
|
|
41
|
+
return False, "praisonaiagents not installed"
|
|
42
|
+
except ImportError:
|
|
43
|
+
return False, "praisonaiagents not installed. Install with: pip install praisonaiagents"
|
|
44
|
+
|
|
45
|
+
def _get_auto_memory(self, user_id: str = None):
|
|
46
|
+
"""Get AutoMemory instance lazily."""
|
|
47
|
+
try:
|
|
48
|
+
from praisonaiagents.memory import AutoMemory, FileMemory
|
|
49
|
+
# AutoMemory requires a FileMemory instance
|
|
50
|
+
memory = FileMemory(user_id=user_id or "default")
|
|
51
|
+
return AutoMemory(memory=memory)
|
|
52
|
+
except ImportError:
|
|
53
|
+
self.print_status(
|
|
54
|
+
"AutoMemory requires praisonaiagents. Install with: pip install praisonaiagents",
|
|
55
|
+
"error"
|
|
56
|
+
)
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
def apply_to_agent_config(self, config: Dict[str, Any], flag_value: Any) -> Dict[str, Any]:
|
|
60
|
+
"""
|
|
61
|
+
Apply auto memory configuration.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
config: Agent configuration dictionary
|
|
65
|
+
flag_value: Boolean or dict with user_id
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Modified configuration
|
|
69
|
+
"""
|
|
70
|
+
if flag_value:
|
|
71
|
+
config['auto_memory'] = True
|
|
72
|
+
if isinstance(flag_value, dict):
|
|
73
|
+
config['auto_memory_user_id'] = flag_value.get('user_id', 'default')
|
|
74
|
+
return config
|
|
75
|
+
|
|
76
|
+
def extract_memories(self, text: str, user_id: str = None, user_message: str = None) -> list:
|
|
77
|
+
"""
|
|
78
|
+
Extract and store memories from text.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
text: Assistant response text to extract memories from
|
|
82
|
+
user_id: User ID for memory isolation
|
|
83
|
+
user_message: Original user message (for context)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
List of extracted memories
|
|
87
|
+
"""
|
|
88
|
+
auto_memory = self._get_auto_memory(user_id)
|
|
89
|
+
if not auto_memory:
|
|
90
|
+
return []
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
# Use process_interaction which extracts AND stores memories
|
|
94
|
+
memories = auto_memory.process_interaction(
|
|
95
|
+
user_message=user_message or text,
|
|
96
|
+
assistant_response=text if user_message else None,
|
|
97
|
+
store=True # Store the memories
|
|
98
|
+
)
|
|
99
|
+
if memories:
|
|
100
|
+
self.print_status(f"🧠Extracted and stored {len(memories)} memories", "success")
|
|
101
|
+
return memories
|
|
102
|
+
except Exception as e:
|
|
103
|
+
self.log(f"Memory extraction failed: {e}", "error")
|
|
104
|
+
|
|
105
|
+
return []
|
|
106
|
+
|
|
107
|
+
def store_memory(self, content: str, user_id: str = None, importance: float = 0.5) -> bool:
|
|
108
|
+
"""
|
|
109
|
+
Store a memory.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
content: Memory content
|
|
113
|
+
user_id: User ID for memory isolation
|
|
114
|
+
importance: Importance score (0-1)
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
True if successful
|
|
118
|
+
"""
|
|
119
|
+
auto_memory = self._get_auto_memory(user_id)
|
|
120
|
+
if not auto_memory:
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
if hasattr(auto_memory, 'store'):
|
|
125
|
+
auto_memory.store(content, importance=importance)
|
|
126
|
+
elif hasattr(auto_memory, 'add'):
|
|
127
|
+
auto_memory.add(content, importance=importance)
|
|
128
|
+
|
|
129
|
+
self.print_status("✅ Memory stored", "success")
|
|
130
|
+
return True
|
|
131
|
+
except Exception as e:
|
|
132
|
+
self.log(f"Memory storage failed: {e}", "error")
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
def post_process_result(self, result: Any, flag_value: Any, user_message: str = None) -> Any:
|
|
136
|
+
"""
|
|
137
|
+
Post-process result to extract and store memories.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
result: Agent output
|
|
141
|
+
flag_value: Boolean or dict with configuration
|
|
142
|
+
user_message: Original user message for context
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Original result (memories are stored)
|
|
146
|
+
"""
|
|
147
|
+
if not flag_value:
|
|
148
|
+
return result
|
|
149
|
+
|
|
150
|
+
user_id = None
|
|
151
|
+
if isinstance(flag_value, dict):
|
|
152
|
+
user_id = flag_value.get('user_id')
|
|
153
|
+
user_message = flag_value.get('user_message', user_message)
|
|
154
|
+
|
|
155
|
+
# Extract and store memories from result
|
|
156
|
+
text = str(result)
|
|
157
|
+
memories = self.extract_memories(text, user_id, user_message=user_message)
|
|
158
|
+
|
|
159
|
+
if memories:
|
|
160
|
+
self.print_status("\n🧠Auto-extracted Memories:", "info")
|
|
161
|
+
for mem in memories:
|
|
162
|
+
mem_type = mem.get('type', 'unknown')
|
|
163
|
+
content = mem.get('content', str(mem))[:50]
|
|
164
|
+
self.print_status(f" • {mem_type}: {content}...", "info")
|
|
165
|
+
|
|
166
|
+
return result
|
|
167
|
+
|
|
168
|
+
def execute(self, text: str = None, user_id: str = None, **kwargs) -> Dict[str, Any]:
|
|
169
|
+
"""
|
|
170
|
+
Execute auto memory extraction.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
text: Text to process
|
|
174
|
+
user_id: User ID for memory isolation
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Dictionary of extracted memories
|
|
178
|
+
"""
|
|
179
|
+
if not text:
|
|
180
|
+
return {}
|
|
181
|
+
|
|
182
|
+
return self.extract_memories(text, user_id)
|