Skip to content

Commit 23410d2

Browse files
committed
sdk: Add some missing fields in TcbInfo
1 parent 1ad75c0 commit 23410d2

File tree

9 files changed

+130
-11
lines changed

9 files changed

+130
-11
lines changed

sdk/go/dstack/client.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,17 @@ type EventLog struct {
4848

4949
// Represents the TCB information
5050
type TcbInfo struct {
51-
Mrtd string `json:"mrtd"`
52-
Rtmr0 string `json:"rtmr0"`
53-
Rtmr1 string `json:"rtmr1"`
54-
Rtmr2 string `json:"rtmr2"`
55-
Rtmr3 string `json:"rtmr3"`
56-
EventLog []EventLog `json:"event_log"`
51+
Mrtd string `json:"mrtd"`
52+
Rtmr0 string `json:"rtmr0"`
53+
Rtmr1 string `json:"rtmr1"`
54+
Rtmr2 string `json:"rtmr2"`
55+
Rtmr3 string `json:"rtmr3"`
56+
// The hash of the OS image. This is empty if the OS image is not measured by KMS.
57+
OsImageHash string `json:"os_image_hash,omitempty"`
58+
ComposeHash string `json:"compose_hash"`
59+
DeviceID string `json:"device_id"`
60+
AppCompose string `json:"app_compose"`
61+
EventLog []EventLog `json:"event_log"`
5762
}
5863

5964
// Represents the response from an info request
@@ -65,8 +70,9 @@ type InfoResponse struct {
6570
AppName string `json:"app_name"`
6671
DeviceID string `json:"device_id"`
6772
KeyProviderInfo string `json:"key_provider_info"`
68-
OsImageHash string `json:"os_image_hash"`
69-
ComposeHash string `json:"compose_hash"`
73+
// Optional: empty if OS image is not measured by KMS
74+
OsImageHash string `json:"os_image_hash,omitempty"`
75+
ComposeHash string `json:"compose_hash"`
7076
}
7177

7278
// DecodeTcbInfo decodes the TcbInfo string into a TcbInfo struct

sdk/go/dstack/client_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,18 @@ func TestInfo(t *testing.T) {
409409
if len(tcbInfo.EventLog) == 0 {
410410
t.Error("expected event log to not be empty")
411411
}
412+
413+
if tcbInfo.ComposeHash == "" {
414+
t.Error("expected compose_hash to not be empty")
415+
}
416+
417+
if tcbInfo.DeviceID == "" {
418+
t.Error("expected device_id to not be empty")
419+
}
420+
421+
if tcbInfo.AppCompose == "" {
422+
t.Error("expected app_compose to not be empty")
423+
}
412424
}
413425

414426
func TestGetKeySignatureVerification(t *testing.T) {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ describe('DstackClient', () => {
6767
expect(result.app_id).not.toBe('')
6868
expect(result.instance_id).not.toBe('')
6969
expect(result.tcb_info).not.toBe('')
70+
expect(result.tcb_info).toHaveProperty('os_image_hash')
71+
expect(result.tcb_info).toHaveProperty('compose_hash')
72+
expect(result.tcb_info).toHaveProperty('device_id')
73+
expect(result.tcb_info).toHaveProperty('app_compose')
74+
expect(result.tcb_info).toHaveProperty('event_log')
7075
})
7176

7277
it('should be able to decode tcb info', async () => {

sdk/js/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export interface InfoResponse {
4646
tcb_info: TcbInfo
4747
app_name: string
4848
device_id: string
49-
os_image_hash: string
49+
os_image_hash?: string // Optional: empty if OS image is not measured by KMS
5050
key_provider_info: string
5151
compose_hash: string
5252
}

sdk/python/src/dstack_sdk/dstack_client.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ class TcbInfo(BaseModel):
9595
rtmr1: str
9696
rtmr2: str
9797
rtmr3: str
98+
os_image_hash: str = "" # Optional: empty if OS image is not measured by KMS
99+
compose_hash: str
100+
device_id: str
101+
app_compose: str
98102
event_log: List[EventLog]
99103

100104

@@ -105,7 +109,7 @@ class InfoResponse(BaseModel):
105109
tcb_info: TcbInfo
106110
app_name: str
107111
device_id: str
108-
os_image_hash: str
112+
os_image_hash: str = "" # Optional: empty if OS image is not measured by KMS
109113
key_provider_info: str
110114
compose_hash: str
111115

sdk/python/tests/test_client.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from dstack_sdk.dstack_client import TcbInfo
2+
from dstack_sdk.dstack_client import InfoResponse
13
import hashlib
24
import pytest
35

@@ -25,6 +27,26 @@ def test_sync_client_get_tls_key():
2527
assert len(result.key) > 0
2628
assert len(result.certificate_chain) > 0
2729

30+
def test_sync_client_get_info():
31+
client = DstackClient()
32+
result = client.info()
33+
check_info_response(result)
34+
35+
def check_info_response(result: InfoResponse):
36+
assert isinstance(result, InfoResponse)
37+
assert isinstance(result.app_id, str)
38+
assert isinstance(result.instance_id, str)
39+
assert isinstance(result.tcb_info, TcbInfo)
40+
assert len(result.tcb_info.mrtd) == 96
41+
assert len(result.tcb_info.rtmr0) == 96
42+
assert len(result.tcb_info.rtmr1) == 96
43+
assert len(result.tcb_info.rtmr2) == 96
44+
assert len(result.tcb_info.rtmr3) == 96
45+
assert len(result.tcb_info.compose_hash) == 64
46+
assert len(result.tcb_info.device_id) == 64
47+
assert len(result.tcb_info.app_compose) > 0
48+
assert len(result.tcb_info.event_log) > 0
49+
2850
@pytest.mark.asyncio
2951
async def test_async_client_get_key():
3052
client = AsyncDstackClient()
@@ -46,6 +68,12 @@ async def test_async_client_get_tls_key():
4668
assert result.key.startswith('-----BEGIN PRIVATE KEY-----')
4769
assert len(result.certificate_chain) > 0
4870

71+
@pytest.mark.asyncio
72+
async def test_async_client_get_info():
73+
client = AsyncDstackClient()
74+
result = await client.info()
75+
check_info_response(result)
76+
4977
@pytest.mark.asyncio
5078
async def test_tls_key_uniqueness():
5179
"""Test that TLS keys are unique across multiple calls."""

sdk/run-tests.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
export DSTACK_SIMULATOR_ENDPOINT=$(realpath simulator/dstack.sock)
6+
export TAPPD_SIMULATOR_ENDPOINT=$(realpath simulator/tappd.sock)
7+
8+
pushd simulator
9+
./build.sh
10+
./dstack-simulator >/dev/null 2>&1 &
11+
SIMULATOR_PID=$!
12+
trap "kill $SIMULATOR_PID 2>/dev/null || true" EXIT
13+
popd
14+
15+
pushd rust/
16+
cargo test
17+
popd
18+
19+
pushd go/
20+
go test -v ./dstack
21+
DSTACK_SIMULATOR_ENDPOINT=$TAPPD_SIMULATOR_ENDPOINT go test -v ./tappd
22+
popd
23+
24+
pushd python/
25+
if [ ! -d .venv ]; then
26+
python -m venv .venv
27+
fi
28+
source .venv/bin/activate
29+
pip install -e .
30+
pip install pytest pytest-asyncio evidence-api web3 solders
31+
pytest
32+
popd
33+
34+
pushd js/
35+
npm install
36+
npm run test -- --run
37+
popd

sdk/rust/src/dstack_client.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ pub struct InfoResponse {
146146
/// The device identifier
147147
pub device_id: String,
148148
/// The hash of the OS image
149+
/// Optional: empty if OS image is not measured by KMS
150+
#[serde(default)]
149151
pub os_image_hash: String,
150152
/// Information about the key provider
151153
pub key_provider_info: String,
@@ -176,6 +178,15 @@ pub struct TcbInfo {
176178
pub rtmr2: String,
177179
/// The value of RTMR3 (Runtime Measurement Register 3)
178180
pub rtmr3: String,
181+
/// The hash of the OS image. This is empty if the OS image is not measured by KMS.
182+
#[serde(default)]
183+
pub os_image_hash: String,
184+
/// The hash of the compose configuration
185+
pub compose_hash: String,
186+
/// The device identifier
187+
pub device_id: String,
188+
/// The app compose
189+
pub app_compose: String,
179190
/// The event log entries
180191
pub event_log: Vec<EventLog>,
181192
}

sdk/rust/tests/test_client.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,21 @@ async fn test_report_data() {
7070
#[tokio::test]
7171
async fn test_info() {
7272
let client = AsyncDstackClient::new(None);
73-
let _info = client.info().await.unwrap();
73+
let info = client.info().await.unwrap();
74+
assert!(!info.app_id.is_empty());
75+
assert!(!info.instance_id.is_empty());
76+
assert!(!info.app_cert.is_empty());
77+
assert!(!info.tcb_info.mrtd.is_empty());
78+
assert!(!info.tcb_info.rtmr0.is_empty());
79+
assert!(!info.tcb_info.rtmr1.is_empty());
80+
assert!(!info.tcb_info.rtmr2.is_empty());
81+
assert!(!info.tcb_info.rtmr3.is_empty());
82+
assert!(!info.tcb_info.compose_hash.is_empty());
83+
assert!(!info.tcb_info.device_id.is_empty());
84+
assert!(!info.tcb_info.app_compose.is_empty());
85+
assert!(!info.tcb_info.event_log.is_empty());
86+
assert!(!info.app_name.is_empty());
87+
assert!(!info.device_id.is_empty());
88+
assert!(!info.key_provider_info.is_empty());
89+
assert!(!info.compose_hash.is_empty());
7490
}

0 commit comments

Comments
 (0)