Skip to content

Commit 2a8abb1

Browse files
committed
feat(sdk): validate algorithm in getKey by checking OS version
When getKey is called with a non-secp256k1 algorithm (e.g. ed25519), the SDK calls the Version RPC to check if the OS supports it. If the Version RPC is unavailable (OS <= 0.5.6), the call is rejected with a clear error instead of silently returning the wrong key type.
1 parent c6b2d94 commit 2a8abb1

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

sdk/go/dstack/client.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,33 @@ func (c *DstackClient) GetTlsKey(
369369
return &response, nil
370370
}
371371

372+
// requiresVersionCheck returns true for algorithms that need OS >= 0.5.7.
373+
func requiresVersionCheck(algorithm string) bool {
374+
switch algorithm {
375+
case "secp256k1", "secp256k1_prehashed", "k256", "":
376+
return false
377+
default:
378+
return true
379+
}
380+
}
381+
382+
// ensureAlgorithmSupported checks the OS version when a non-secp256k1 algorithm is requested.
383+
// On old OS (no Version RPC), it returns an error to prevent silent key type mismatch.
384+
func (c *DstackClient) ensureAlgorithmSupported(ctx context.Context, algorithm string) error {
385+
if !requiresVersionCheck(algorithm) {
386+
return nil
387+
}
388+
if _, err := c.GetVersion(ctx); err != nil {
389+
return fmt.Errorf("algorithm %q is not supported: OS version too old (Version RPC unavailable)", algorithm)
390+
}
391+
return nil
392+
}
393+
372394
// Gets a key from the dstack service.
373395
func (c *DstackClient) GetKey(ctx context.Context, path string, purpose string, algorithm string) (*GetKeyResponse, error) {
396+
if err := c.ensureAlgorithmSupported(ctx, algorithm); err != nil {
397+
return nil, err
398+
}
374399
payload := map[string]interface{}{
375400
"path": path,
376401
"purpose": purpose,

sdk/js/src/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ export interface TlsKeyOptions {
177177
usageClientAuth?: boolean;
178178
}
179179

180+
const SECP256K1_ALGORITHMS = new Set(['secp256k1', 'secp256k1_prehashed', 'k256', ''])
181+
180182
export class DstackClient<T extends TcbInfo = TcbInfoV05x> {
181183
protected endpoint: string
182184

@@ -202,7 +204,17 @@ export class DstackClient<T extends TcbInfo = TcbInfoV05x> {
202204
this.endpoint = endpoint
203205
}
204206

207+
private async ensureAlgorithmSupported(algorithm: string): Promise<void> {
208+
if (SECP256K1_ALGORITHMS.has(algorithm)) return
209+
try {
210+
await this.version()
211+
} catch {
212+
throw new Error(`algorithm "${algorithm}" is not supported: OS version too old (Version RPC unavailable)`)
213+
}
214+
}
215+
205216
async getKey(path: string, purpose: string = '', algorithm: string = 'secp256k1'): Promise<GetKeyResponse> {
217+
await this.ensureAlgorithmSupported(algorithm)
206218
const payload = JSON.stringify({
207219
path: path,
208220
purpose: purpose,

sdk/python/src/dstack_sdk/dstack_client.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,26 @@ async def __aexit__(self, exc_type, exc_val, exc_tb):
380380
self._sync_client.close()
381381
self._sync_client = None
382382

383+
async def _ensure_algorithm_supported(self, algorithm: str) -> None:
384+
"""Check OS version when a non-secp256k1 algorithm is requested."""
385+
if algorithm in ("secp256k1", "secp256k1_prehashed", "k256", ""):
386+
return
387+
try:
388+
await self.version()
389+
except Exception:
390+
raise RuntimeError(
391+
f'algorithm "{algorithm}" is not supported: '
392+
"OS version too old (Version RPC unavailable)"
393+
)
394+
383395
async def get_key(
384396
self,
385397
path: str | None = None,
386398
purpose: str | None = None,
387399
algorithm: str = "secp256k1",
388400
) -> GetKeyResponse:
389401
"""Derive a key from the given path, purpose, and algorithm."""
402+
await self._ensure_algorithm_supported(algorithm)
390403
data: Dict[str, Any] = {
391404
"path": path or "",
392405
"purpose": purpose or "",

0 commit comments

Comments
 (0)