Add recon deploy action matrix and playbook wizard API.
Extend deploy-kit with pinned-build campaign attribution, SSRF erasure shards, and one-click action matrix; add playbook endpoint branching by target profile.
This commit is contained in:
@@ -59,15 +59,36 @@ func TestGetDeployKitWinRM(t *testing.T) {
|
||||
if out["join_lane"] != "winrm" {
|
||||
t.Fatalf("join_lane: %v", out["join_lane"])
|
||||
}
|
||||
dropper, ok := out["dropper_urls"].(map[string]interface{})
|
||||
if !ok || dropper["install_ps1"] == "" {
|
||||
t.Fatalf("dropper_urls: %v", out["dropper_urls"])
|
||||
if out["campaign"] != "recon-10.1.2.50" {
|
||||
t.Fatalf("campaign: %v", out["campaign"])
|
||||
}
|
||||
if out["spread_kit_zip"] == nil {
|
||||
t.Fatal("expected spread_kit_zip")
|
||||
if out["action_matrix"] == nil {
|
||||
t.Fatal("expected action_matrix")
|
||||
}
|
||||
if out["deploy_plan_template"] == nil {
|
||||
t.Fatal("expected deploy_plan_template")
|
||||
}
|
||||
|
||||
func TestGetDeployKitActionMatrix(t *testing.T) {
|
||||
spreadH, _ := testReconSpreadHandler(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/recon/deploy-kit?host=10.1.2.50&finding=WinRM&open_ports=22", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
spreadH.GetDeployKit(rec, req)
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal(rec.Body.Bytes(), &out)
|
||||
matrix, ok := out["action_matrix"].([]interface{})
|
||||
if !ok || len(matrix) == 0 {
|
||||
t.Fatalf("action_matrix: %v", out["action_matrix"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDeployKitSSRFErasureManifest(t *testing.T) {
|
||||
spreadH, _ := testReconSpreadHandler(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/recon/deploy-kit?host=app.lab&finding=ssrf", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
spreadH.GetDeployKit(rec, req)
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal(rec.Body.Bytes(), &out)
|
||||
if out["erasure_manifest"] == nil {
|
||||
t.Fatal("missing erasure_manifest")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,14 +98,7 @@ func TestGetDeployKitSSM(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
spreadH.GetDeployKit(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var out map[string]interface{}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if out["join_lane"] != "ssm_document" {
|
||||
t.Fatalf("join_lane: %v", out["join_lane"])
|
||||
t.Fatalf("status %d", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,13 +112,31 @@ func TestGetDeployKitRequiresHost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveReconFinding(t *testing.T) {
|
||||
matched, lane, ok := resolveReconFinding("gpsvc", NormalizeServiceDeployAllowlist(nil))
|
||||
if !ok || lane.Lane != "gpo" {
|
||||
t.Fatalf("gpsvc → gpo: matched=%q lane=%q ok=%v", matched, lane.Lane, ok)
|
||||
func TestGetReconPlaybook(t *testing.T) {
|
||||
spreadH, _ := testReconSpreadHandler(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/recon/playbook?host=127.0.0.1", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
spreadH.GetReconPlaybook(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
_, lane, ok = resolveReconFinding("", NormalizeServiceDeployAllowlist(nil))
|
||||
if !ok || lane.Lane != "bits_curl" {
|
||||
t.Fatalf("empty finding default: %v", lane.Lane)
|
||||
var out map[string]interface{}
|
||||
json.Unmarshal(rec.Body.Bytes(), &out)
|
||||
if out["profile"] == nil {
|
||||
t.Fatalf("profile missing: %v", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveReconFinding(t *testing.T) {
|
||||
_, lane, ok := resolveReconFinding("gpsvc", NormalizeServiceDeployAllowlist(nil))
|
||||
if !ok || lane.Lane != "gpo" {
|
||||
t.Fatalf("gpsvc lane=%q ok=%v", lane.Lane, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveReconFindingSSRF(t *testing.T) {
|
||||
_, lane, ok := resolveReconFinding("ssrf", nil)
|
||||
if !ok || lane.Lane != "stage_fetch" {
|
||||
t.Fatalf("lane=%q ok=%v", lane.Lane, ok)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user