72 lines
3.5 KiB
Go
72 lines
3.5 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.pcux.cn/xuans/Scert/backend/internal/certificate"
|
|
"git.pcux.cn/xuans/Scert/backend/internal/deployment"
|
|
"git.pcux.cn/xuans/Scert/backend/internal/domain"
|
|
"git.pcux.cn/xuans/Scert/backend/internal/repository"
|
|
)
|
|
|
|
func TestAsyncTaskReportRestoresVerificationAndRecovery(t *testing.T) {
|
|
server, tasks, _, cleanup := newTaskAPITestServer(t, func(context.Context, string) (certificate.IssueResult, deployment.Report, error) {
|
|
return certificate.IssueResult{}, deployment.Report{
|
|
Total: 1, Failed: 1, Status: "failed", VerificationStatus: "failed", RecoveryStatus: "success",
|
|
Results: []deployment.Result{{ServerID: "private-report-target", Status: "failed", FailureCode: deployment.FailureRecoveryRestored, Message: "secret-remote-output"}},
|
|
}, errors.New("站点校验失败,已恢复")
|
|
})
|
|
defer cleanup()
|
|
response := httptest.NewRecorder()
|
|
serveAdminHTTP(server, response, httptest.NewRequest(http.MethodPost, "/api/v1/domains/domain-1/issue", nil))
|
|
task := submittedTask(t, response)
|
|
waitTaskWorkersForTest(t, server)
|
|
path := "/api/v1/tasks/" + task.ID + "/deployment-results"
|
|
response = httptest.NewRecorder()
|
|
serveAdminHTTP(server, response, httptest.NewRequest(http.MethodGet, path, nil))
|
|
var body struct {
|
|
Items []repository.TaskDeploymentResult `json:"items"`
|
|
Reports []repository.TaskDeploymentReport `json:"reports"`
|
|
}
|
|
if response.Code != http.StatusOK || json.Unmarshal(response.Body.Bytes(), &body) != nil || len(body.Items) != 1 || len(body.Reports) != 1 {
|
|
t.Fatalf("任务完整报告接口响应错误:%d %s", response.Code, response.Body.String())
|
|
}
|
|
report := body.Reports[0]
|
|
if report.TaskID != task.ID || report.AttemptNumber != 1 || report.Report.VerificationStatus != "failed" || report.Report.RecoveryStatus != "success" || report.Report.Results[0].FailureCode != deployment.FailureRecoveryRestored {
|
|
t.Fatalf("接口遗漏验证和恢复报告:%+v", report)
|
|
}
|
|
if strings.Contains(response.Body.String(), "secret-remote-output") {
|
|
t.Fatal("接口泄露原始远端输出")
|
|
}
|
|
outsider := httpUserSessionCookie(server, "outsider", repository.UserRoleUser)
|
|
response = serveUserRequest(server, outsider, http.MethodGet, path, "")
|
|
if response.Code != http.StatusForbidden || strings.Contains(response.Body.String(), "private-report-target") {
|
|
t.Fatal("完整报告未遵守项目权限")
|
|
}
|
|
member := httpUserSessionCookie(server, "report-reader", repository.UserRoleUser)
|
|
if err := server.projectMembers.GrantProjectRole(t.Context(), "test-admin", domain.DefaultProjectID, "report-reader", domain.ProjectRoleReadOnly); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
response = serveUserRequest(server, member, http.MethodGet, path, "")
|
|
if response.Code != http.StatusOK || !strings.Contains(response.Body.String(), "private-report-target") {
|
|
t.Fatal("只读成员无法读取完整报告")
|
|
}
|
|
if err := server.projectMembers.RevokeProjectRole(t.Context(), "test-admin", domain.DefaultProjectID, "report-reader", domain.ProjectRoleReadOnly); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
response = serveUserRequest(server, member, http.MethodGet, path, "")
|
|
if response.Code != http.StatusForbidden || strings.Contains(response.Body.String(), "private-report-target") {
|
|
t.Fatal("撤权后仍泄露完整报告")
|
|
}
|
|
visible, err := tasks.ListVisibleTaskDeploymentReports(t.Context(), "report-reader", task.ID)
|
|
if err != nil || len(visible) != 0 {
|
|
t.Fatalf("报告仓储未实时检查权限:%+v %v", visible, err)
|
|
}
|
|
}
|