a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
138 lines
4.1 KiB
Go
138 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// capturedFlow records the (repo, tool, args) a dataflow verb lowered to.
|
|
type capturedFlow struct {
|
|
repo string
|
|
tool string
|
|
args map[string]any
|
|
}
|
|
|
|
// runDataflow drives the real command tree for one dataflow verb (flow/taint),
|
|
// stubbing the shared daemon seam. Returns the captured call, the buffer, and
|
|
// any error.
|
|
func runDataflow(t *testing.T, verb string, argv ...string) (*capturedFlow, *bytes.Buffer, error) {
|
|
t.Helper()
|
|
resetFlowFlags()
|
|
|
|
orig := flowDaemonTool
|
|
t.Cleanup(func() { flowDaemonTool = orig })
|
|
|
|
var cap *capturedFlow
|
|
flowDaemonTool = func(repo, tool string, args map[string]any) (json.RawMessage, error) {
|
|
cap = &capturedFlow{repo: repo, tool: tool, args: args}
|
|
return json.RawMessage(`{"status":"ok"}`), nil
|
|
}
|
|
|
|
buf := &bytes.Buffer{}
|
|
rootCmd.SetOut(buf)
|
|
rootCmd.SetErr(buf)
|
|
rootCmd.SetIn(strings.NewReader(""))
|
|
rootCmd.SetArgs(append([]string{verb}, argv...))
|
|
err := rootCmd.Execute()
|
|
return cap, buf, err
|
|
}
|
|
|
|
func resetFlowFlags() {
|
|
resetCobraFlags(flowCmd)
|
|
resetCobraFlags(taintCmd)
|
|
|
|
flowIndex = "."
|
|
flowFrom, flowTo = "", ""
|
|
flowMaxDepth, flowMaxPaths = 0, 0
|
|
flowMinTier, flowFormat = "", "json"
|
|
|
|
taintIndex = "."
|
|
taintSource, taintSink = "", ""
|
|
taintMaxDepth, taintLimit = 0, 0
|
|
taintMinTier, taintFormat = "", "json"
|
|
}
|
|
|
|
// --- flow (flow_between) ----------------------------------------------------
|
|
|
|
func TestFlow_Lowers(t *testing.T) {
|
|
cap, _, err := runDataflow(t, "flow", "--from", "A", "--to", "B")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, cap)
|
|
require.Equal(t, "flow_between", cap.tool)
|
|
require.Equal(t, "A", cap.args["source_id"])
|
|
require.Equal(t, "B", cap.args["sink_id"])
|
|
require.Equal(t, "json", cap.args["format"])
|
|
}
|
|
|
|
func TestFlow_AllFlags(t *testing.T) {
|
|
cap, _, err := runDataflow(t, "flow",
|
|
"--from", "A", "--to", "B",
|
|
"--max-depth", "6", "--max-paths", "3", "--min-tier", "ast_resolved")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "flow_between", cap.tool)
|
|
require.Equal(t, 6, cap.args["max_depth"])
|
|
require.Equal(t, 3, cap.args["max_paths"])
|
|
require.Equal(t, "ast_resolved", cap.args["min_tier"])
|
|
}
|
|
|
|
func TestFlow_OnlyChangedFlagsSent(t *testing.T) {
|
|
cap, _, err := runDataflow(t, "flow", "--from", "A", "--to", "B")
|
|
require.NoError(t, err)
|
|
_, hasDepth := cap.args["max_depth"]
|
|
require.False(t, hasDepth, "unset --max-depth must not be forwarded")
|
|
_, hasTier := cap.args["min_tier"]
|
|
require.False(t, hasTier, "unset --min-tier must not be forwarded")
|
|
}
|
|
|
|
func TestFlow_MissingFromTo(t *testing.T) {
|
|
_, _, err := runDataflow(t, "flow", "--from", "A")
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "--from and --to are required")
|
|
}
|
|
|
|
// --- taint (taint_paths) ----------------------------------------------------
|
|
|
|
func TestTaint_Lowers(t *testing.T) {
|
|
cap, _, err := runDataflow(t, "taint", "--source", "s", "--sink", "k")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, cap)
|
|
require.Equal(t, "taint_paths", cap.tool)
|
|
require.Equal(t, "s", cap.args["source_pattern"])
|
|
require.Equal(t, "k", cap.args["sink_pattern"])
|
|
}
|
|
|
|
func TestTaint_AllFlags(t *testing.T) {
|
|
cap, _, err := runDataflow(t, "taint",
|
|
"--source", "s", "--sink", "k",
|
|
"--max-depth", "10", "--limit", "30", "--min-tier", "lsp_resolved")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "taint_paths", cap.tool)
|
|
require.Equal(t, 10, cap.args["max_depth"])
|
|
require.Equal(t, 30, cap.args["limit"])
|
|
require.Equal(t, "lsp_resolved", cap.args["min_tier"])
|
|
}
|
|
|
|
func TestTaint_MissingSourceSink(t *testing.T) {
|
|
_, _, err := runDataflow(t, "taint", "--source", "s")
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "--source and --sink are required")
|
|
}
|
|
|
|
// TestFlow_DaemonRequired asserts the real call path returns the daemon-required
|
|
// error when no daemon tracks the repo.
|
|
func TestFlow_DaemonRequired(t *testing.T) {
|
|
resetFlowFlags()
|
|
buf := &bytes.Buffer{}
|
|
rootCmd.SetOut(buf)
|
|
rootCmd.SetErr(buf)
|
|
rootCmd.SetIn(strings.NewReader(""))
|
|
rootCmd.SetArgs([]string{"flow", "--from", "A", "--to", "B", "--index", t.TempDir()})
|
|
err := rootCmd.Execute()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "gortex track")
|
|
}
|