mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-10 23:11:40 +08:00
🐛 fix(jvm): 加固诊断与变更安全边界
- 诊断 SSE 支持空心跳事件,避免无输出时解码失败 - Arthas Tunnel 增加会话过期清理、配置漂移校验和取消兜底 - Provider 合约清理 Base URL 查询参数和片段,避免探测泄露敏感信息 - JVM 变更请求强制校验原因并规范化写入审计字段
This commit is contained in:
@@ -82,6 +82,12 @@ func (a *App) JVMGetValue(cfg connection.ConnectionConfig, resourcePath string)
|
||||
}
|
||||
|
||||
func (a *App) JVMPreviewChange(cfg connection.ConnectionConfig, req jvm.ChangeRequest) connection.QueryResult {
|
||||
var err error
|
||||
req, err = jvm.NormalizeChangeRequest(req)
|
||||
if err != nil {
|
||||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||||
}
|
||||
|
||||
normalized, provider, err := resolveJVMProviderForMode(cfg, req.ProviderMode)
|
||||
if err != nil {
|
||||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||||
@@ -96,6 +102,12 @@ func (a *App) JVMPreviewChange(cfg connection.ConnectionConfig, req jvm.ChangeRe
|
||||
}
|
||||
|
||||
func (a *App) JVMApplyChange(cfg connection.ConnectionConfig, req jvm.ChangeRequest) connection.QueryResult {
|
||||
var err error
|
||||
req, err = jvm.NormalizeChangeRequest(req)
|
||||
if err != nil {
|
||||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||||
}
|
||||
|
||||
normalized, provider, err := resolveJVMProviderForMode(cfg, req.ProviderMode)
|
||||
if err != nil {
|
||||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||||
|
||||
@@ -25,6 +25,8 @@ type fakeJVMProvider struct {
|
||||
previewErr error
|
||||
apply jvm.ApplyResult
|
||||
applyErr error
|
||||
previewReq *jvm.ChangeRequest
|
||||
applyReq *jvm.ChangeRequest
|
||||
}
|
||||
|
||||
func (f fakeJVMProvider) Mode() string { return jvm.ModeJMX }
|
||||
@@ -40,13 +42,19 @@ func (f fakeJVMProvider) ListResources(context.Context, connection.ConnectionCon
|
||||
func (f fakeJVMProvider) GetValue(context.Context, connection.ConnectionConfig, string) (jvm.ValueSnapshot, error) {
|
||||
return f.value, f.valueErr
|
||||
}
|
||||
func (f fakeJVMProvider) PreviewChange(context.Context, connection.ConnectionConfig, jvm.ChangeRequest) (jvm.ChangePreview, error) {
|
||||
func (f fakeJVMProvider) PreviewChange(_ context.Context, _ connection.ConnectionConfig, req jvm.ChangeRequest) (jvm.ChangePreview, error) {
|
||||
if f.previewReq != nil {
|
||||
*f.previewReq = req
|
||||
}
|
||||
if !f.previewSet {
|
||||
return jvm.ChangePreview{Allowed: true, Summary: "preview", RiskLevel: "low"}, f.previewErr
|
||||
}
|
||||
return f.preview, f.previewErr
|
||||
}
|
||||
func (f fakeJVMProvider) ApplyChange(context.Context, connection.ConnectionConfig, jvm.ChangeRequest) (jvm.ApplyResult, error) {
|
||||
func (f fakeJVMProvider) ApplyChange(_ context.Context, _ connection.ConnectionConfig, req jvm.ChangeRequest) (jvm.ApplyResult, error) {
|
||||
if f.applyReq != nil {
|
||||
*f.applyReq = req
|
||||
}
|
||||
return f.apply, f.applyErr
|
||||
}
|
||||
|
||||
@@ -578,6 +586,75 @@ func TestJVMApplyChangePersistsAuditSource(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestJVMApplyChangeNormalizesRequestBeforeProviderAndAudit(t *testing.T) {
|
||||
app := NewAppWithSecretStore(nil)
|
||||
app.configDir = t.TempDir()
|
||||
readOnly := false
|
||||
var previewReq jvm.ChangeRequest
|
||||
var applyReq jvm.ChangeRequest
|
||||
restore := swapJVMProviderFactory(func(mode string) (jvm.Provider, error) {
|
||||
return fakeJVMProvider{
|
||||
value: jvm.ValueSnapshot{
|
||||
ResourceID: "/cache/orders",
|
||||
Kind: "entry",
|
||||
Format: "json",
|
||||
},
|
||||
previewReq: &previewReq,
|
||||
applyReq: &applyReq,
|
||||
apply: jvm.ApplyResult{
|
||||
Status: "applied",
|
||||
UpdatedValue: jvm.ValueSnapshot{
|
||||
ResourceID: "/cache/orders",
|
||||
Kind: "entry",
|
||||
Format: "json",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
defer restore()
|
||||
|
||||
res := app.JVMApplyChange(connection.ConnectionConfig{
|
||||
Type: "jvm",
|
||||
ID: "conn-orders",
|
||||
Host: "orders.internal",
|
||||
JVM: connection.JVMConfig{
|
||||
ReadOnly: &readOnly,
|
||||
PreferredMode: "endpoint",
|
||||
AllowedModes: []string{"endpoint"},
|
||||
},
|
||||
}, jvm.ChangeRequest{
|
||||
ProviderMode: " endpoint ",
|
||||
ResourceID: " /cache/orders ",
|
||||
Action: " put ",
|
||||
Reason: " repair cache ",
|
||||
Source: " manual ",
|
||||
Payload: map[string]any{
|
||||
"status": "ready",
|
||||
},
|
||||
})
|
||||
if !res.Success {
|
||||
t.Fatalf("expected success, got %+v", res)
|
||||
}
|
||||
if previewReq.ProviderMode != "endpoint" || previewReq.ResourceID != "/cache/orders" || previewReq.Action != "put" || previewReq.Reason != "repair cache" {
|
||||
t.Fatalf("expected normalized preview request, got %#v", previewReq)
|
||||
}
|
||||
if applyReq.ProviderMode != "endpoint" || applyReq.ResourceID != "/cache/orders" || applyReq.Action != "put" || applyReq.Reason != "repair cache" || applyReq.Source != "manual" {
|
||||
t.Fatalf("expected normalized apply request, got %#v", applyReq)
|
||||
}
|
||||
|
||||
listRes := app.JVMListAuditRecords("conn-orders", 10)
|
||||
if !listRes.Success {
|
||||
t.Fatalf("expected audit list success, got %+v", listRes)
|
||||
}
|
||||
records, ok := listRes.Data.([]jvm.AuditRecord)
|
||||
if !ok || len(records) != 1 {
|
||||
t.Fatalf("expected one audit record, got %#v", listRes.Data)
|
||||
}
|
||||
if records[0].ProviderMode != "endpoint" || records[0].ResourceID != "/cache/orders" || records[0].Action != "put" || records[0].Reason != "repair cache" || records[0].Source != "manual" {
|
||||
t.Fatalf("expected normalized audit record, got %#v", records[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestJVMPreviewChangeRejectsModeOutsideAllowedModes(t *testing.T) {
|
||||
app := NewAppWithSecretStore(nil)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user