Skip to content

Commit e8ed1f9

Browse files
committed
Add sandbox token derivation helper
* Add a sandbox auth helper that derives per-run HMAC tokens from the internal platform token.
1 parent 0a57b8c commit e8ed1f9

4 files changed

Lines changed: 115 additions & 0 deletions

File tree

cli/polyaxon/_sandbox/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from polyaxon._sandbox.auth import (
2+
DERIVATION_PREFIX,
3+
derive_sandbox_token,
4+
derive_sandbox_token_from_env,
5+
)
6+
7+
8+
__all__ = [
9+
"DERIVATION_PREFIX",
10+
"derive_sandbox_token",
11+
"derive_sandbox_token_from_env",
12+
]

cli/polyaxon/_sandbox/auth.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import hashlib
2+
import hmac
3+
import os
4+
5+
from polyaxon._env_vars.keys import ENV_KEYS_SECRET_INTERNAL_TOKEN
6+
from polyaxon.exceptions import PolyaxonConverterError
7+
8+
9+
DERIVATION_PREFIX = b"sandbox:v1:"
10+
11+
12+
def derive_sandbox_token(signing_key: str, run_uuid: str) -> str:
13+
if not signing_key or not signing_key.strip():
14+
raise ValueError("A non-empty signing key is required.")
15+
if not run_uuid or not run_uuid.strip():
16+
raise ValueError("A non-empty run uuid is required.")
17+
18+
return hmac.new(
19+
signing_key.encode(),
20+
DERIVATION_PREFIX + run_uuid.encode(),
21+
hashlib.sha256,
22+
).hexdigest()
23+
24+
25+
def derive_sandbox_token_from_env(run_uuid: str) -> str:
26+
signing_key = os.environ.get(ENV_KEYS_SECRET_INTERNAL_TOKEN)
27+
if not signing_key or not signing_key.strip():
28+
raise PolyaxonConverterError(
29+
"plugins.sandbox is enabled but "
30+
f"{ENV_KEYS_SECRET_INTERNAL_TOKEN} is not set."
31+
)
32+
return derive_sandbox_token(signing_key, run_uuid)

cli/tests/test_sandbox/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import hashlib
2+
import hmac
3+
import os
4+
import uuid
5+
6+
from unittest import TestCase
7+
8+
import pytest
9+
10+
from polyaxon._env_vars.keys import ENV_KEYS_SECRET_INTERNAL_TOKEN
11+
from polyaxon._sandbox.auth import (
12+
DERIVATION_PREFIX,
13+
derive_sandbox_token,
14+
derive_sandbox_token_from_env,
15+
)
16+
from polyaxon.exceptions import PolyaxonConverterError
17+
18+
19+
@pytest.mark.utils_mark
20+
class TestSandboxAuth(TestCase):
21+
def setUp(self):
22+
super().setUp()
23+
self.current_internal_token = os.environ.get(ENV_KEYS_SECRET_INTERNAL_TOKEN)
24+
25+
def tearDown(self):
26+
if self.current_internal_token is None:
27+
os.environ.pop(ENV_KEYS_SECRET_INTERNAL_TOKEN, None)
28+
else:
29+
os.environ[ENV_KEYS_SECRET_INTERNAL_TOKEN] = self.current_internal_token
30+
super().tearDown()
31+
32+
def test_derive_sandbox_token(self):
33+
signing_key = "internal-token"
34+
run_uuid = uuid.uuid4().hex
35+
expected = hmac.new(
36+
signing_key.encode(),
37+
DERIVATION_PREFIX + run_uuid.encode(),
38+
hashlib.sha256,
39+
).hexdigest()
40+
41+
assert derive_sandbox_token(signing_key, run_uuid) == expected
42+
43+
def test_derive_sandbox_token_scopes_by_key_and_run_uuid(self):
44+
run_uuid = uuid.uuid4().hex
45+
token = derive_sandbox_token("internal-token", run_uuid)
46+
47+
assert token != derive_sandbox_token("other-token", run_uuid)
48+
assert token != derive_sandbox_token("internal-token", uuid.uuid4().hex)
49+
50+
def test_derive_sandbox_token_rejects_empty_inputs(self):
51+
with self.assertRaises(ValueError):
52+
derive_sandbox_token("", uuid.uuid4().hex)
53+
54+
with self.assertRaises(ValueError):
55+
derive_sandbox_token("internal-token", "")
56+
57+
def test_derive_sandbox_token_from_env(self):
58+
os.environ[ENV_KEYS_SECRET_INTERNAL_TOKEN] = "internal-token"
59+
run_uuid = uuid.uuid4().hex
60+
61+
assert derive_sandbox_token_from_env(run_uuid) == derive_sandbox_token(
62+
"internal-token", run_uuid
63+
)
64+
65+
def test_derive_sandbox_token_from_env_requires_internal_token(self):
66+
os.environ.pop(ENV_KEYS_SECRET_INTERNAL_TOKEN, None)
67+
68+
with self.assertRaises(PolyaxonConverterError) as ctx:
69+
derive_sandbox_token_from_env(uuid.uuid4().hex)
70+
assert ENV_KEYS_SECRET_INTERNAL_TOKEN in str(ctx.exception)

0 commit comments

Comments
 (0)