feat(httpapi): return replica docker install commands on speaker create
quality / commitlint (push) Skipped
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / openapi (push) Failing after 21s
quality / web (push) Successful in 55s
quality / go (push) Successful in 1m2s
quality / bird2 (push) Successful in 16s
CD / quality (push) Failing after 2m49s
CD / publish (push) Skipped
quality / commitlint (push) Skipped
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / openapi (push) Failing after 21s
quality / web (push) Successful in 55s
quality / go (push) Successful in 1m2s
quality / bird2 (push) Successful in 16s
CD / quality (push) Failing after 2m49s
CD / publish (push) Skipped
После создания реплики 201 отдаёт agent_secret, node_token и install.docker_commands (bird2 + agent + Traefik DNS-01). UI показывает шаг установки вместо закрытия диалога, чтобы секрет больше не терялся. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -33,12 +33,23 @@ func TestPostSpeaker_defaultsFromEndpointIP(t *testing.T) {
|
||||
if out["agent_secret"] == nil || out["agent_secret"] == "" {
|
||||
t.Fatal("expected agent_secret on create")
|
||||
}
|
||||
if out["node_token"] == nil || out["node_token"] == "" {
|
||||
t.Fatal("expected node_token on replica create")
|
||||
}
|
||||
if out["node_ipv4"] != "203.0.113.55" {
|
||||
t.Fatalf("node_ipv4: %#v", out["node_ipv4"])
|
||||
}
|
||||
if out["bird_bgp_source_ipv4"] != "203.0.113.55" {
|
||||
t.Fatalf("bird_bgp_source_ipv4: %#v", out["bird_bgp_source_ipv4"])
|
||||
}
|
||||
install, _ := out["install"].(map[string]any)
|
||||
if install == nil {
|
||||
t.Fatal("expected install on replica create")
|
||||
}
|
||||
cmd, _ := install["docker_commands"].(string)
|
||||
if !strings.Contains(cmd, "traefik") || !strings.Contains(cmd, "dnschallenge") {
|
||||
t.Fatalf("docker_commands missing traefik dns challenge: %s", cmd[:min(200, len(cmd))])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteSpeaker(t *testing.T) {
|
||||
@@ -84,3 +95,103 @@ func TestGetBundleSigningPublicKey(t *testing.T) {
|
||||
t.Fatalf("missing public_key_base64: %#v", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostSpeaker_installCommandsAndMetaObject(t *testing.T) {
|
||||
srv, err := New(Options{InsecureDev: true, SeedDemo: true, BundleSeedHex: testBundleSeed})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer srv.Close()
|
||||
tenant, _, _, _, _ := srv.Store().DemoIDs()
|
||||
mustSetTestAPIKeys(t, srv, "edkey|"+tenant+"|editor")
|
||||
|
||||
body := `{
|
||||
"endpoint":"https://bgp-dc2.example.com",
|
||||
"role":"replica",
|
||||
"meta_json":{"agent_domain":"bgp-dc2.example.com","node_ipv4":"203.0.113.10"},
|
||||
"letsencrypt_email":"[email protected]",
|
||||
"cf_dns_api_token":"cf-token-xyz",
|
||||
"panel_ip_whitelist":"203.0.113.1/32",
|
||||
"control_plane_url":"https://cp.example.com"
|
||||
}`
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/speakers", strings.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer edkey")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
h := srv.Handler()
|
||||
h.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var out map[string]any
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
id, _ := out["id"].(string)
|
||||
if id == "" {
|
||||
t.Fatal("missing id")
|
||||
}
|
||||
secret, _ := out["agent_secret"].(string)
|
||||
token, _ := out["node_token"].(string)
|
||||
pub, _ := out["bundle_pubkey_base64"].(string)
|
||||
if secret == "" || token == "" || pub == "" {
|
||||
t.Fatalf("missing one-shot secrets: %#v", out)
|
||||
}
|
||||
install, _ := out["install"].(map[string]any)
|
||||
cmd, _ := install["docker_commands"].(string)
|
||||
for _, want := range []string{
|
||||
"traefik",
|
||||
"dnschallenge=true",
|
||||
"dnschallenge.provider=cloudflare",
|
||||
"CF_DNS_API_TOKEN",
|
||||
"cf-token-xyz",
|
||||
"Host(`bgp-dc2.example.com`)",
|
||||
secret,
|
||||
token,
|
||||
"https://cp.example.com",
|
||||
} {
|
||||
if !strings.Contains(cmd, want) {
|
||||
t.Errorf("docker_commands missing %q", want)
|
||||
}
|
||||
}
|
||||
|
||||
get := httptest.NewRequest(http.MethodGet, "/v1/speakers/"+id, nil)
|
||||
get.Header.Set("Authorization", "Bearer edkey")
|
||||
grec := httptest.NewRecorder()
|
||||
h.ServeHTTP(grec, get)
|
||||
if grec.Code != http.StatusOK {
|
||||
t.Fatalf("GET status %d body %s", grec.Code, grec.Body.String())
|
||||
}
|
||||
got := grec.Body.String()
|
||||
if strings.Contains(got, secret) || strings.Contains(got, token) || strings.Contains(got, "docker_commands") {
|
||||
t.Fatalf("GET must not leak install secrets: %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostSpeaker_masterSkipsInstall(t *testing.T) {
|
||||
srv, err := New(Options{InsecureDev: true, SeedDemo: true, BundleSeedHex: testBundleSeed})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer srv.Close()
|
||||
tenant, _, _, _, _ := srv.Store().DemoIDs()
|
||||
mustSetTestAPIKeys(t, srv, "edkey|"+tenant+"|editor")
|
||||
|
||||
body := `{"endpoint":"https://127.0.0.1:8080","role":"master"}`
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/speakers", strings.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer edkey")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
srv.Handler().ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var out map[string]any
|
||||
_ = json.Unmarshal(rec.Body.Bytes(), &out)
|
||||
if out["node_token"] != nil {
|
||||
t.Fatalf("master must not mint node_token: %#v", out["node_token"])
|
||||
}
|
||||
if out["install"] != nil {
|
||||
t.Fatalf("master must not include install: %#v", out["install"])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user