File size: 4,482 Bytes
857a91b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package api

import (
	"net/http"
	"testing"
)

func TestCloudRuntimeAndProviderFlow(t *testing.T) {
	srv := authServer(t)

	// Create a workspace owner and grab a session token.
	rec, body := do(t, srv, http.MethodPost, "/v1/auth/signup", "", `{"name":"Maya","email":"maya@acme.io","password":"hunter22"}`)
	if rec.Code != http.StatusCreated {
		t.Fatalf("signup %d: %v", rec.Code, body)
	}
	token, _ := body["token"].(string)

	// Mint a join token.
	rec, body = do(t, srv, http.MethodPost, "/v1/cloud/join-tokens", token, `{"label":"my space","max_uses":1,"ttl_minutes":60}`)
	if rec.Code != http.StatusCreated {
		t.Fatalf("mint join token %d: %v", rec.Code, body)
	}
	secret, _ := body["secret"].(string)
	if secret == "" {
		t.Fatal("expected a join-token secret")
	}

	// Register a runtime using the join token (no session — simulates a remote Space).
	rec, body = do(t, srv, http.MethodPost, "/v1/cloud/runtimes/register", "",
		`{"join_token":"`+secret+`","name":"maya-space","kind":"hf-space","hf_space":"maya/matrixcloud","caps":["mcp.test"]}`)
	if rec.Code != http.StatusCreated {
		t.Fatalf("register runtime %d: %v", rec.Code, body)
	}
	runtimeToken, _ := body["runtime_token"].(string)
	if runtimeToken == "" {
		t.Fatal("expected a runtime token")
	}

	// The join token is single-use now.
	rec, _ = do(t, srv, http.MethodPost, "/v1/cloud/runtimes/register", "",
		`{"join_token":"`+secret+`","name":"again"}`)
	if rec.Code != http.StatusUnauthorized {
		t.Errorf("reused join token should 401, got %d", rec.Code)
	}

	// Heartbeat with the runtime token.
	rec, _ = do(t, srv, http.MethodPost, "/v1/cloud/runtimes/heartbeat", runtimeToken, `{"status":"online","caps":["mcp.test","model.inspect"]}`)
	if rec.Code != http.StatusOK {
		t.Fatalf("heartbeat %d", rec.Code)
	}
	// Bad runtime token rejected.
	rec, _ = do(t, srv, http.MethodPost, "/v1/cloud/runtimes/heartbeat", "bogus", `{"status":"online"}`)
	if rec.Code != http.StatusUnauthorized {
		t.Errorf("bad heartbeat token should 401, got %d", rec.Code)
	}

	// The owner sees the runtime online.
	rec, body = do(t, srv, http.MethodGet, "/v1/cloud/runtimes", token, "")
	if rec.Code != http.StatusOK {
		t.Fatalf("list runtimes %d", rec.Code)
	}
	rts, _ := body["runtimes"].([]any)
	if len(rts) != 1 {
		t.Fatalf("expected 1 runtime, got %d", len(rts))
	}

	// Store a BYO Hugging Face credential; only a hint is ever returned.
	rec, body = do(t, srv, http.MethodPost, "/v1/cloud/providers", token,
		`{"provider":"huggingface","label":"default","secret":"hf_supersecret9","meta":{"default_model":"Qwen/Qwen2.5-7B-Instruct"}}`)
	if rec.Code != http.StatusCreated {
		t.Fatalf("set provider %d: %v", rec.Code, body)
	}
	rec, body = do(t, srv, http.MethodGet, "/v1/cloud/providers", token, "")
	provs, _ := body["providers"].([]any)
	if len(provs) != 1 {
		t.Fatalf("expected 1 provider, got %v", body)
	}
	p0, _ := provs[0].(map[string]any)
	if hint, _ := p0["hint"].(string); hint == "" || hint == "hf_supersecret9" {
		t.Errorf("provider must expose only a hint, got %v", p0["hint"])
	}

	// Cloud endpoints require auth.
	rec, _ = do(t, srv, http.MethodGet, "/v1/cloud/runtimes", "", "")
	if rec.Code != http.StatusUnauthorized {
		t.Errorf("unauth list should 401, got %d", rec.Code)
	}
}

func TestAuditLogRecordsActions(t *testing.T) {
	srv := authServer(t)
	_, body := do(t, srv, http.MethodPost, "/v1/auth/signup", "", `{"name":"Auditor","email":"audit@acme.io","password":"hunter22"}`)
	token, _ := body["token"].(string)

	// Generate a couple of auditable actions.
	do(t, srv, http.MethodPost, "/v1/cloud/join-tokens", token, `{"label":"x","max_uses":1}`)
	do(t, srv, http.MethodPost, "/v1/cloud/providers", token, `{"provider":"huggingface","secret":"hf_abc1234"}`)

	rec, b := do(t, srv, http.MethodGet, "/v1/cloud/audit", token, "")
	if rec.Code != http.StatusOK {
		t.Fatalf("audit list %d: %v", rec.Code, b)
	}
	events, _ := b["events"].([]any)
	actions := map[string]bool{}
	for _, e := range events {
		if m, ok := e.(map[string]any); ok {
			actions[m["action"].(string)] = true
		}
	}
	for _, want := range []string{"user.signup", "runtime.join_token.created", "provider.credential.added"} {
		if !actions[want] {
			t.Errorf("missing audit action %q (got %v)", want, actions)
		}
	}
	// Unauthenticated access is rejected.
	if rec, _ := do(t, srv, http.MethodGet, "/v1/cloud/audit", "", ""); rec.Code != http.StatusUnauthorized {
		t.Errorf("unauth audit = %d, want 401", rec.Code)
	}
}