Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Record image-affecting changes to `manager/`, `worker/`, `copaw/`, `openclaw-bas

**Bug Fixes**

- **CoPaw Worker k8s storage**: CoPaw workers in self-hosted k8s deployments now fall back to static MinIO alias setup when `MC_HOST_hiclaw` is not injected, restoring startup `mc mirror` behavior while preserving cloud STS mode.
- **CoPaw Worker heartbeat**: CoPaw worker templates now seed heartbeat at a 10-minute interval so Team Leader agents created from the worker template can run heartbeat turns without requiring an explicit Team CR heartbeat spec.
- **Helm CRDs**: Removed unsupported `propertyNames` schema fields from Worker and Team CRDs so Kubernetes API servers accept the chart CRDs.
- **CoPaw local runtime paths**: CoPaw direct-run defaults now honor `COPAW_INSTALL_DIR` and `COPAW_WORKING_DIR` before falling back to local home-directory paths, while container entrypoints can continue to pass explicit directories.
Expand Down
12 changes: 8 additions & 4 deletions copaw/src/copaw_worker/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ def _ensure_alias(self) -> None:

Cloud mode (RRSA/STS): refresh credentials before every mc batch
via the shared shell function (lazy, no-op when token is valid).
Local mode: set mc alias once with static credentials.
Local and self-hosted k8s modes: set mc alias once with static
credentials, unless k8s already injected ``MC_HOST_hiclaw``.
"""
runtime = os.environ.get("HICLAW_RUNTIME", "<unset>")
mc_host_set = bool(os.environ.get(f"MC_HOST_{_MC_ALIAS}"))
Expand All @@ -297,8 +298,11 @@ def _ensure_alias(self) -> None:
mc_host_set,
controller_url,
)
if self._k8s_mode:
logger.info("_ensure_alias: k8s mode, skipping mc alias set (mc-wrapper handles credentials)")
if self._k8s_mode and mc_host_set:
logger.info(
"_ensure_alias: k8s mode with MC_HOST_%s, skipping static alias set",
_MC_ALIAS,
)
self._alias_set = True
return
if self._cloud_mode:
Expand All @@ -314,7 +318,7 @@ def _ensure_alias(self) -> None:
if self._alias_set:
logger.info("_ensure_alias: credential path=static, alias already set")
return
# Local mode: static credentials, set alias once
# Local and self-hosted k8s modes use static credentials.
if self.endpoint.startswith("http"):
url = self.endpoint
else:
Expand Down
31 changes: 30 additions & 1 deletion copaw/tests/test_worker_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
from copaw_worker.sync import FileSync


def test_ensure_alias_skips_static_alias_in_k8s_mode(monkeypatch, tmp_path):
def test_ensure_alias_skips_static_alias_in_k8s_mode_when_mc_host_exists(
monkeypatch, tmp_path
):
calls = []

monkeypatch.setenv("HICLAW_RUNTIME", "k8s")
monkeypatch.setenv("MC_HOST_hiclaw", "http://token@example.com")
monkeypatch.setattr(sync, "_mc", lambda *args, **_kwargs: calls.append(args))

fs = FileSync(
Expand All @@ -28,6 +31,32 @@ def test_ensure_alias_skips_static_alias_in_k8s_mode(monkeypatch, tmp_path):
assert calls == []


def test_ensure_alias_falls_back_to_static_alias_in_local_k8s(
monkeypatch, tmp_path
):
calls = []

monkeypatch.setenv("HICLAW_RUNTIME", "k8s")
monkeypatch.delenv("MC_HOST_hiclaw", raising=False)
monkeypatch.setattr(sync, "_mc", lambda *args, **_kwargs: calls.append(args))

fs = FileSync(
endpoint="minio:9000",
access_key="tt",
secret_key="secret",
bucket="hiclaw",
worker_name="tt",
local_dir=tmp_path,
)

fs._ensure_alias()

assert fs._alias_set is True
assert calls == [
("alias", "set", "hiclaw", "http://minio:9000", "tt", "secret")
]


def test_filesync_fallback_uses_copaw_working_dir_parent(monkeypatch, tmp_path):
working_dir = tmp_path / "alice" / ".copaw"
monkeypatch.setenv("COPAW_WORKING_DIR", str(working_dir))
Expand Down
Loading