diff --git a/agent-node/src/agent_pb2.py b/agent-node/src/agent_pb2.py index 450935e..0bdab29 100644 --- a/agent-node/src/agent_pb2.py +++ b/agent-node/src/agent_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: agent.proto -# Protobuf Python Version: 5.29.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -11,9 +11,9 @@ from google.protobuf.internal import builder as _builder _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, - 5, - 29, - 0, + 6, + 31, + 1, '', 'agent.proto' ) diff --git a/agent-node/src/agent_pb2_grpc.py b/agent-node/src/agent_pb2_grpc.py index e972a62..e4fe22b 100644 --- a/agent-node/src/agent_pb2_grpc.py +++ b/agent-node/src/agent_pb2_grpc.py @@ -5,7 +5,7 @@ import agent_pb2 as agent__pb2 -GRPC_GENERATED_VERSION = '1.71.2' +GRPC_GENERATED_VERSION = '1.80.0' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -18,7 +18,7 @@ if _version_not_supported: raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' - + f' but the generated code in agent_pb2_grpc.py depends on' + + ' but the generated code in agent_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' diff --git a/ai-hub/tests/core/grpc/test_crypto.py b/ai-hub/tests/core/grpc/test_crypto.py new file mode 100644 index 0000000..4f48c26 --- /dev/null +++ b/ai-hub/tests/core/grpc/test_crypto.py @@ -0,0 +1,14 @@ +import pytest +from app.core.grpc.utils.crypto import sign_bytes, verify_bytes_signature, sign_payload, verify_signature + +def test_sign_and_verify_payload(): + payload = "hello world" + sig = sign_payload(payload) + assert verify_signature(payload, sig) is True + assert verify_signature(payload + "x", sig) is False + +def test_sign_and_verify_bytes(): + data = b"hello world" + sig = sign_bytes(data) + assert verify_bytes_signature(data, sig) is True + assert verify_bytes_signature(data + b"x", sig) is False diff --git a/ai-hub/tests/core/grpc/test_grpc_server.py b/ai-hub/tests/core/grpc/test_grpc_server.py index c852be5..ba3008f 100644 --- a/ai-hub/tests/core/grpc/test_grpc_server.py +++ b/ai-hub/tests/core/grpc/test_grpc_server.py @@ -51,3 +51,56 @@ def test_build_sandbox_policy_explicit_permissive(orchestrator): policy = orchestrator._build_sandbox_policy({"shell": {"sandbox": {"mode": "PERMISSIVE"}}}) assert policy.mode == agent_pb2.SandboxPolicy.PERMISSIVE + +def test_manifest_accumulation(orchestrator): + node_id = "test-node" + session_id = "session1" + + orchestrator.mirror = MagicMock() + orchestrator.mirror.reconcile.return_value = None + + # Send chunk 0 + msg1 = agent_pb2.ClientTaskMessage( + file_sync=agent_pb2.FileSyncMessage( + session_id=session_id, + manifest=agent_pb2.DirectoryManifest( + root_path="/tmp", + chunk_index=0, + is_final=False, + files=[agent_pb2.FileInfo(path="file1", is_dir=False, size=100)] + ) + ) + ) + orchestrator._handle_client_message(msg1, node_id, MagicMock()) + + key = (node_id, session_id) + assert key in orchestrator.manifest_accumulators + assert len(orchestrator.manifest_accumulators[key]) == 1 + + # Send chunk 1 (final) + msg2 = agent_pb2.ClientTaskMessage( + file_sync=agent_pb2.FileSyncMessage( + session_id=session_id, + manifest=agent_pb2.DirectoryManifest( + root_path="/tmp", + chunk_index=1, + is_final=True, + files=[agent_pb2.FileInfo(path="file2", is_dir=False, size=200)] + ) + ) + ) + + orchestrator._handle_client_message(msg2, node_id, MagicMock()) + + # After final chunk, it should be removed from accumulators + assert key not in orchestrator.manifest_accumulators + + # And mirror.reconcile should be called with full manifest! + orchestrator.mirror.reconcile.assert_called_once() + args, kwargs = orchestrator.mirror.reconcile.call_args + assert args[0] == session_id + full_manifest = args[1] + assert full_manifest.root_path == "/tmp" + assert len(full_manifest.files) == 2 + assert full_manifest.files[0].path == "file1" + assert full_manifest.files[1].path == "file2" diff --git a/scripts/remote_deploy.sh b/scripts/remote_deploy.sh index 0d73500..3eac690 100755 --- a/scripts/remote_deploy.sh +++ b/scripts/remote_deploy.sh @@ -6,11 +6,13 @@ USER="${REMOTE_USER}" PASS="${REMOTE_PASS}" +LOCAL_APP_DIR="${LOCAL_APP_DIR:-/app}" + # If credentials are missing, try to fetch from GitBucket Private Snippet if [ -z "$PASS" ] || [ -z "$HOST" ]; then # Load token/id from local env if present - if [ -f "/app/.env.gitbucket" ]; then - source "/app/.env.gitbucket" + if [ -f "$LOCAL_APP_DIR/.env.gitbucket" ]; then + source "$LOCAL_APP_DIR/.env.gitbucket" fi GITBUCKET_TOKEN="${GITBUCKET_TOKEN}" @@ -74,7 +76,7 @@ --exclude 'data/' \ --exclude 'CaudeCodeSourceCode/' \ --exclude '.env*' \ - -e "ssh -o StrictHostKeyChecking=no" /app/ "$USER@$HOST:$REMOTE_TMP" + -e "ssh -o StrictHostKeyChecking=no" "$LOCAL_APP_DIR/" "$USER@$HOST:$REMOTE_TMP" if [ $? -ne 0 ]; then echo "Rsync failed! Exiting."