From 7e9f4985cf754097d9b8b7765cc7e355ff9fa187 Mon Sep 17 00:00:00 2001 From: rookiestar28 <151893693+rookiestar28@users.noreply.github.com> Date: Mon, 16 Feb 2026 06:08:08 +0800 Subject: [PATCH] fix: remove leftover merge marker in pack registry --- services/observability/backpressure.py | 12 ++--- services/packs/pack_registry.py | 13 ++---- services/permission_posture.py | 48 ++++++++++++-------- tests/test_backpressure.py | 26 ++++++----- tests/test_packs.py | 2 +- tests/test_permission_posture.py | 60 ++++++++++++++++++------- tests/test_security_gate_permissions.py | 38 +++++++++------- tests/test_wp0_contract_baseline.py | 28 +++++++----- web/openclaw_ui.js | 1 - 9 files changed, 136 insertions(+), 92 deletions(-) diff --git a/services/observability/backpressure.py b/services/observability/backpressure.py index 0a2ba9c..56f95e2 100644 --- a/services/observability/backpressure.py +++ b/services/observability/backpressure.py @@ -40,11 +40,11 @@ class BoundedQueue(Generic[T]): def __init__(self, capacity: int) -> None: if capacity <= 0: raise ValueError("Capacity must be positive") - + self._capacity = capacity self._deque: Deque[T] = deque(maxlen=capacity) self._lock = threading.Lock() - + # Metrics self._high_watermark = 0 self._total_enqueued = 0 @@ -64,14 +64,14 @@ class BoundedQueue(Generic[T]): self._total_dropped += 1 self._last_drop_ts = time.time() dropped = True - + self._deque.append(item) self._total_enqueued += 1 - + current_size = len(self._deque) if current_size > self._high_watermark: self._high_watermark = current_size - + return not dropped def get_all(self) -> List[T]: @@ -88,7 +88,7 @@ class BoundedQueue(Generic[T]): high_watermark=self._high_watermark, total_enqueued=self._total_enqueued, total_dropped=self._total_dropped, - last_drop_ts=self._last_drop_ts + last_drop_ts=self._last_drop_ts, ) def clear(self) -> None: diff --git a/services/packs/pack_registry.py b/services/packs/pack_registry.py index 27deded..24e9b96 100644 --- a/services/packs/pack_registry.py +++ b/services/packs/pack_registry.py @@ -3,7 +3,6 @@ import re import shutil from typing import Dict, List, Optional -<<<<<<< HEAD from ..safe_io import resolve_under_root from .pack_archive import PackArchive, PackError from .pack_types import PackMetadata @@ -57,9 +56,7 @@ class PackRegistry: # A malicious pack.json could contain traversal sequences. _validate_pack_segment(name, "name") _validate_pack_segment(version, "version") - target_dir = resolve_under_root( - self.packs_dir, os.path.join(name, version) - ) + target_dir = resolve_under_root(self.packs_dir, os.path.join(name, version)) if os.path.exists(target_dir): if not overwrite: @@ -76,9 +73,7 @@ class PackRegistry: def uninstall_pack(self, name: str, version: str) -> bool: _validate_pack_segment(name, "name") _validate_pack_segment(version, "version") - target_dir = resolve_under_root( - self.packs_dir, os.path.join(name, version) - ) + target_dir = resolve_under_root(self.packs_dir, os.path.join(name, version)) if os.path.exists(target_dir): shutil.rmtree(target_dir) # Clean up parent if empty @@ -118,9 +113,7 @@ class PackRegistry: def get_pack_path(self, name: str, version: str) -> Optional[str]: _validate_pack_segment(name, "name") _validate_pack_segment(version, "version") - target_dir = resolve_under_root( - self.packs_dir, os.path.join(name, version) - ) + target_dir = resolve_under_root(self.packs_dir, os.path.join(name, version)) if os.path.exists(target_dir): return target_dir return None diff --git a/services/permission_posture.py b/services/permission_posture.py index 5fffbde..cc2b60d 100644 --- a/services/permission_posture.py +++ b/services/permission_posture.py @@ -60,24 +60,24 @@ class PermissionEvaluator: def evaluate(self) -> List[PermissionResult]: """Run all permission checks.""" results = [] - + # 1. State Directory results.append(self._check_state_dir()) # 2. Secrets File results.append(self._check_secrets_file()) - + return results def _check_state_dir(self) -> PermissionResult: """Check state directory permissions.""" path = self.state_dir if not path.exists(): - return PermissionResult( + return PermissionResult( resource="state_dir", severity=PermissionSeverity.SKIP, message="State directory does not exist", - code="perm.state_dir.missing" + code="perm.state_dir.missing", ) # Common: Must be writable by owner/current user @@ -88,7 +88,7 @@ class PermissionEvaluator: severity=PermissionSeverity.FAIL, message=f"State directory not writable: {path}", code="perm.state_dir.not_writable", - remediation="Ensure the process user has write access." + remediation="Ensure the process user has write access.", ) # POSIX Hardening @@ -97,13 +97,17 @@ class PermissionEvaluator: mode = path.stat().st_mode if mode & stat.S_IWOTH: # World writable is CRITICAL in Hardened - sev = PermissionSeverity.FAIL if self.profile == RuntimeProfile.HARDENED else PermissionSeverity.WARN + sev = ( + PermissionSeverity.FAIL + if self.profile == RuntimeProfile.HARDENED + else PermissionSeverity.WARN + ) return PermissionResult( resource="state_dir", severity=sev, - message="State directory is world-writable", + message="State directory is world-writable", code="perm.state_dir.world_writable", - remediation=f"chmod 700 {path}" + remediation=f"chmod 700 {path}", ) except Exception as e: logger.warning(f"Failed to stat state dir: {e}") @@ -112,19 +116,19 @@ class PermissionEvaluator: resource="state_dir", severity=PermissionSeverity.PASS, message="State directory permissions OK", - code="perm.state_dir.ok" + code="perm.state_dir.ok", ) def _check_secrets_file(self) -> PermissionResult: """Check secrets.json permissions.""" path = self.state_dir / "secrets.json" - + if not path.exists(): - return PermissionResult( + return PermissionResult( resource="secrets_file", - severity=PermissionSeverity.PASS, # Not an error to not exist + severity=PermissionSeverity.PASS, # Not an error to not exist message="Secrets file not present", - code="perm.secrets.missing" + code="perm.secrets.missing", ) if self.system != "Windows": @@ -132,13 +136,17 @@ class PermissionEvaluator: mode = path.stat().st_mode # Check World Readable/Writable if mode & (stat.S_IROTH | stat.S_IWOTH): - sev = PermissionSeverity.FAIL if self.profile == RuntimeProfile.HARDENED else PermissionSeverity.WARN + sev = ( + PermissionSeverity.FAIL + if self.profile == RuntimeProfile.HARDENED + else PermissionSeverity.WARN + ) return PermissionResult( resource="secrets_file", severity=sev, message="Secrets file is world-accessible", code="perm.secrets.world_accessible", - remediation=f"chmod 600 {path}" + remediation=f"chmod 600 {path}", ) except Exception as e: logger.warning(f"Failed to stat secrets file: {e}") @@ -147,7 +155,7 @@ class PermissionEvaluator: resource="secrets_file", severity=PermissionSeverity.PASS, message="Secrets file permissions OK", - code="perm.secrets.ok" + code="perm.secrets.ok", ) @@ -158,13 +166,15 @@ def evaluate_startup_permissions() -> Tuple[bool, List[PermissionResult]]: """ evaluator = PermissionEvaluator() results = evaluator.evaluate() - + # Block startup if any FAIL result exists failures = [r for r in results if r.severity == PermissionSeverity.FAIL] if failures: - logger.critical(f"Startup blocked by permission checks ({len(failures)} failures).") + logger.critical( + f"Startup blocked by permission checks ({len(failures)} failures)." + ) for f in failures: logger.critical(f" [{f.code}] {f.message} -> {f.remediation}") return False, results - + return True, results diff --git a/tests/test_backpressure.py b/tests/test_backpressure.py index e1e3c0e..ce504fa 100644 --- a/tests/test_backpressure.py +++ b/tests/test_backpressure.py @@ -1,31 +1,32 @@ - -import unittest import time +import unittest + from services.observability.backpressure import BoundedQueue + class TestBoundedQueue(unittest.TestCase): - + def test_capacity_and_drops(self): """Test strict capacity enforcement and drop counting.""" q = BoundedQueue[int](capacity=2) - + # 1. Fill to capacity self.assertTrue(q.enqueue(1)) self.assertTrue(q.enqueue(2)) - + stats = q.stats() self.assertEqual(stats.current_size, 2) self.assertEqual(stats.high_watermark, 2) self.assertEqual(stats.total_dropped, 0) - + # 2. Overflow (Drop Oldest) self.assertFalse(q.enqueue(3)) - + stats = q.stats() self.assertEqual(stats.current_size, 2) self.assertEqual(stats.total_dropped, 1) self.assertGreater(stats.last_drop_ts, 0) - + # Check content (1 should be dropped, 2 and 3 remain) items = q.get_all() self.assertEqual(items, [2, 3]) @@ -33,18 +34,19 @@ class TestBoundedQueue(unittest.TestCase): def test_stats_tracking(self): """Test cumulative stats logic.""" q = BoundedQueue[str](capacity=5) - + q.enqueue("a") q.enqueue("b") self.assertEqual(q.stats().high_watermark, 2) - - q.get_all() # Just reading doesn't change state - + + q.get_all() # Just reading doesn't change state + q.clear() stats = q.stats() self.assertEqual(stats.current_size, 0) self.assertEqual(stats.high_watermark, 0) self.assertEqual(stats.total_enqueued, 0) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_packs.py b/tests/test_packs.py index a28e304..32bc590 100644 --- a/tests/test_packs.py +++ b/tests/test_packs.py @@ -6,13 +6,13 @@ import unittest import zipfile from services.packs.pack_archive import PackArchive -from services.packs.pack_registry import PackRegistry, _validate_pack_segment from services.packs.pack_manifest import ( MAX_MANIFEST_FILES, PackError, validate_manifest_integrity, validate_pack_metadata, ) +from services.packs.pack_registry import PackRegistry, _validate_pack_segment from services.packs.pack_types import PackMetadata, PackType diff --git a/tests/test_permission_posture.py b/tests/test_permission_posture.py index 41bcff6..c756e81 100644 --- a/tests/test_permission_posture.py +++ b/tests/test_permission_posture.py @@ -1,16 +1,17 @@ - -import unittest import stat +import unittest from pathlib import Path from unittest.mock import MagicMock, patch + from services.permission_posture import ( PermissionEvaluator, PermissionResult, PermissionSeverity, - evaluate_startup_permissions + evaluate_startup_permissions, ) from services.runtime_profile import RuntimeProfile + class TestPermissionPosture(unittest.TestCase): @patch("services.permission_posture.get_runtime_profile") @@ -19,15 +20,23 @@ class TestPermissionPosture(unittest.TestCase): @patch("pathlib.Path.exists") @patch("os.access") @patch("pathlib.Path.stat") - def test_posix_hardened_fail(self, mock_stat, mock_access, mock_exists, mock_system, mock_get_state, mock_get_profile): + def test_posix_hardened_fail( + self, + mock_stat, + mock_access, + mock_exists, + mock_system, + mock_get_state, + mock_get_profile, + ): """Hardened profile fails on world-writable state dir.""" # Setup mock_get_profile.return_value = RuntimeProfile.HARDENED mock_get_state.return_value = "/tmp/state" mock_system.return_value = "Linux" mock_exists.return_value = True - mock_access.return_value = True # Writable by us - + mock_access.return_value = True # Writable by us + # Mock world-writable mode mock_stat_res = MagicMock() mock_stat_res.st_mode = stat.S_IWOTH | stat.S_IRWXU @@ -48,7 +57,15 @@ class TestPermissionPosture(unittest.TestCase): @patch("pathlib.Path.exists") @patch("os.access") @patch("pathlib.Path.stat") - def test_posix_minimal_warn(self, mock_stat, mock_access, mock_exists, mock_system, mock_get_state, mock_get_profile): + def test_posix_minimal_warn( + self, + mock_stat, + mock_access, + mock_exists, + mock_system, + mock_get_state, + mock_get_profile, + ): """Minimal profile warns on world-writable state dir.""" # Setup mock_get_profile.return_value = RuntimeProfile.MINIMAL @@ -56,7 +73,7 @@ class TestPermissionPosture(unittest.TestCase): mock_system.return_value = "Linux" mock_exists.return_value = True mock_access.return_value = True - + # Mock world-writable mode mock_stat_res = MagicMock() mock_stat_res.st_mode = stat.S_IWOTH | stat.S_IRWXU @@ -77,7 +94,15 @@ class TestPermissionPosture(unittest.TestCase): @patch("pathlib.Path.exists") @patch("os.access") @patch("pathlib.Path.stat") - def test_secrets_world_readable_hardened(self, mock_stat, mock_access, mock_exists, mock_system, mock_get_state, mock_get_profile): + def test_secrets_world_readable_hardened( + self, + mock_stat, + mock_access, + mock_exists, + mock_system, + mock_get_state, + mock_get_profile, + ): """Hardened profile fails on world-readable secrets.""" mock_get_profile.return_value = RuntimeProfile.HARDENED mock_get_state.return_value = "/tmp/state" @@ -89,10 +114,10 @@ class TestPermissionPosture(unittest.TestCase): mock_stat_res = MagicMock() mock_stat_res.st_mode = stat.S_IROTH | stat.S_IRWXU mock_stat.return_value = mock_stat_res - + evaluator = PermissionEvaluator() results = evaluator.evaluate() - + # Check secrets result secret_res = next(r for r in results if r.resource == "secrets_file") self.assertEqual(secret_res.severity, PermissionSeverity.FAIL) @@ -103,20 +128,23 @@ class TestPermissionPosture(unittest.TestCase): @patch("services.permission_posture.platform.system") @patch("pathlib.Path.exists") @patch("os.access") - def test_startup_gate_block(self, mock_access, mock_exists, mock_system, mock_get_state, mock_get_profile): + def test_startup_gate_block( + self, mock_access, mock_exists, mock_system, mock_get_state, mock_get_profile + ): """Ensure evaluate_startup_permissions returns False on failures.""" mock_get_profile.return_value = RuntimeProfile.HARDENED mock_get_state.return_value = "/tmp/state" mock_system.return_value = "Linux" mock_exists.return_value = True - + # Fail access check (critical for all profiles) - mock_access.return_value = False - + mock_access.return_value = False + allowed, results = evaluate_startup_permissions() - + self.assertFalse(allowed) self.assertTrue(any(r.severity == PermissionSeverity.FAIL for r in results)) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_security_gate_permissions.py b/tests/test_security_gate_permissions.py index e572801..6923e81 100644 --- a/tests/test_security_gate_permissions.py +++ b/tests/test_security_gate_permissions.py @@ -1,34 +1,37 @@ - import unittest -from unittest.mock import patch, MagicMock +from unittest.mock import MagicMock, patch + +from services.permission_posture import PermissionResult, PermissionSeverity from services.security_gate import SecurityGate, enforce_startup_gate -from services.permission_posture import PermissionResult, PermissionSeverity + class TestSecurityGatePermissions(unittest.TestCase): - + @patch("services.security_gate.is_hardened_mode") @patch("services.permission_posture.evaluate_startup_permissions") - @patch("services.access_control.is_auth_configured") # Patch source module + @patch("services.access_control.is_auth_configured") # Patch source module @patch("services.redaction.redact_text") - def test_gate_fails_on_permission_error(self, mock_redact, mock_auth, mock_eval_perms, mock_hardened): + def test_gate_fails_on_permission_error( + self, mock_redact, mock_auth, mock_eval_perms, mock_hardened + ): """Gate should report failure if permission check fails in Hardened mode.""" # Setup mock_hardened.return_value = True - mock_auth.return_value = True # Auth OK - mock_redact.return_value = "redacted" # Redaction OK - + mock_auth.return_value = True # Auth OK + mock_redact.return_value = "redacted" # Redaction OK + # Mock permission failure fail_res = PermissionResult( resource="test", severity=PermissionSeverity.FAIL, message="Test Perm Fail", - code="perm.test.fail" + code="perm.test.fail", ) mock_eval_perms.return_value = (False, [fail_res]) - + # Execute passed, reasons = SecurityGate.verify_mandatory_controls() - + # Assert self.assertFalse(passed) self.assertTrue(any("Test Perm Fail" in r for r in reasons)) @@ -37,21 +40,24 @@ class TestSecurityGatePermissions(unittest.TestCase): @patch("services.permission_posture.evaluate_startup_permissions") @patch("services.access_control.is_auth_configured") @patch("services.redaction.redact_text") - def test_gate_raise_exception(self, mock_redact, mock_auth, mock_eval_perms, mock_hardened): + def test_gate_raise_exception( + self, mock_redact, mock_auth, mock_eval_perms, mock_hardened + ): """enforce_startup_gate should raise RuntimeError on failure.""" mock_hardened.return_value = True mock_auth.return_value = True - + fail_res = PermissionResult( resource="test", severity=PermissionSeverity.FAIL, message="Test Perm Fail", - code="perm.test.fail" + code="perm.test.fail", ) mock_eval_perms.return_value = (False, [fail_res]) - + with self.assertRaises(RuntimeError): enforce_startup_gate() + if __name__ == "__main__": unittest.main() diff --git a/tests/test_wp0_contract_baseline.py b/tests/test_wp0_contract_baseline.py index 13433a5..3b90f60 100644 --- a/tests/test_wp0_contract_baseline.py +++ b/tests/test_wp0_contract_baseline.py @@ -1,10 +1,15 @@ - -import unittest import json +import unittest from dataclasses import asdict + +from services.job_events import JobEvent, JobEventStore, JobEventType from services.operator_doctor import CheckResult, DoctorReport, Severity -from services.security_doctor import SecurityCheckResult, SecurityReport, SecuritySeverity -from services.job_events import JobEvent, JobEventType, JobEventStore +from services.security_doctor import ( + SecurityCheckResult, + SecurityReport, + SecuritySeverity, +) + class TestWP0ContractBaseline(unittest.TestCase): """ @@ -20,7 +25,7 @@ class TestWP0ContractBaseline(unittest.TestCase): severity=Severity.PASS.value, message="Test Message", detail="Details", - remediation="Fix it" + remediation="Fix it", ) d = result.to_dict() self.assertEqual(d["name"], "test-check") @@ -44,13 +49,13 @@ class TestWP0ContractBaseline(unittest.TestCase): message="Security Fail", category="endpoint", detail="Detail", - remediation="Remedy" + remediation="Remedy", ) d = result.to_dict() self.assertEqual(d["name"], "sec-check") self.assertEqual(d["severity"], "fail") self.assertEqual(d["category"], "endpoint") - + report = SecurityReport() report.add(result) rd = report.to_dict() @@ -60,25 +65,26 @@ class TestWP0ContractBaseline(unittest.TestCase): def test_job_event_structure(self): """Verify Job Event structure and basic ring buffer behavior.""" store = JobEventStore(max_size=2) - + # Emit 1 e1 = store.emit(JobEventType.QUEUED, "p1") self.assertEqual(e1.seq, 1) self.assertEqual(e1.event_type, "queued") self.assertEqual(e1.prompt_id, "p1") - + # Emit 2 e2 = store.emit(JobEventType.RUNNING, "p1") self.assertEqual(e2.seq, 2) - + # Emit 3 (Should evict 1) e3 = store.emit(JobEventType.COMPLETED, "p1") self.assertEqual(e3.seq, 3) - + events = store.events_since(0) self.assertEqual(len(events), 2) self.assertEqual(events[0].seq, 2) self.assertEqual(events[1].seq, 3) + if __name__ == "__main__": unittest.main() diff --git a/web/openclaw_ui.js b/web/openclaw_ui.js index 8e96869..d884083 100644 --- a/web/openclaw_ui.js +++ b/web/openclaw_ui.js @@ -232,4 +232,3 @@ class QueueMonitor { export const moltbotUI = new MoltbotUI(); const monitor = new QueueMonitor(moltbotUI); monitor.start(); -