Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions pkg/plugins/cidrs/pure_fns_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package cidrs

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// ── splitHandles (rdap.go) ────────────────────────────────────────────────────
Expand Down Expand Up @@ -73,3 +75,45 @@ func TestIsLikelyRIRHandle_CaseSensitive(t *testing.T) {
assert.False(t, isLikelyRIRHandle("SEC-FILING"))
assert.True(t, isLikelyRIRHandle("PRAETORIAN-1")) // no blocklisted prefix
}

// ── ArinRefs UnmarshalJSON (reverse_rir.go) ─────────────────────────────────

func TestArinRefs_UnmarshalArray(t *testing.T) {
data := `[{"@handle":"ACME-1","@name":"Acme"},{"@handle":"ACME-2","@name":"Acme Inc"}]`
var refs ArinRefs
require.NoError(t, json.Unmarshal([]byte(data), &refs))
require.Len(t, refs, 2)
assert.Equal(t, "ACME-1", refs[0].Handle)
assert.Equal(t, "ACME-2", refs[1].Handle)
}

func TestArinRefs_UnmarshalSingleObject(t *testing.T) {
data := `{"@handle":"PS-1576","@name":"Praetorian Security, Inc."}`
var refs ArinRefs
require.NoError(t, json.Unmarshal([]byte(data), &refs))
require.Len(t, refs, 1)
assert.Equal(t, "PS-1576", refs[0].Handle)
}

func TestArinRefs_UnmarshalNull(t *testing.T) {
data := `null`
var refs ArinRefs
require.NoError(t, json.Unmarshal([]byte(data), &refs))
assert.Empty(t, refs)
}

func TestArinOrgsResponse_SingleResult(t *testing.T) {
data := `{"orgs":{"orgRef":{"@handle":"PS-1576","@name":"Praetorian Security, Inc."}}}`
var resp ArinOrgsResponse
require.NoError(t, json.Unmarshal([]byte(data), &resp))
require.Len(t, resp.Orgs.OrgRef, 1)
assert.Equal(t, "PS-1576", resp.Orgs.OrgRef[0].Handle)
}

func TestArinOrgsResponse_MultipleResults(t *testing.T) {
data := `{"orgs":{"orgRef":[{"@handle":"PRAET-1","@name":"Praetorian Global"},{"@handle":"PS-1576","@name":"Praetorian Security"}]}}`
var resp ArinOrgsResponse
require.NoError(t, json.Unmarshal([]byte(data), &resp))
require.Len(t, resp.Orgs.OrgRef, 2)
assert.Equal(t, "PRAET-1", resp.Orgs.OrgRef[0].Handle)
}
29 changes: 25 additions & 4 deletions pkg/plugins/cidrs/reverse_rir.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,27 +333,48 @@ type ArinRef struct {
Name string `json:"@name"`
}

// ArinRefs handles ARIN's JSON quirk: single results are returned as a bare
// object, not a single-element array. Standard json.Unmarshal fails silently
// when unmarshaling an object into []T.
type ArinRefs []ArinRef

func (r *ArinRefs) UnmarshalJSON(data []byte) error {
// Try array first (common case with multiple results).
var arr []ArinRef
if err := json.Unmarshal(data, &arr); err == nil {
*r = arr
return nil
}
// Fall back to single object (ARIN returns this for exactly one result).
var single ArinRef
if err := json.Unmarshal(data, &single); err != nil {
return err
}
*r = ArinRefs{single}
return nil
}

type ArinOrgsResponse struct {
Orgs struct {
OrgRef []ArinRef `json:"orgRef"`
OrgRef ArinRefs `json:"orgRef"`
} `json:"orgs"`
}

type ArinCustomersResponse struct {
Customers struct {
CustomerRef []ArinRef `json:"customerRef"`
CustomerRef ArinRefs `json:"customerRef"`
} `json:"customers"`
}

type ArinNetsResponse struct {
Nets struct {
NetRef []ArinRef `json:"netRef"`
NetRef ArinRefs `json:"netRef"`
} `json:"nets"`
}

type ArinAsnsResponse struct {
Asns struct {
AsnRef []ArinRef `json:"asnRef"`
AsnRef ArinRefs `json:"asnRef"`
} `json:"asns"`
}

Expand Down
26 changes: 22 additions & 4 deletions pkg/runner/internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,41 @@ func TestEnrichWithHandles_MultipleRegistries(t *testing.T) {
assert.Empty(t, result.Meta["afrinic_handles"])
}

func TestEnrichWithHandles_UnknownRegistryBroadcastsToAll(t *testing.T) {
// Tests Phase 11 fix: a FindingCIDRHandle with no/empty registry key
// must be broadcast to ALL FOUR RIRs (arin, ripe, apnic, afrinic).
func TestEnrichWithHandles_EmptyRegistryBroadcastsToAll(t *testing.T) {
input := plugins.Input{OrgName: "Acme", Meta: make(map[string]string)}
findings := []plugins.Finding{
{
Type: plugins.FindingCIDRHandle,
Value: "UNKNOWN-HANDLE",
Source: "edgar",
Data: map[string]any{}, // no "registry" key → unknown
Data: map[string]any{}, // no "registry" key → empty string
},
}
result := enrichWithHandles(input, findings)
assert.Equal(t, "UNKNOWN-HANDLE", result.Meta["arin_handles"])
assert.Equal(t, "UNKNOWN-HANDLE", result.Meta["ripe_handles"])
assert.Equal(t, "UNKNOWN-HANDLE", result.Meta["apnic_handles"])
assert.Equal(t, "UNKNOWN-HANDLE", result.Meta["afrinic_handles"])
assert.Equal(t, "UNKNOWN-HANDLE", result.Meta["lacnic_handles"])
}

func TestEnrichWithHandles_UnknownRegistryBroadcastsToAll(t *testing.T) {
input := plugins.Input{OrgName: "Acme", Meta: make(map[string]string)}
findings := []plugins.Finding{
{
Type: plugins.FindingCIDRHandle,
Value: "EDGAR-HANDLE",
Source: "edgar",
Data: map[string]any{"registry": "unknown", "org": "Acme"},
},
}
result := enrichWithHandles(input, findings)
assert.Equal(t, "EDGAR-HANDLE", result.Meta["arin_handles"])
assert.Equal(t, "EDGAR-HANDLE", result.Meta["ripe_handles"])
assert.Equal(t, "EDGAR-HANDLE", result.Meta["apnic_handles"])
assert.Equal(t, "EDGAR-HANDLE", result.Meta["afrinic_handles"])
assert.Equal(t, "EDGAR-HANDLE", result.Meta["lacnic_handles"])
assert.Empty(t, result.Meta["unknown_handles"])
}

func TestEnrichWithHandles_PreservesExistingMeta(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/runner/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ func enrichWithHandles(input plugins.Input, findings []plugins.Finding) plugins.
continue
}
reg, _ := f.Data["registry"].(string)
if reg == "" {
for _, r := range []string{"arin", "ripe", "apnic", "afrinic"} {
if reg == "" || reg == "unknown" {
for _, r := range []string{"arin", "ripe", "apnic", "afrinic", "lacnic"} {
groups[r] = append(groups[r], f.Value)
}
continue
Expand Down
Loading