diff --git a/cmd/file.go b/cmd/file.go index 2900575e..c1d467ec 100644 --- a/cmd/file.go +++ b/cmd/file.go @@ -185,8 +185,8 @@ func updateSpinner(options model.Options, sf bool, current, total int) { } func printFileErrorAndUsage() { -printing.DalLog("ERROR", "Please provide a valid target file (targets.txt or rawdata.raw)", options) -printing.DalLog("ERROR", "Example: dalfox file ./targets.txt or ./rawdata.raw", options) + printing.DalLog("ERROR", "Please provide a valid target file (targets.txt or rawdata.raw)", options) + printing.DalLog("ERROR", "Example: dalfox file ./targets.txt or ./rawdata.raw", options) } func init() { diff --git a/cmd/root.go b/cmd/root.go index cd543ee4..274baf15 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -151,62 +151,62 @@ func initConfig() { // Initialize options struct with CLI arguments (overriding configuration file values) options = model.Options{ - Header: args.Header, - Cookie: args.Cookie, + Header: args.Header, + Cookie: args.Cookie, UniqParam: args.P, BlindURL: args.Blind, CustomPayloadFile: args.CustomPayload, CustomBlindXSSPayloadFile: args.CustomBlindXSSPayloadFile, CustomAlertValue: args.CustomAlertValue, CustomAlertType: args.CustomAlertType, - Data: args.Data, - UserAgent: args.UserAgent, - OutputFile: args.Output, - Format: args.Format, - FoundAction: args.FoundAction, - FoundActionShell: args.FoundActionShell, - ProxyAddress: args.Proxy, - Grep: args.Grep, - IgnoreReturn: args.IgnoreReturn, - IgnoreParams: args.IgnoreParams, - Timeout: args.Timeout, - Concurrence: args.Concurrence, - MaxCPU: args.MaxCPU, - Delay: args.Delay, - OnlyDiscovery: args.OnlyDiscovery, - OnlyCustomPayload: args.OnlyCustomPayload, - Silence: args.Silence, - FollowRedirect: args.FollowRedirect, - Scan: make(map[string]model.Scan), - Mining: args.Mining, - MiningWordlist: args.MiningWord, - FindingDOM: args.FindingDOM, - NoColor: args.NoColor, - Method: args.Method, - NoSpinner: args.NoSpinner, - NoBAV: args.SkipBAV, - NoGrep: args.SkipGrep, - Debug: args.Debug, - CookieFromRaw: args.CookieFromRaw, - AuroraObject: au, - StartTime: stime, - MulticastMode: false, - RemotePayloads: args.RemotePayloads, - RemoteWordlists: args.RemoteWordlists, - UseHeadless: !args.SkipHeadless, - UseDeepDXSS: args.UseDeepDXSS, - OnlyPoC: args.OnlyPoC, - OutputAll: args.OutputAll, - WAF: false, - WAFEvasion: args.WAFEvasion, - PoCType: args.PoCType, - ReportBool: args.ReportBool, - ReportFormat: args.ReportFormat, - OutputRequest: args.OutputRequest, - OutputResponse: args.OutputResponse, - UseBAV: args.UseBAV, - SkipDiscovery: args.SkipDiscovery, - HarFilePath: args.HarFilePath, + Data: args.Data, + UserAgent: args.UserAgent, + OutputFile: args.Output, + Format: args.Format, + FoundAction: args.FoundAction, + FoundActionShell: args.FoundActionShell, + ProxyAddress: args.Proxy, + Grep: args.Grep, + IgnoreReturn: args.IgnoreReturn, + IgnoreParams: args.IgnoreParams, + Timeout: args.Timeout, + Concurrence: args.Concurrence, + MaxCPU: args.MaxCPU, + Delay: args.Delay, + OnlyDiscovery: args.OnlyDiscovery, + OnlyCustomPayload: args.OnlyCustomPayload, + Silence: args.Silence, + FollowRedirect: args.FollowRedirect, + Scan: make(map[string]model.Scan), + Mining: args.Mining, + MiningWordlist: args.MiningWord, + FindingDOM: args.FindingDOM, + NoColor: args.NoColor, + Method: args.Method, + NoSpinner: args.NoSpinner, + NoBAV: args.SkipBAV, + NoGrep: args.SkipGrep, + Debug: args.Debug, + CookieFromRaw: args.CookieFromRaw, + AuroraObject: au, + StartTime: stime, + MulticastMode: false, + RemotePayloads: args.RemotePayloads, + RemoteWordlists: args.RemoteWordlists, + UseHeadless: !args.SkipHeadless, + UseDeepDXSS: args.UseDeepDXSS, + OnlyPoC: args.OnlyPoC, + OutputAll: args.OutputAll, + WAF: false, + WAFEvasion: args.WAFEvasion, + PoCType: args.PoCType, + ReportBool: args.ReportBool, + ReportFormat: args.ReportFormat, + OutputRequest: args.OutputRequest, + OutputResponse: args.OutputResponse, + UseBAV: args.UseBAV, + SkipDiscovery: args.SkipDiscovery, + HarFilePath: args.HarFilePath, } // If configuration file was loaded, apply values from it for options not specified via CLI diff --git a/go.mod b/go.mod index bf4a85a1..c8448ea8 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/hahwul/volt v1.0.7 github.com/labstack/echo/v4 v4.13.4 github.com/logrusorgru/aurora v2.0.3+incompatible - github.com/mark3labs/mcp-go v0.28.0 - github.com/olekukonko/tablewriter v0.0.5 + github.com/mark3labs/mcp-go v0.32.0 + github.com/olekukonko/tablewriter v1.0.7 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 @@ -20,7 +20,7 @@ require ( github.com/swaggo/swag v1.16.4 github.com/tidwall/sjson v1.2.5 github.com/tylerb/graceful v1.2.15 - golang.org/x/sync v0.14.0 + golang.org/x/sync v0.15.0 golang.org/x/term v0.32.0 ) @@ -32,7 +32,7 @@ require ( github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect github.com/chromedp/sysutil v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect @@ -49,8 +49,11 @@ require ( github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/olekukonko/errors v1.1.0 // indirect + github.com/olekukonko/ll v0.0.9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/swaggo/files/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index bdc32e5a..8eac5101 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -81,6 +83,8 @@ github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4 github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mark3labs/mcp-go v0.28.0 h1:7yl4y5D1KYU2f/9Uxp7xfLIggfunHoESCRbrjcytcLM= github.com/mark3labs/mcp-go v0.28.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= +github.com/mark3labs/mcp-go v0.32.0 h1:fgwmbfL2gbd67obg57OfV2Dnrhs1HtSdlY/i5fn7MU8= +github.com/mark3labs/mcp-go v0.32.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -90,14 +94,25 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= +github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= +github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw= +github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -173,6 +188,8 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/report/report.go b/internal/report/report.go index 77cced9e..d11f0ed5 100644 --- a/internal/report/report.go +++ b/internal/report/report.go @@ -21,15 +21,14 @@ func GenerateReport(scanResult model.Result, options model.Options) { } func renderTable(params []model.ParamResult, options model.Options) { - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{ + table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeader([]string{ "Param", "Type", "Reflected", "R-Point", "R-Code", "Chars", - }) + })) for _, v := range params { chars := strings.Join(v.Chars, " ") @@ -53,8 +52,7 @@ func renderTable(params []model.ParamResult, options model.Options) { } func renderPoCTable(pocs []model.PoC, options model.Options) { - pocTable := tablewriter.NewWriter(os.Stdout) - pocTable.SetHeader([]string{ + pocTable := tablewriter.NewTable(os.Stdout, tablewriter.WithHeader([]string{ "#", "Type", "Severity", @@ -62,7 +60,7 @@ func renderPoCTable(pocs []model.PoC, options model.Options) { "Param", "Inject-Type", "CWE", - }) + })) for i, v := range pocs { line := []string{ diff --git a/pkg/scanning/bav.go b/pkg/scanning/bav.go index 1a5b1e4b..685d5993 100644 --- a/pkg/scanning/bav.go +++ b/pkg/scanning/bav.go @@ -39,7 +39,7 @@ func RunBAVAnalysis(target string, options model.Options, rl *rateLimiter, bav * bavWaitGroup.Wait() *bav = " > BAV(o)" -printing.DalLog("SYSTEM", "["+*bav+"] BAV analysis completed", options) + printing.DalLog("SYSTEM", "["+*bav+"] BAV analysis completed", options) } // SSTIAnalysis is basic check for SSTI diff --git a/pkg/scanning/parameterAnalysis.go b/pkg/scanning/parameterAnalysis.go index 38c0af86..6966a533 100644 --- a/pkg/scanning/parameterAnalysis.go +++ b/pkg/scanning/parameterAnalysis.go @@ -259,7 +259,7 @@ func ParameterAnalysis(target string, options model.Options, rl *rateLimiter) ma } var wgg sync.WaitGroup -const maxConcurrency = 1000 // Define a reasonable maximum limit to prevent excessive memory allocation + const maxConcurrency = 1000 // Define a reasonable maximum limit to prevent excessive memory allocation concurrency := options.Concurrence if concurrency > maxConcurrency { concurrency = maxConcurrency diff --git a/pkg/server/mcp.go b/pkg/server/mcp.go index c2379d2e..e40c5874 100644 --- a/pkg/server/mcp.go +++ b/pkg/server/mcp.go @@ -96,7 +96,10 @@ func RunMCPServer(options model.Options) { // Handler for the scan tool s.AddTool(scanTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - url := request.Params.Arguments["url"].(string) + // Type assert Arguments to map[string]any + args := request.Params.Arguments.(map[string]any) + + url := args["url"].(string) if url == "" { return nil, fmt.Errorf("URL is required") } @@ -121,13 +124,13 @@ func RunMCPServer(options model.Options) { } for _, opt := range stringOptions { - if value, ok := request.Params.Arguments[opt.paramName].(string); ok && value != "" { + if value, ok := args[opt.paramName].(string); ok && value != "" { opt.setter(value) } } // Handle special case for headers which requires splitting - if headers, ok := request.Params.Arguments["headers"].(string); ok && headers != "" { + if headers, ok := args["headers"].(string); ok && headers != "" { rqOptions.Header = strings.Split(headers, "|") } @@ -141,7 +144,7 @@ func RunMCPServer(options model.Options) { } for _, opt := range numericOptions { - if value, ok := request.Params.Arguments[opt.paramName].(float64); ok { + if value, ok := args[opt.paramName].(float64); ok { opt.setter(int(value)) } } @@ -159,22 +162,22 @@ func RunMCPServer(options model.Options) { } for _, opt := range boolOptions { - if value, ok := request.Params.Arguments[opt.paramName].(bool); ok { + if value, ok := args[opt.paramName].(bool); ok { opt.setter(value) } } // Handle special cases for mining options - if skipMiningAll, ok := request.Params.Arguments["skip-mining-all"].(bool); ok && skipMiningAll { + if skipMiningAll, ok := args["skip-mining-all"].(bool); ok && skipMiningAll { rqOptions.Mining = false rqOptions.FindingDOM = false } - if skipMiningDict, ok := request.Params.Arguments["skip-mining-dict"].(bool); ok && skipMiningDict { + if skipMiningDict, ok := args["skip-mining-dict"].(bool); ok && skipMiningDict { rqOptions.Mining = false } - if skipMiningDOM, ok := request.Params.Arguments["skip-mining-dom"].(bool); ok && skipMiningDOM { + if skipMiningDOM, ok := args["skip-mining-dom"].(bool); ok && skipMiningDOM { rqOptions.FindingDOM = false } @@ -218,7 +221,10 @@ func RunMCPServer(options model.Options) { // Handler for the results tool s.AddTool(resultsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - scanID := request.Params.Arguments["scan_id"].(string) + // Type assert Arguments to map[string]any + args := request.Params.Arguments.(map[string]any) + + scanID := args["scan_id"].(string) if scanID == "" { return nil, fmt.Errorf("scan_id is required") } diff --git a/pkg/server/server.go b/pkg/server/server.go index 6ab215b4..9d2fe999 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -33,7 +33,7 @@ func RunAPIServer(options model.Options) { if options.Scan == nil { options.Scan = make(map[string]model.Scan) } - e := setupEchoServer(&options, &scans) // Pass address of options + e := setupEchoServer(&options, &scans) // Pass address of options printing.DalLog("SYSTEM", "Listen "+e.Server.Addr, options) // Pass options by value graceful.ListenAndServe(e.Server, 5*time.Second) } @@ -93,8 +93,8 @@ func scansHandler(c echo.Context, scans *[]string) error { func scanHandler(c echo.Context, scans *[]string, options *model.Options) error { // options is now *model.Options sid := c.Param("sid") // Check if sid exists in options.Scan (source of truth) or in the scans slice for active scanning processes - scanData, inOptionsScan := options.Scan[sid] // This will now use the pointer's Scan field - scanResult := GetScan(sid, *options) // Dereference options for GetScan + scanData, inOptionsScan := options.Scan[sid] // This will now use the pointer's Scan field + scanResult := GetScan(sid, *options) // Dereference options for GetScan if !inOptionsScan && !contains(*scans, sid) { // If not in options.Scan and not in scans slice return c.JSON(http.StatusNotFound, Res{Code: 404, Msg: "Scan ID not found"}) diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index 5f6d37d2..46869f61 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -45,7 +45,6 @@ func TestScanHandler(t *testing.T) { c.SetParamNames("sid") c.SetParamValues("test-scan-notfound") - scans := []string{} // SID not in scans options := model.Options{ Scan: make(map[string]model.Scan), // SID not in options.Scan @@ -96,14 +95,13 @@ func TestScanHandler(t *testing.T) { c.SetParamValues(sid) dummyResults := []model.PoC{{Type: "test-poc", InjectType: "G", PoCType: "R", Method: "GET", Data: "dummy", Param: "p", Payload: "alert(1)", Evidence: "alert(1)", CWE: "CWE-79", Severity: "High"}} - + scans := []string{sid} // It might or might not be in scans slice if finished, but must be in options.Scan options := model.Options{ Scan: make(map[string]model.Scan), } options.Scan[sid] = model.Scan{URL: "http://test.com/vuln", ScanID: sid, Results: dummyResults} - if assert.NoError(t, scanHandler(c, &scans, &options)) { assert.Equal(t, http.StatusOK, rec.Code) // Note: The model.PoC struct has json tags like "inject_type", "poc_type". @@ -321,7 +319,7 @@ func TestDeleteScanHandler(t *testing.T) { options := model.Options{Scan: make(map[string]model.Scan)} scanIDInMapOnly := "id_only_in_map" options.Scan[scanIDInMapOnly] = model.Scan{URL: "http://test.com", ScanID: scanIDInMapOnly} - + otherID := "other_id" scans := []string{otherID} // scanIDInMapOnly is NOT in this slice @@ -342,7 +340,7 @@ func TestDeleteScanHandler(t *testing.T) { // Assert that "id_only_in_map" is no longer in options.Scan _, existsInMap := options.Scan[scanIDInMapOnly] assert.False(t, existsInMap) - + // Assert that the scans slice remains []string{"other_id"} assert.Equal(t, []string{otherID}, scans) assert.Len(t, options.Scan, 0) // Since only scanIDInMapOnly was in options.Scan