diff --git a/.golangci.yml b/.golangci.yml index db566d98..a86d2281 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -145,6 +145,28 @@ linters: - name: error-naming - name: if-return + exclusions: + # Path-scoped exclusions consolidate repeated per-site nolint + # waivers into one place so reviewers grep the config, not 20 + # scattered comments. Issue #499 lane A: gosec G304 (potential file + # inclusion via variable) is the canonical noise in test files — + # every detector test reads "testdata/.schema.json" through + # filepath.Join, which is by definition a variable path. The path + # is checked into the repo, the working dir is set by `go test`, + # and the file is not operator-controlled at runtime. Waiving G304 + # on `_test.go` collapses ~22 inline waivers across + # module/pkg/patterns/** and the integration / SDK test trees with + # no loss of coverage on production code (gosec still runs G304 on + # non-test files; see module/pkg/replay/runner.go and + # module/receiver/ncclfrreceiver/nccl_fr.go which keep their inline + # rationale comments because they read paths derived from operator + # config). + rules: + - linters: + - gosec + path: _test\.go + text: "G304" + issues: max-issues-per-linter: 0 max-same-issues: 0 diff --git a/module/pkg/nccl/fr_parser/fixtures_test.go b/module/pkg/nccl/fr_parser/fixtures_test.go index 2cda60ca..c7ee4d44 100644 --- a/module/pkg/nccl/fr_parser/fixtures_test.go +++ b/module/pkg/nccl/fr_parser/fixtures_test.go @@ -81,7 +81,7 @@ func TestFixtures_MatchGoldens(t *testing.T) { if err != nil { t.Fatalf("Bytes: %v", err) } - gotBytes, err := os.ReadFile(pklPath) //nolint:gosec // testdata path is package-controlled + gotBytes, err := os.ReadFile(pklPath) if err != nil { t.Fatalf("read %s: %v (run `make generate-fixtures`)", pklPath, err) } @@ -89,7 +89,7 @@ func TestFixtures_MatchGoldens(t *testing.T) { t.Fatalf("%s out of date: run `make generate-fixtures`", pklPath) } - gotJSON, err := os.ReadFile(jsonPath) //nolint:gosec // testdata path is package-controlled + gotJSON, err := os.ReadFile(jsonPath) if err != nil { t.Fatalf("read %s: %v (run `make generate-fixtures`)", jsonPath, err) } diff --git a/module/pkg/patterns/checkpointer_hang_test.go b/module/pkg/patterns/checkpointer_hang_test.go index d39e4268..2b10ec04 100644 --- a/module/pkg/patterns/checkpointer_hang_test.go +++ b/module/pkg/patterns/checkpointer_hang_test.go @@ -4,15 +4,14 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // checkpointer_hang detector test suite (NORTHSTAR pattern #11). @@ -582,16 +581,7 @@ func TestCheckpointerHangDetector_AsymmetricWindowTightensBackwardLeg(t *testing func TestCheckpointerHangVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "checkpointer_hang_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "checkpointer_hang_verdict.schema.json")) t0 := time.Unix(1_700_000_000, 0).UTC() stalls := []patterns.TrainingStepStallRecord{ @@ -636,16 +626,7 @@ func TestCheckpointerHangVerdict_SchemaConformance(t *testing.T) { func TestCheckpointerHangVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "checkpointer_hang_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "checkpointer_hang_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "checkpoint_phase", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/cuda_oom_test.go b/module/pkg/patterns/cuda_oom_test.go index 3e9b56d4..15703b27 100644 --- a/module/pkg/patterns/cuda_oom_test.go +++ b/module/pkg/patterns/cuda_oom_test.go @@ -4,15 +4,14 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // cuda_oom detector test suite (NORTHSTAR pattern #10). The detector @@ -466,16 +465,7 @@ func TestCUDAOOMDetector_ThresholdConfigurable(t *testing.T) { func TestCUDAOOMVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "cuda_oom_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "cuda_oom_verdict.schema.json")) fbAt := time.Unix(1_700_000_000, 0).UTC() oomAt := fbAt.Add(30 * time.Second) @@ -506,16 +496,7 @@ func TestCUDAOOMVerdict_SchemaConformance(t *testing.T) { func TestCUDAOOMVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "cuda_oom_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "cuda_oom_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "hw_fb", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/dataloader_hang_test.go b/module/pkg/patterns/dataloader_hang_test.go index 6097f0bf..6a62086b 100644 --- a/module/pkg/patterns/dataloader_hang_test.go +++ b/module/pkg/patterns/dataloader_hang_test.go @@ -4,15 +4,14 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // TestDataLoaderHangDetector_WorkerKilledDiscriminatorFires pins the @@ -434,16 +433,7 @@ func TestDataLoaderHangDetector_ThresholdConfigurable(t *testing.T) { func TestDataLoaderHangVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "dataloader_hang_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "dataloader_hang_verdict.schema.json")) now := mustParseDLTime(t, "2026-06-01T10:00:00Z") stalls := []patterns.TrainingStepStallRecord{ @@ -483,16 +473,7 @@ func TestDataLoaderHangVerdict_SchemaConformance(t *testing.T) { func TestDataLoaderHangVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "dataloader_hang_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "dataloader_hang_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "training_step_stall", "uid": "u1", "timestamp": "2026-06-01T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/hbm_ecc_test.go b/module/pkg/patterns/hbm_ecc_test.go index f36d3b4b..3a570d13 100644 --- a/module/pkg/patterns/hbm_ecc_test.go +++ b/module/pkg/patterns/hbm_ecc_test.go @@ -4,16 +4,15 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "regexp" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // hbm_ecc detector test suite. The detector reads DCGM-derived HBM @@ -342,16 +341,7 @@ func TestHBMECCDetector_MostRecentECCWins(t *testing.T) { func TestHBMECCVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "hbm_ecc_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "hbm_ecc_verdict.schema.json")) eccAt := time.Unix(1_700_000_000, 0).UTC() eccs := []patterns.HBMECCRecord{ @@ -379,16 +369,7 @@ func TestHBMECCVerdict_SchemaConformance(t *testing.T) { func TestHBMECCVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "hbm_ecc_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "hbm_ecc_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "hw_error", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/nccl_bootstrap_test.go b/module/pkg/patterns/nccl_bootstrap_test.go index e5258a50..4813e1df 100644 --- a/module/pkg/patterns/nccl_bootstrap_test.go +++ b/module/pkg/patterns/nccl_bootstrap_test.go @@ -4,15 +4,14 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // nccl_bootstrap detector test suite (NORTHSTAR pattern #9). The @@ -402,16 +401,7 @@ func TestNCCLBootstrapDetector_MaxPodReadyAnchorsEvidence(t *testing.T) { func TestNCCLBootstrapVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "nccl_bootstrap_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "nccl_bootstrap_verdict.schema.json")) now := mustParseTime(t, "2026-06-01T10:00:00Z") readyAt := now.Add(-10 * time.Minute) @@ -439,16 +429,7 @@ func TestNCCLBootstrapVerdict_SchemaConformance(t *testing.T) { func TestNCCLBootstrapVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "nccl_bootstrap_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "nccl_bootstrap_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "training_pod", "uid": "u1", "timestamp": "2026-06-01T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/nccl_hang_test.go b/module/pkg/patterns/nccl_hang_test.go index 1ba6a58e..6740c744 100644 --- a/module/pkg/patterns/nccl_hang_test.go +++ b/module/pkg/patterns/nccl_hang_test.go @@ -4,16 +4,15 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "regexp" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // nccl_hang detector test suite. The detector reads cross-rank NCCL @@ -215,16 +214,7 @@ func TestNCCLHangDetector_LaterCompletedRecordSupersedes(t *testing.T) { func TestNCCLHangVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "nccl_hang_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "nccl_hang_verdict.schema.json")) now := time.Unix(1_700_000_600, 0).UTC() stuckNs := now.Add(-10 * time.Minute).UnixNano() @@ -249,16 +239,7 @@ func TestNCCLHangVerdict_SchemaConformance(t *testing.T) { func TestNCCLHangVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "nccl_hang_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "nccl_hang_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "nccl_fr", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/pcie_aer_test.go b/module/pkg/patterns/pcie_aer_test.go index 2a277e46..f39f262e 100644 --- a/module/pkg/patterns/pcie_aer_test.go +++ b/module/pkg/patterns/pcie_aer_test.go @@ -4,16 +4,15 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "regexp" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // pcie_aer detector test suite. The detector reads PCIe AER kernel @@ -378,16 +377,7 @@ func TestPCIeAERDetector_NoBaselineSkipped(t *testing.T) { func TestPCIeAERVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "pcie_aer_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "pcie_aer_verdict.schema.json")) aerAt := time.Unix(1_700_000_000, 0).UTC() collapseAt := aerAt.Add(30 * time.Second) @@ -421,16 +411,7 @@ func TestPCIeAERVerdict_SchemaConformance(t *testing.T) { func TestPCIeAERVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "pcie_aer_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "pcie_aer_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "pcie_aer", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/silent_data_corruption_test.go b/module/pkg/patterns/silent_data_corruption_test.go index 3f7e92cf..35b3b3bd 100644 --- a/module/pkg/patterns/silent_data_corruption_test.go +++ b/module/pkg/patterns/silent_data_corruption_test.go @@ -4,15 +4,14 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // silent_data_corruption detector test suite (pattern #13). The @@ -557,16 +556,7 @@ func TestSDCDetector_JobEndFallbackToTimestamp(t *testing.T) { func TestSDCVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "silent_data_corruption_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "silent_data_corruption_verdict.schema.json")) jobStart := time.Unix(1_700_000_000, 0).UTC() jobEnd := jobStart.Add(time.Hour) @@ -620,16 +610,7 @@ func TestSDCVerdict_SchemaConformance(t *testing.T) { func TestSDCVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "silent_data_corruption_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "silent_data_corruption_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "hw_gpu_sdc", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/thermal_throttle_test.go b/module/pkg/patterns/thermal_throttle_test.go index 725a70cd..0a35f63d 100644 --- a/module/pkg/patterns/thermal_throttle_test.go +++ b/module/pkg/patterns/thermal_throttle_test.go @@ -4,16 +4,15 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "regexp" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // thermal_throttle detector test suite. The detector reads DCGM- @@ -353,16 +352,7 @@ func TestThermalThrottleDetector_DuplicateGPUDeltasSumWithinWindow(t *testing.T) func TestThermalThrottleVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "thermal_throttle_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "thermal_throttle_verdict.schema.json")) t0 := time.Unix(1_700_000_000, 0).UTC() recs := []patterns.ThermalThrottleRecord{ @@ -396,16 +386,7 @@ func TestThermalThrottleVerdict_SchemaConformance(t *testing.T) { func TestThermalThrottleVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "thermal_throttle_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "thermal_throttle_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "hw_throttle", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/patterns/verdict_envelope_schema_test.go b/module/pkg/patterns/verdict_envelope_schema_test.go index 34b706c9..acc620e0 100644 --- a/module/pkg/patterns/verdict_envelope_schema_test.go +++ b/module/pkg/patterns/verdict_envelope_schema_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // envelopeSchemaPath is the repo-mirrored v1.0-rc1 Verdict envelope @@ -28,20 +29,18 @@ var envelopeSchemaPath = filepath.Join("..", "..", "..", "docs", "schemas", "ver // to defend against. func loadEnvelopeSchema(t *testing.T) *jsonschema.Schema { t.Helper() - bs, err := os.ReadFile(envelopeSchemaPath) //nolint:gosec // test-local relative path - require.NoError(t, err, - "docs/schemas/verdict-1.0.0-rc1.json must exist; this artifact is "+ - "cut-criterion-2 for v1.0-rc1 and is read by external verdict-"+ - "consumption SDKs (criterion 12). Run `git status docs/schemas/` "+ - "and verify the file landed.") - - compiler := jsonschema.NewCompiler() - var doc any - require.NoError(t, json.Unmarshal(bs, &doc)) - require.NoError(t, compiler.AddResource(envelopeSchemaPath, doc)) - schema, err := compiler.Compile(envelopeSchemaPath) - require.NoError(t, err) - return schema + // Pre-check the artifact is present with a domain-specific message + // — the cut-criterion-2 wording is load-bearing for reviewers + // debugging a missing schema. We still delegate compilation to the + // shared helper so the load-parse-compile path stays uniform. + if _, err := os.Stat(envelopeSchemaPath); err != nil { + require.NoError(t, err, + "docs/schemas/verdict-1.0.0-rc1.json must exist; this artifact is "+ + "cut-criterion-2 for v1.0-rc1 and is read by external verdict-"+ + "consumption SDKs (criterion 12). Run `git status docs/schemas/` "+ + "and verify the file landed.") + } + return jsonschematest.Compile(t, envelopeSchemaPath) } // validatesEnvelope marshals v, decodes back to a generic any, and @@ -186,7 +185,7 @@ func TestVerdictEnvelopeV1RC1_CanonicalShippedFixturesValidate(t *testing.T) { t.Parallel() schema := loadEnvelopeSchema(t) - bs, err := os.ReadFile(canonicalShippedFixturesPath) //nolint:gosec // test-local relative path + bs, err := os.ReadFile(canonicalShippedFixturesPath) require.NoError(t, err, "docs/schemas/fixtures/shipped-patterns-v1.0.0-rc1.json must exist; "+ "it is the cross-SDK fixture contract from issue #368.") @@ -340,7 +339,7 @@ func TestVerdictEnvelopeV1RC1_RejectsEnvelopeDrift(t *testing.T) { // drift here is a release-tagging bug, not a schema cleanup. func TestVerdictEnvelopeV1RC1_HasStableID(t *testing.T) { t.Parallel() - bs, err := os.ReadFile(envelopeSchemaPath) //nolint:gosec // test-local relative path + bs, err := os.ReadFile(envelopeSchemaPath) require.NoError(t, err) var doc map[string]any require.NoError(t, json.Unmarshal(bs, &doc)) @@ -385,7 +384,7 @@ func TestCanonicalShippedFixtures_PatternIDsMatchDetectorConsts(t *testing.T) { "silent_data_corruption": patterns.PatternIDSilentDataCorruption, } - bs, err := os.ReadFile(canonicalShippedFixturesPath) //nolint:gosec // test-local relative path + bs, err := os.ReadFile(canonicalShippedFixturesPath) require.NoError(t, err) var doc struct { diff --git a/module/pkg/patterns/verdict_schema_test.go b/module/pkg/patterns/verdict_schema_test.go index 8cab8185..40dd3a8d 100644 --- a/module/pkg/patterns/verdict_schema_test.go +++ b/module/pkg/patterns/verdict_schema_test.go @@ -4,14 +4,13 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "testing" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // TestPodEvictedVerdict_SchemaConformance loads testdata/verdict.schema.json @@ -21,16 +20,7 @@ import ( func TestPodEvictedVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err, "schema file is the rubric L405 fixture; do not remove it") - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "verdict.schema.json")) cases := []struct { name string @@ -87,16 +77,7 @@ func TestPodEvictedVerdict_SchemaConformance(t *testing.T) { func TestPodEvictedVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "verdict.schema.json")) validEvidence := []any{map[string]any{ "kind": "pod_event", "uid": "u", diff --git a/module/pkg/patterns/xid_correlation_test.go b/module/pkg/patterns/xid_correlation_test.go index 7144a44d..faa8aa29 100644 --- a/module/pkg/patterns/xid_correlation_test.go +++ b/module/pkg/patterns/xid_correlation_test.go @@ -4,16 +4,15 @@ package patterns_test import ( "encoding/json" - "os" "path/filepath" "regexp" "testing" "time" - "github.com/santhosh-tekuri/jsonschema/v6" "github.com/stretchr/testify/require" "github.com/tracecoreai/tracecore/module/pkg/patterns" + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" ) // xid_correlation detector test suite. The detector reads GPU Xid @@ -404,16 +403,7 @@ func TestXidCorrelationVerdict_DeprecatedEvictedPodCoEmits(t *testing.T) { func TestXidCorrelationVerdict_SchemaConformance(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "xid_correlation_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "xid_correlation_verdict.schema.json")) xidAt := time.Unix(1_700_000_000, 0).UTC() xids := []patterns.XidRecord{ @@ -443,16 +433,7 @@ func TestXidCorrelationVerdict_SchemaConformance(t *testing.T) { func TestXidCorrelationVerdict_SchemaRejectsDrift(t *testing.T) { t.Parallel() - schemaPath := filepath.Join("testdata", "xid_correlation_verdict.schema.json") - schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-local relative path - require.NoError(t, err) - - compiler := jsonschema.NewCompiler() - var schemaDoc any - require.NoError(t, json.Unmarshal(schemaBytes, &schemaDoc)) - require.NoError(t, compiler.AddResource(schemaPath, schemaDoc)) - schema, err := compiler.Compile(schemaPath) - require.NoError(t, err) + schema := jsonschematest.Compile(t, filepath.Join("testdata", "xid_correlation_verdict.schema.json")) validEvidence := []any{ map[string]any{"kind": "kernel_event", "uid": "u1", "timestamp": "2026-05-18T10:00:00Z", "description": "d"}, diff --git a/module/pkg/replay/helpers_test.go b/module/pkg/replay/helpers_test.go index 04e71517..4a397e75 100644 --- a/module/pkg/replay/helpers_test.go +++ b/module/pkg/replay/helpers_test.go @@ -64,7 +64,7 @@ func listFixtures(root string) ([]string, error) { // corpus fails fast. func readJSON(t *testing.T, path string, target any) { t.Helper() - bs, err := os.ReadFile(path) //nolint:gosec // fixture path is test-controlled + bs, err := os.ReadFile(path) if os.IsNotExist(err) { return } @@ -87,7 +87,7 @@ func assertGolden(t *testing.T, dir string, got any) { return } - want, err := os.ReadFile(goldenPath) //nolint:gosec // fixture path is test-controlled + want, err := os.ReadFile(goldenPath) require.NoError(t, err, "read golden %s", goldenPath) require.JSONEq(t, string(want), string(gotJSON), "detector output diverged from %s", goldenPath) diff --git a/module/pkg/replay/manifest_schema_test.go b/module/pkg/replay/manifest_schema_test.go index 32cd0e07..d17877d1 100644 --- a/module/pkg/replay/manifest_schema_test.go +++ b/module/pkg/replay/manifest_schema_test.go @@ -66,7 +66,7 @@ func TestReplayCorporaManifestSchema(t *testing.T) { if filepath.Base(path) != "manifest.json" { return nil } - bs, readErr := os.ReadFile(path) //nolint:gosec // fixture path is test-controlled + bs, readErr := os.ReadFile(path) require.NoError(t, readErr, "read manifest %s", path) var m manifestEnvelope diff --git a/module/pkg/testutil/jsonschematest/jsonschematest.go b/module/pkg/testutil/jsonschematest/jsonschematest.go new file mode 100644 index 00000000..dc4b817c --- /dev/null +++ b/module/pkg/testutil/jsonschematest/jsonschematest.go @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: Apache-2.0 + +// Package jsonschematest centralizes the load-parse-compile dance that +// every pattern detector's schema-conformance test was previously +// open-coding (issue #499). Each call site looked like: +// +// schemaBytes, err := os.ReadFile(schemaPath) // test-local +// require.NoError(t, err) +// compiler := jsonschema.NewCompiler() +// var doc any +// require.NoError(t, json.Unmarshal(schemaBytes, &doc)) +// require.NoError(t, compiler.AddResource(schemaPath, doc)) +// schema, err := compiler.Compile(schemaPath) +// require.NoError(t, err) +// +// — repeated 22 times across 12 test files, each carrying an inline +// gosec G304 waiver. The helper collapses all of that to one line and +// the waiver moves to a single path-scoped exclusion in .golangci.yml +// (gosec G304 on *_test.go). Detector tests that compile +// JSON Schema fixtures should call this; ad-hoc inline compilation is +// a drift risk. +package jsonschematest + +import ( + "encoding/json" + "os" + "testing" + + "github.com/santhosh-tekuri/jsonschema/v6" +) + +// Compile reads, parses, and compiles the JSON Schema at schemaPath +// (relative to the test's working directory, typically +// "testdata/_verdict.schema.json"). It calls t.Fatalf on any +// failure — a missing schema file, malformed JSON, or a compiler error +// is a binary "test cannot run" condition, not an assertion the body +// should keep going past. +// +// The function uses testing.TB instead of *testing.T so it composes +// with subtests and benchmarks without forcing a cast at the call +// site. +func Compile(t testing.TB, schemaPath string) *jsonschema.Schema { + t.Helper() + + // G304: the path is test-local. The package-level gosec G304 + // exclusion for *_test.go in .golangci.yml covers callers; this + // helper is non-test code but is only reachable from tests, so + // we accept one waiver here in exchange for deleting 22 inline + // waivers across the patterns suite. + schemaBytes, err := os.ReadFile(schemaPath) //nolint:gosec // schemaPath is a test-controlled relative path; helper is reached only from tests + if err != nil { + t.Fatalf("jsonschematest.Compile: read %s: %v", schemaPath, err) + return nil + } + + compiler := jsonschema.NewCompiler() + var doc any + if err := json.Unmarshal(schemaBytes, &doc); err != nil { + t.Fatalf("jsonschematest.Compile: unmarshal %s: %v", schemaPath, err) + return nil + } + if err := compiler.AddResource(schemaPath, doc); err != nil { + t.Fatalf("jsonschematest.Compile: add resource %s: %v", schemaPath, err) + return nil + } + schema, err := compiler.Compile(schemaPath) + if err != nil { + t.Fatalf("jsonschematest.Compile: compile %s: %v", schemaPath, err) + return nil + } + return schema +} diff --git a/module/pkg/testutil/jsonschematest/jsonschematest_test.go b/module/pkg/testutil/jsonschematest/jsonschematest_test.go new file mode 100644 index 00000000..81c02850 --- /dev/null +++ b/module/pkg/testutil/jsonschematest/jsonschematest_test.go @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: Apache-2.0 + +package jsonschematest_test + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tracecoreai/tracecore/module/pkg/testutil/jsonschematest" +) + +// TestCompile_ValidSchema returns a schema that accepts conforming +// documents and rejects non-conforming ones — the helper's contract: +// it must produce a usable *jsonschema.Schema, not a sentinel. +func TestCompile_ValidSchema(t *testing.T) { + t.Parallel() + + schema := jsonschematest.Compile(t, filepath.Join("testdata", "valid.schema.json")) + require.NotNil(t, schema, "Compile must return a non-nil schema for a valid schema file") + + // Conforming document validates. + require.NoError(t, schema.Validate(map[string]any{"name": "ok", "count": 1})) + // Missing required field is rejected (proves we actually compiled the schema, + // not just a stub that accepts everything). + require.Error(t, schema.Validate(map[string]any{"count": 1}), + "schema with required:[name] must reject documents missing 'name'") +} + +// TestCompile_FailsOnMissingFile asserts the helper does not silently +// swallow a missing-file error — a refactor that hides ReadFile errors +// would let an entire test suite pass against a non-existent schema. +// We run the failure case in a subtest with a stub testing.T because +// the helper signals via t.Fatal, which would abort this test if used +// directly. +func TestCompile_FailsOnMissingFile(t *testing.T) { + t.Parallel() + + bogus := filepath.Join("testdata", "does_not_exist.schema.json") + stub := &stubT{TB: t} + // Run inside a goroutine because t.Fatal calls runtime.Goexit; we + // want to observe that the failure was recorded, not let it tear + // down our test. + done := make(chan struct{}) + go func() { + defer close(done) + defer func() { _ = recover() }() + jsonschematest.Compile(stub, bogus) + }() + <-done + + require.True(t, stub.failed, "Compile must call t.Fatal on missing schema file (got no failure)") +} + +// stubT implements just enough of testing.TB for jsonschematest.Compile +// to drive its t.Helper / t.Fatalf path under test. We embed testing.TB +// so the type satisfies the interface; only the methods Compile actually +// invokes are observed. +type stubT struct { + testing.TB + failed bool +} + +func (s *stubT) Helper() {} + +func (s *stubT) Fatalf(format string, args ...any) { + s.failed = true + s.Logf("stubT.Fatalf: "+format, args...) + // Mimic real testing.T.Fatalf which terminates the goroutine. + panic("stubT.Fatalf") +} + +func (s *stubT) Errorf(format string, args ...any) { + s.failed = true + s.Logf("stubT.Errorf: "+format, args...) +} diff --git a/module/pkg/testutil/jsonschematest/testdata/valid.schema.json b/module/pkg/testutil/jsonschematest/testdata/valid.schema.json new file mode 100644 index 00000000..db1f11d6 --- /dev/null +++ b/module/pkg/testutil/jsonschematest/testdata/valid.schema.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/valid.schema.json", + "type": "object", + "required": ["name"], + "properties": { + "name": {"type": "string"}, + "count": {"type": "integer", "minimum": 0} + }, + "additionalProperties": false +} diff --git a/module/processor/patterndetectorprocessor/cuda_oom_recipe_test.go b/module/processor/patterndetectorprocessor/cuda_oom_recipe_test.go index 551678f3..c5b86a2a 100644 --- a/module/processor/patterndetectorprocessor/cuda_oom_recipe_test.go +++ b/module/processor/patterndetectorprocessor/cuda_oom_recipe_test.go @@ -40,7 +40,7 @@ func TestRecipe_CUDAOOM_StanzaPinsWireContract(t *testing.T) { t.Parallel() recipePath := findRepoFile(t, "docs/integrations/examples/filelog-container.yaml") - raw, err := os.ReadFile(recipePath) //nolint:gosec // G304: test-local repo path resolved via findRepoFile; not user-controlled. + raw, err := os.ReadFile(recipePath) require.NoError(t, err, "reading recipe example yaml") recipe := string(raw) diff --git a/module/processor/patterndetectorprocessor/ib_link_flap_recipe_test.go b/module/processor/patterndetectorprocessor/ib_link_flap_recipe_test.go index b790e9b8..733fa8ce 100644 --- a/module/processor/patterndetectorprocessor/ib_link_flap_recipe_test.go +++ b/module/processor/patterndetectorprocessor/ib_link_flap_recipe_test.go @@ -38,7 +38,7 @@ func TestRecipe_IBLinkFlap_StanzaPinsWireContract(t *testing.T) { // Walk up to the repo root so the test is invariant under // `go test ./...` from anywhere. recipePath := findRepoFile(t, "docs/integrations/examples/prometheus-scrape.yaml") - raw, err := os.ReadFile(recipePath) //nolint:gosec // G304: test-local repo path resolved via findRepoFile; not user-controlled. + raw, err := os.ReadFile(recipePath) require.NoError(t, err, "reading recipe example yaml") recipe := string(raw) diff --git a/module/processor/rankjoinprocessor/rankjoin_test.go b/module/processor/rankjoinprocessor/rankjoin_test.go index a0568cbf..d197de0a 100644 --- a/module/processor/rankjoinprocessor/rankjoin_test.go +++ b/module/processor/rankjoinprocessor/rankjoin_test.go @@ -207,7 +207,7 @@ func TestRankJoin_FixtureCorpusGoldenLoadsCleanly(t *testing.T) { // 2026-05-18T10:00:00Z. The fixture is the rubric L404 deliverable // for M19. fixtureDir := filepath.Join("..", "..", "pkg", "replay", "pod_evicted", "canonical") - manBytes, err := os.ReadFile(filepath.Join(fixtureDir, "manifest.json")) //nolint:gosec // G304: test-local fixture path. + manBytes, err := os.ReadFile(filepath.Join(fixtureDir, "manifest.json")) if err != nil { t.Fatalf("read manifest: %v", err) } @@ -221,7 +221,7 @@ func TestRankJoin_FixtureCorpusGoldenLoadsCleanly(t *testing.T) { t.Fatalf("manifest pattern_id: got %q, want %q (fixture drift)", manifest.PatternID, patterns.PatternIDPodEvicted) } - eventsBytes, err := os.ReadFile(filepath.Join(fixtureDir, "events.json")) //nolint:gosec // G304: test-local fixture path. + eventsBytes, err := os.ReadFile(filepath.Join(fixtureDir, "events.json")) if err != nil { t.Fatalf("read events: %v", err) } diff --git a/module/receiver/ncclfrreceiver/nccl_fr_integration_test.go b/module/receiver/ncclfrreceiver/nccl_fr_integration_test.go index b5bb2471..baf0ace0 100644 --- a/module/receiver/ncclfrreceiver/nccl_fr_integration_test.go +++ b/module/receiver/ncclfrreceiver/nccl_fr_integration_test.go @@ -87,7 +87,7 @@ func TestIntegration_E2E_FactoryToConsumer(t *testing.T) { }() // Drop the committed .pkl fixture into the watched directory. - pklBytes, err := os.ReadFile(filepath.Join(integrationFixtureDir, slug+".pkl")) //nolint:gosec // G304: test-local fixture path. + pklBytes, err := os.ReadFile(filepath.Join(integrationFixtureDir, slug+".pkl")) if err != nil { t.Fatalf("read committed fixture: %v (run `make generate-fixtures`)", err) } @@ -238,7 +238,7 @@ func runFixtureRoundtrip(t *testing.T, slug string) { _ = r.Shutdown(stopCtx) }() - pklBytes, err := os.ReadFile(filepath.Join(integrationFixtureDir, slug+".pkl")) //nolint:gosec // G304: test-local fixture path. + pklBytes, err := os.ReadFile(filepath.Join(integrationFixtureDir, slug+".pkl")) if err != nil { t.Fatalf("read committed fixture: %v", err) } @@ -453,7 +453,7 @@ func assertGolden(t *testing.T, path string, got []normalizedLog) { return } - gotFile, err := os.ReadFile(path) //nolint:gosec // testdata-relative path + gotFile, err := os.ReadFile(path) if err != nil { if errors.Is(err, os.ErrNotExist) { t.Fatalf("golden %s missing — regenerate with `UPDATE_GOLDEN=1 go test ./module/receiver/ncclfrreceiver/...`", path) diff --git a/module/sdk/verdict/decode_test.go b/module/sdk/verdict/decode_test.go index 69bbc265..e24c2f91 100644 --- a/module/sdk/verdict/decode_test.go +++ b/module/sdk/verdict/decode_test.go @@ -37,7 +37,7 @@ type shippedFixture struct { // cross-SDK fixture contract for issue #368. func loadShippedFixtures(t *testing.T) []shippedFixture { t.Helper() - bs, err := os.ReadFile(canonicalFixturesPath) //nolint:gosec // test-local relative path + bs, err := os.ReadFile(canonicalFixturesPath) require.NoError(t, err, "docs/schemas/fixtures/shipped-patterns-v1.0.0-rc1.json must exist; "+ "this file is the single source of truth for shipped pattern fixtures "+ diff --git a/module/sdk/verdict/schema_sync_test.go b/module/sdk/verdict/schema_sync_test.go index 9adee0ee..3c9a1c80 100644 --- a/module/sdk/verdict/schema_sync_test.go +++ b/module/sdk/verdict/schema_sync_test.go @@ -33,11 +33,11 @@ import ( func TestEmbeddedSchemaMatchesCanonical(t *testing.T) { t.Parallel() - embeddedRaw, err := os.ReadFile(filepath.Join(".", "schema.json")) //nolint:gosec // test-local + embeddedRaw, err := os.ReadFile(filepath.Join(".", "schema.json")) require.NoError(t, err, "module/sdk/verdict/schema.json must exist (build-time embed source)") canonicalRaw, err := os.ReadFile( - filepath.Join("..", "..", "..", "docs", "schemas", "verdict-1.0.0-rc1.json")) //nolint:gosec // test-local + filepath.Join("..", "..", "..", "docs", "schemas", "verdict-1.0.0-rc1.json")) require.NoError(t, err, "docs/schemas/verdict-1.0.0-rc1.json is the criterion-2 source of truth") var embedded, canonical any