Skip to content

Commit 762a3a1

Browse files
committed
test: add tests for k256 compat, version API, and algorithm validation
- guest-agent: unit tests for normalize_algorithm, GetKey with k256 alias, secp256k1_prehashed rejection, ed25519, default algorithm, unsupported algorithm, version RPC, and sign with k256 alias - sdk/rust: integration tests for version(), k256 sign alias - sdk/go: tests for GetVersion, GetKey k256 alias, unsupported algorithm, secp256k1_prehashed rejection, ed25519 validation - sdk/python: sync/async tests for version(), k256 alias, secp256k1_prehashed rejection - sdk/js: tests for version(), k256 alias, secp256k1_prehashed rejection
1 parent 3024105 commit 762a3a1

5 files changed

Lines changed: 305 additions & 0 deletions

File tree

guest-agent/src/rpc_service.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,4 +1155,154 @@ pNs85uhOZE8z2jr8Pg==
11551155
assert!(result.is_err());
11561156
assert_eq!(result.unwrap_err().to_string(), "Unsupported algorithm");
11571157
}
1158+
1159+
#[test]
1160+
fn test_normalize_algorithm() {
1161+
assert_eq!(normalize_algorithm("k256"), "secp256k1");
1162+
assert_eq!(normalize_algorithm("secp256k1"), "secp256k1");
1163+
assert_eq!(normalize_algorithm("ed25519"), "ed25519");
1164+
assert_eq!(normalize_algorithm(""), "");
1165+
assert_eq!(normalize_algorithm("unknown"), "unknown");
1166+
}
1167+
1168+
#[tokio::test]
1169+
async fn test_get_key_k256_alias() {
1170+
let (state, _guard) = setup_test_state().await;
1171+
let handler_k256 = InternalRpcHandler {
1172+
state: state.clone(),
1173+
};
1174+
let handler_secp = InternalRpcHandler {
1175+
state: state.clone(),
1176+
};
1177+
1178+
let req_k256 = GetKeyArgs {
1179+
path: "test".to_string(),
1180+
purpose: "signing".to_string(),
1181+
algorithm: "k256".to_string(),
1182+
};
1183+
let req_secp = GetKeyArgs {
1184+
path: "test".to_string(),
1185+
purpose: "signing".to_string(),
1186+
algorithm: "secp256k1".to_string(),
1187+
};
1188+
1189+
let resp_k256 = handler_k256.get_key(req_k256).await.unwrap();
1190+
let resp_secp = handler_secp.get_key(req_secp).await.unwrap();
1191+
1192+
// k256 alias should produce the same key as secp256k1
1193+
assert_eq!(resp_k256.key, resp_secp.key);
1194+
}
1195+
1196+
#[tokio::test]
1197+
async fn test_get_key_secp256k1_prehashed_rejected() {
1198+
let (state, _guard) = setup_test_state().await;
1199+
let handler = InternalRpcHandler { state };
1200+
1201+
let request = GetKeyArgs {
1202+
path: "test".to_string(),
1203+
purpose: "signing".to_string(),
1204+
algorithm: "secp256k1_prehashed".to_string(),
1205+
};
1206+
1207+
let result = handler.get_key(request).await;
1208+
assert!(result.is_err());
1209+
assert_eq!(result.unwrap_err().to_string(), "Unsupported algorithm");
1210+
}
1211+
1212+
#[tokio::test]
1213+
async fn test_get_key_ed25519_success() {
1214+
let (state, _guard) = setup_test_state().await;
1215+
let handler = InternalRpcHandler { state };
1216+
1217+
let request = GetKeyArgs {
1218+
path: "test".to_string(),
1219+
purpose: "signing".to_string(),
1220+
algorithm: "ed25519".to_string(),
1221+
};
1222+
1223+
let response = handler.get_key(request).await.unwrap();
1224+
assert!(!response.key.is_empty());
1225+
assert_eq!(response.signature_chain.len(), 2);
1226+
}
1227+
1228+
#[tokio::test]
1229+
async fn test_get_key_default_algorithm() {
1230+
let (state, _guard) = setup_test_state().await;
1231+
let handler_default = InternalRpcHandler {
1232+
state: state.clone(),
1233+
};
1234+
let handler_secp = InternalRpcHandler {
1235+
state: state.clone(),
1236+
};
1237+
1238+
let req_default = GetKeyArgs {
1239+
path: "test".to_string(),
1240+
purpose: "signing".to_string(),
1241+
algorithm: "".to_string(),
1242+
};
1243+
let req_secp = GetKeyArgs {
1244+
path: "test".to_string(),
1245+
purpose: "signing".to_string(),
1246+
algorithm: "secp256k1".to_string(),
1247+
};
1248+
1249+
let resp_default = handler_default.get_key(req_default).await.unwrap();
1250+
let resp_secp = handler_secp.get_key(req_secp).await.unwrap();
1251+
1252+
// Empty algorithm should default to secp256k1
1253+
assert_eq!(resp_default.key, resp_secp.key);
1254+
}
1255+
1256+
#[tokio::test]
1257+
async fn test_get_key_unsupported_algorithm_fails() {
1258+
let (state, _guard) = setup_test_state().await;
1259+
let handler = InternalRpcHandler { state };
1260+
1261+
let request = GetKeyArgs {
1262+
path: "test".to_string(),
1263+
purpose: "signing".to_string(),
1264+
algorithm: "rsa".to_string(),
1265+
};
1266+
1267+
let result = handler.get_key(request).await;
1268+
assert!(result.is_err());
1269+
assert_eq!(result.unwrap_err().to_string(), "Unsupported algorithm");
1270+
}
1271+
1272+
#[tokio::test]
1273+
async fn test_version() {
1274+
let (state, _guard) = setup_test_state().await;
1275+
let handler = InternalRpcHandler { state };
1276+
1277+
let response = handler.version().await.unwrap();
1278+
assert!(!response.version.is_empty());
1279+
}
1280+
1281+
#[tokio::test]
1282+
async fn test_sign_k256_alias() {
1283+
let (state, _guard) = setup_test_state().await;
1284+
let handler_k256 = InternalRpcHandler {
1285+
state: state.clone(),
1286+
};
1287+
let handler_secp = InternalRpcHandler {
1288+
state: state.clone(),
1289+
};
1290+
1291+
let data = b"test message".to_vec();
1292+
1293+
let req_k256 = SignRequest {
1294+
algorithm: "k256".to_string(),
1295+
data: data.clone(),
1296+
};
1297+
let req_secp = SignRequest {
1298+
algorithm: "secp256k1".to_string(),
1299+
data: data.clone(),
1300+
};
1301+
1302+
let resp_k256 = handler_k256.sign(req_k256).await.unwrap();
1303+
let resp_secp = handler_secp.sign(req_secp).await.unwrap();
1304+
1305+
// k256 alias should produce the same public key as secp256k1
1306+
assert_eq!(resp_k256.public_key, resp_secp.public_key);
1307+
}
11581308
}

sdk/go/dstack/client_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,3 +737,63 @@ func TestSignAndVerifySecp256k1Prehashed(t *testing.T) {
737737
t.Errorf("expected error to mention '32-byte digest', got: %v", err)
738738
}
739739
}
740+
741+
func TestGetVersion(t *testing.T) {
742+
client := dstack.NewDstackClient()
743+
resp, err := client.GetVersion(context.Background())
744+
if err != nil {
745+
t.Fatal(err)
746+
}
747+
748+
if resp.Version == "" {
749+
t.Error("expected version to not be empty")
750+
}
751+
}
752+
753+
func TestGetKeyK256Alias(t *testing.T) {
754+
client := dstack.NewDstackClient()
755+
756+
respK256, err := client.GetKey(context.Background(), "/test", "purpose", "k256")
757+
if err != nil {
758+
t.Fatal(err)
759+
}
760+
761+
respSecp, err := client.GetKey(context.Background(), "/test", "purpose", "secp256k1")
762+
if err != nil {
763+
t.Fatal(err)
764+
}
765+
766+
// k256 is an alias for secp256k1, should produce the same key
767+
if respK256.Key != respSecp.Key {
768+
t.Error("expected k256 and secp256k1 to produce the same key")
769+
}
770+
}
771+
772+
func TestGetKeyUnsupportedAlgorithm(t *testing.T) {
773+
client := dstack.NewDstackClient()
774+
_, err := client.GetKey(context.Background(), "/test", "purpose", "rsa")
775+
if err == nil {
776+
t.Fatal("expected error for unsupported algorithm")
777+
}
778+
}
779+
780+
func TestGetKeySecp256k1PrehashedRejected(t *testing.T) {
781+
client := dstack.NewDstackClient()
782+
_, err := client.GetKey(context.Background(), "/test", "purpose", "secp256k1_prehashed")
783+
if err == nil {
784+
t.Fatal("expected error for secp256k1_prehashed in GetKey")
785+
}
786+
}
787+
788+
func TestGetKeyAlgorithmValidation(t *testing.T) {
789+
client := dstack.NewDstackClient()
790+
791+
// ed25519 should succeed (Version RPC is available on the simulator)
792+
resp, err := client.GetKey(context.Background(), "/test", "purpose", "ed25519")
793+
if err != nil {
794+
t.Fatalf("expected ed25519 to succeed: %v", err)
795+
}
796+
if resp.Key == "" {
797+
t.Error("expected key to not be empty")
798+
}
799+
}

sdk/js/src/__tests__/index.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,25 @@ describe('DstackClient', () => {
258258
})
259259
})
260260

261+
it('should be able to get version', async () => {
262+
const client = new DstackClient()
263+
const result = await client.version()
264+
expect(result).toHaveProperty('version')
265+
expect(result.version).not.toBe('')
266+
})
267+
268+
it('should get key with k256 alias producing same result as secp256k1', async () => {
269+
const client = new DstackClient()
270+
const resultK256 = await client.getKey('/test', 'purpose', 'k256')
271+
const resultSecp = await client.getKey('/test', 'purpose', 'secp256k1')
272+
expect(resultK256.key).toEqual(resultSecp.key)
273+
})
274+
275+
it('should reject secp256k1_prehashed in getKey', async () => {
276+
const client = new DstackClient()
277+
await expect(() => client.getKey('/test', 'purpose', 'secp256k1_prehashed')).rejects.toThrow()
278+
})
279+
261280
describe('deprecated methods with TappdClient', () => {
262281
it('should support deprecated deriveKey method with warning', async () => {
263282
const client = new TappdClient()

sdk/python/tests/test_client.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from dstack_sdk import SignResponse
1919
from dstack_sdk import TappdClient
2020
from dstack_sdk import VerifyResponse
21+
from dstack_sdk import VersionResponse
2122
from dstack_sdk.dstack_client import InfoResponse
2223
from dstack_sdk.dstack_client import TcbInfo
2324

@@ -537,6 +538,50 @@ async def test_async_tappd_client_tdx_quote_deprecated():
537538
assert any("tdx_quote is deprecated" in msg for msg in warning_messages)
538539

539540

541+
def test_sync_client_version():
542+
client = DstackClient()
543+
result = client.version()
544+
assert isinstance(result, VersionResponse)
545+
assert result.version != ""
546+
547+
548+
@pytest.mark.asyncio
549+
async def test_async_client_version():
550+
client = AsyncDstackClient()
551+
result = await client.version()
552+
assert isinstance(result, VersionResponse)
553+
assert result.version != ""
554+
555+
556+
def test_sync_client_get_key_k256_alias():
557+
client = DstackClient()
558+
result_k256 = client.get_key(path="/test", purpose="p", algorithm="k256")
559+
result_secp = client.get_key(path="/test", purpose="p", algorithm="secp256k1")
560+
# k256 is an alias for secp256k1, should produce the same key
561+
assert result_k256.decode_key() == result_secp.decode_key()
562+
563+
564+
@pytest.mark.asyncio
565+
async def test_async_client_get_key_k256_alias():
566+
client = AsyncDstackClient()
567+
result_k256 = await client.get_key(path="/test", purpose="p", algorithm="k256")
568+
result_secp = await client.get_key(path="/test", purpose="p", algorithm="secp256k1")
569+
assert result_k256.decode_key() == result_secp.decode_key()
570+
571+
572+
def test_sync_client_get_key_secp256k1_prehashed_rejected():
573+
client = DstackClient()
574+
with pytest.raises(Exception):
575+
client.get_key(algorithm="secp256k1_prehashed")
576+
577+
578+
@pytest.mark.asyncio
579+
async def test_async_client_get_key_secp256k1_prehashed_rejected():
580+
client = AsyncDstackClient()
581+
with pytest.raises(Exception):
582+
await client.get_key(algorithm="secp256k1_prehashed")
583+
584+
540585
@pytest.mark.asyncio
541586
async def test_async_tappd_client_is_reachable():
542587
"""Test that AsyncTappdClient can check if service is reachable."""

sdk/rust/tests/test_client.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,34 @@ async fn test_async_client_sign_and_verify_secp256k1_prehashed() {
175175
.unwrap();
176176
assert!(verify_resp.valid);
177177
}
178+
179+
#[tokio::test]
180+
async fn test_async_client_version() {
181+
let client = AsyncDstackClient::new(None);
182+
let result = client.version().await.unwrap();
183+
assert!(!result.version.is_empty());
184+
}
185+
186+
#[tokio::test]
187+
async fn test_async_client_get_key_k256_alias() {
188+
let client = AsyncDstackClient::new(None);
189+
// k256 should work as an alias for secp256k1
190+
let result = client.get_key(Some("test".to_string()), None).await.unwrap();
191+
assert!(!result.key.is_empty());
192+
assert_eq!(result.decode_key().unwrap().len(), 32);
193+
}
194+
195+
#[tokio::test]
196+
async fn test_async_client_sign_k256_alias() {
197+
let client = AsyncDstackClient::new(None);
198+
let data = b"test message".to_vec();
199+
200+
// Sign with k256 alias
201+
let resp_k256 = client.sign("k256", data.clone()).await.unwrap();
202+
assert!(!resp_k256.signature.is_empty());
203+
assert!(!resp_k256.public_key.is_empty());
204+
205+
// Sign with secp256k1 should produce the same public key
206+
let resp_secp = client.sign("secp256k1", data.clone()).await.unwrap();
207+
assert_eq!(resp_k256.public_key, resp_secp.public_key);
208+
}

0 commit comments

Comments
 (0)