programgarden 1.26.0__tar.gz → 1.28.0__tar.gz

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.
Files changed (37) hide show
  1. {programgarden-1.26.0 → programgarden-1.28.0}/PKG-INFO +2 -2
  2. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/__init__.py +1 -1
  3. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/context.py +29 -9
  4. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/executor.py +342 -175
  5. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/resolver.py +315 -0
  6. {programgarden-1.26.0 → programgarden-1.28.0}/pyproject.toml +2 -2
  7. {programgarden-1.26.0 → programgarden-1.28.0}/README.md +0 -0
  8. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/binding_validator.py +0 -0
  9. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/client.py +0 -0
  10. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/code_worker.py +0 -0
  11. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/database/__init__.py +0 -0
  12. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/database/checkpoint_manager.py +0 -0
  13. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/database/query_builder.py +0 -0
  14. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/database/workflow_position_tracker.py +0 -0
  15. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/database/workflow_risk_tracker.py +0 -0
  16. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/deep_fixtures.py +0 -0
  17. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/node_runner.py +0 -0
  18. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/plugin/__init__.py +0 -0
  19. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/plugin/sandbox.py +0 -0
  20. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/providers/__init__.py +0 -0
  21. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/providers/llm_errors.py +0 -0
  22. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/providers/llm_provider.py +0 -0
  23. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/reconnect_handler.py +0 -0
  24. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/resource/__init__.py +0 -0
  25. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/resource/context.py +0 -0
  26. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/resource/limiter.py +0 -0
  27. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/resource/monitor.py +0 -0
  28. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/resource/throttle.py +0 -0
  29. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/semantic_rules.py +0 -0
  30. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/tools/__init__.py +0 -0
  31. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/tools/credential_tools.py +0 -0
  32. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/tools/definition_tools.py +0 -0
  33. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/tools/event_tools.py +0 -0
  34. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/tools/job_tools.py +0 -0
  35. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/tools/registry_tools.py +0 -0
  36. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/tools/sqlite_tools.py +0 -0
  37. {programgarden-1.26.0 → programgarden-1.28.0}/programgarden/validation_recommender.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programgarden
3
- Version: 1.26.0
3
+ Version: 1.28.0
4
4
  Summary: ProgramGarden - 노드 기반 자동매매 DSL 실행 엔진
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Author: 프로그램동산
@@ -16,7 +16,7 @@ Requires-Dist: croniter (>=6.0.0,<7.0.0)
16
16
  Requires-Dist: litellm (>=1.40.0)
17
17
  Requires-Dist: lxml (>=6.0.2,<7.0.0)
18
18
  Requires-Dist: programgarden-community (>=1.13.11,<2.0.0)
19
- Requires-Dist: programgarden-core (>=1.18.0,<2.0.0)
19
+ Requires-Dist: programgarden-core (>=1.20.0,<2.0.0)
20
20
  Requires-Dist: programgarden-finance (>=1.6.14,<2.0.0)
21
21
  Requires-Dist: psutil (>=6.0.0,<7.0.0)
22
22
  Requires-Dist: psycopg2-binary (>=2.9.11,<3.0.0)
@@ -91,7 +91,7 @@ except ImportError:
91
91
  # Community package not installed
92
92
  pass
93
93
 
94
- __version__ = "1.18.0"
94
+ __version__ = "1.28.0"
95
95
  __all__ = [
96
96
  # Core
97
97
  "ProgramGarden",
@@ -2626,26 +2626,46 @@ class ExecutionContext:
2626
2626
  logger.warning(f"Failed to sync fills from history: {e}")
2627
2627
  return 0
2628
2628
 
2629
+ # 노드 출력에 실려 외부로 나가면 안 되는 키 (부분일치, 소문자 비교).
2630
+ # BrokerNode 는 `connection.appkey/appsecret` 을 하류 노드에 넘기기 위해 **출력에 싣는다**
2631
+ # (내부 전송 경로라 지울 수 없다). 따라서 외부로 나가는 모든 경계에서 가려야 한다.
2632
+ SENSITIVE_OUTPUT_KEYS = frozenset(
2633
+ {"appkey", "appsecret", "secret", "password", "token", "api_key", "apikey", "private_key"}
2634
+ )
2635
+
2636
+ def _sanitize_value(self, value: Any) -> Any:
2637
+ """dict/list 를 재귀적으로 훑어 민감 키를 가린다."""
2638
+ if isinstance(value, dict):
2639
+ return self._sanitize_outputs(value)
2640
+ if isinstance(value, (list, tuple)):
2641
+ # 리스트 안의 dict 도 가려야 한다 (예: credentials[] 배열).
2642
+ sanitized_items = [self._sanitize_value(item) for item in value]
2643
+ return type(value)(sanitized_items) if isinstance(value, tuple) else sanitized_items
2644
+ return value
2645
+
2629
2646
  def _sanitize_outputs(self, outputs: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
2630
2647
  """Remove sensitive information from outputs."""
2631
2648
  # None은 None으로 반환, 빈 딕셔너리 {}는 그대로 유지
2632
2649
  if outputs is None:
2633
2650
  return None
2634
-
2635
- # Filter sensitive keywords
2636
- sensitive_keys = {"appkey", "appsecret", "secret", "password", "token", "api_key"}
2651
+
2637
2652
  sanitized = {}
2638
-
2639
2653
  for k, v in outputs.items():
2640
- if any(sk in k.lower() for sk in sensitive_keys):
2654
+ if any(sk in str(k).lower() for sk in self.SENSITIVE_OUTPUT_KEYS):
2641
2655
  sanitized[k] = "[REDACTED]"
2642
- elif isinstance(v, dict):
2643
- sanitized[k] = self._sanitize_outputs(v)
2644
2656
  else:
2645
- sanitized[k] = v
2646
-
2657
+ sanitized[k] = self._sanitize_value(v)
2658
+
2647
2659
  return sanitized
2648
2660
 
2661
+ def get_all_outputs_sanitized(self, node_id: str) -> Dict[str, Any]:
2662
+ """외부로 내보낼 노드 출력 — 민감 키가 가려진 사본.
2663
+
2664
+ 내부 전송(바인딩 해석 · broker connection auto-inject)은 `get_all_outputs()` 의
2665
+ raw 값을 그대로 쓰고, **외부 노출면**(리스너 이벤트 · `get_state()`)만 이걸 쓴다.
2666
+ """
2667
+ return self._sanitize_outputs(self.get_all_outputs(node_id)) or {}
2668
+
2649
2669
  # === Logging ===
2650
2670
 
2651
2671
  def log(