Files
bucketeer/internal/scan/scanner_test.go
T

106 lines
3.4 KiB
Go
Raw Normal View History

package scan
import (
"context"
"testing"
"tea.karlcom.de/karl/bucketeer/internal/dns"
"tea.karlcom.de/karl/bucketeer/internal/model"
"tea.karlcom.de/karl/bucketeer/internal/probe"
)
type fakeProber struct {
last model.Candidate
state model.ExposureState
detail string
listable bool
obj bool
}
func (f *fakeProber) ProbeDetailed(ctx context.Context, c model.Candidate) probe.Result {
f.last = c
return probe.Result{Exposure: f.state, Detail: f.detail, Listable: f.listable, ObjectReadable: f.obj}
}
type fakeLister struct{ entries []model.Entry }
func (f *fakeLister) List(ctx context.Context, c model.Candidate) ([]model.Entry, error) {
return f.entries, nil
}
type fakeEnricher struct{ chain []string }
func (f *fakeEnricher) Resolve(ctx context.Context, host string) (dns.Result, bool) {
return dns.Result{Chain: append([]string{host}, f.chain...)}, true
}
type fakeStore struct {
ensured []model.Candidate
entries int
}
func (f *fakeStore) EnsureAsset(ctx context.Context, c model.Candidate) (int64, error) {
f.ensured = append(f.ensured, c)
return int64(len(f.ensured)), nil
}
func (f *fakeStore) ReplaceEntries(ctx context.Context, provider, service, host string, entries []model.Entry) (int, error) {
f.entries = len(entries)
return len(entries), nil
}
func (f *fakeStore) ListProbeTargets(ctx context.Context, exposure string, limit int) ([]model.ProbeTarget, error) {
return nil, nil
}
func (f *fakeStore) UpdateExposure(ctx context.Context, provider, service, host string, state model.ExposureState, detail string, listable, objectReadable bool) error {
return nil
}
func TestScanDirectReadable(t *testing.T) {
pb := &fakeProber{state: model.ExposurePublicRead, detail: "s3 status=200", listable: true}
st := &fakeStore{}
s := &Scanner{Prober: pb, Indexer: &fakeLister{entries: []model.Entry{{Name: "a.txt"}, {Name: "b.txt"}}}, Store: st}
res := s.Scan(context.Background(), "bucket-01.s3-eu-west-1.amazonaws.com")
if len(res) != 1 || res[0].Exposure != "public_read" || res[0].Entries != 2 || len(res[0].Sample) != 2 {
t.Fatalf("unexpected result: %+v", res)
}
}
func TestScanAzureContainerPath(t *testing.T) {
pb := &fakeProber{state: model.ExposurePublicRead, detail: "azure container 'images' is publicly listable", listable: true}
s := &Scanner{Prober: pb, Indexer: &fakeLister{}, Store: &fakeStore{}}
res := s.Scan(context.Background(), "https://eroticfeeldev.blob.core.windows.net/images")
if len(res) != 1 || res[0].Service != "blob_storage" {
t.Fatalf("unexpected result: %+v", res)
}
if pb.last.Container != "images" {
t.Fatalf("container hint not passed: %+v", pb.last)
}
}
func TestScanViaCNAME(t *testing.T) {
pb := &fakeProber{state: model.ExposurePublicRead, listable: true}
st := &fakeStore{}
s := &Scanner{
Prober: pb,
Indexer: &fakeLister{},
Store: st,
Enricher: &fakeEnricher{chain: []string{"veteran1.nyc3.digitaloceanspaces.com"}},
}
res := s.Scan(context.Background(), "cdn.mydomain.example")
if len(res) != 1 || res[0].Provider != "digitalocean" {
t.Fatalf("expected digitalocean via CNAME, got %+v", res)
}
if len(res[0].CNAMEChain) < 2 {
t.Fatalf("expected CNAME chain, got %+v", res[0].CNAMEChain)
}
}
func TestScanUnknown(t *testing.T) {
s := &Scanner{Prober: &fakeProber{}, Store: &fakeStore{}}
res := s.Scan(context.Background(), "www.example.com")
if len(res) != 1 || res[0].Error == "" {
t.Fatalf("expected error result, got %+v", res)
}
}