Compare commits

...

8 Commits

Author SHA1 Message Date
Zubair Khan 50b05655af Merge branch 'main' into thog-scanner-detector 2023-07-06 19:15:44 -04:00
Zubair Khan d8814d2036 update test 2023-07-06 19:15:15 -04:00
Zubair Khan ecebfde7e7 remove debug logs 2023-07-06 19:13:51 -04:00
Zubair Khan 4988bc7fea remove unused client 2023-07-06 19:13:11 -04:00
Zubair Khan a1a948c2c2 proto stuff 2023-07-06 19:09:04 -04:00
Zubair Khan 9840de71aa patterns and test 2023-07-06 15:36:21 -04:00
Zubair Khan 9a46b9b8ac save progress 2023-07-06 14:03:32 -04:00
Zubair Khan 39d8d0319a init 2023-07-06 13:23:47 -04:00
8 changed files with 830 additions and 6 deletions
@@ -0,0 +1,309 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.20.0
// source: api.proto
package scannerpb
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type HeartbeatRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
}
func (x *HeartbeatRequest) Reset() {
*x = HeartbeatRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HeartbeatRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeartbeatRequest) ProtoMessage() {}
func (x *HeartbeatRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeartbeatRequest.ProtoReflect.Descriptor instead.
func (*HeartbeatRequest) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{0}
}
func (x *HeartbeatRequest) GetStatus() string {
if x != nil {
return x.Status
}
return ""
}
func (x *HeartbeatRequest) GetReason() string {
if x != nil {
return x.Reason
}
return ""
}
func (x *HeartbeatRequest) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
type HeartbeatResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *HeartbeatResponse) Reset() {
*x = HeartbeatResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HeartbeatResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeartbeatResponse) ProtoMessage() {}
func (x *HeartbeatResponse) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeartbeatResponse.ProtoReflect.Descriptor instead.
func (*HeartbeatResponse) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{1}
}
var File_api_proto protoreflect.FileDescriptor
var file_api_proto_rawDesc = []byte{
0x0a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69,
0x22, 0x5c, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06,
0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65,
0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x13,
0x0a, 0x11, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x32, 0x4a, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74,
0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x65,
0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
0x5e, 0x5a, 0x5c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72,
0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72,
0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c,
0x65, 0x68, 0x6f, 0x67, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x73, 0x63,
0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x70, 0x62, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_api_proto_rawDescOnce sync.Once
file_api_proto_rawDescData = file_api_proto_rawDesc
)
func file_api_proto_rawDescGZIP() []byte {
file_api_proto_rawDescOnce.Do(func() {
file_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_proto_rawDescData)
})
return file_api_proto_rawDescData
}
var file_api_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_api_proto_goTypes = []interface{}{
(*HeartbeatRequest)(nil), // 0: api.HeartbeatRequest
(*HeartbeatResponse)(nil), // 1: api.HeartbeatResponse
}
var file_api_proto_depIdxs = []int32{
0, // 0: api.AgentService.Heartbeat:input_type -> api.HeartbeatRequest
1, // 1: api.AgentService.Heartbeat:output_type -> api.HeartbeatResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_api_proto_init() }
func file_api_proto_init() {
if File_api_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HeartbeatRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HeartbeatResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_api_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_api_proto_goTypes,
DependencyIndexes: file_api_proto_depIdxs,
MessageInfos: file_api_proto_msgTypes,
}.Build()
File_api_proto = out.File
file_api_proto_rawDesc = nil
file_api_proto_goTypes = nil
file_api_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// AgentServiceClient is the client API for AgentService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type AgentServiceClient interface {
Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error)
}
type agentServiceClient struct {
cc grpc.ClientConnInterface
}
func NewAgentServiceClient(cc grpc.ClientConnInterface) AgentServiceClient {
return &agentServiceClient{cc}
}
func (c *agentServiceClient) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) {
out := new(HeartbeatResponse)
err := c.cc.Invoke(ctx, "/api.AgentService/Heartbeat", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// AgentServiceServer is the server API for AgentService service.
type AgentServiceServer interface {
Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error)
}
// UnimplementedAgentServiceServer can be embedded to have forward compatible implementations.
type UnimplementedAgentServiceServer struct {
}
func (*UnimplementedAgentServiceServer) Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Heartbeat not implemented")
}
func RegisterAgentServiceServer(s *grpc.Server, srv AgentServiceServer) {
s.RegisterService(&_AgentService_serviceDesc, srv)
}
func _AgentService_Heartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HeartbeatRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServiceServer).Heartbeat(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.AgentService/Heartbeat",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServiceServer).Heartbeat(ctx, req.(*HeartbeatRequest))
}
return interceptor(ctx, in, info, handler)
}
var _AgentService_serviceDesc = grpc.ServiceDesc{
ServiceName: "api.AgentService",
HandlerType: (*AgentServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Heartbeat",
Handler: _AgentService_Heartbeat_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api.proto",
}
@@ -0,0 +1,244 @@
// Code generated by protoc-gen-validate. DO NOT EDIT.
// source: api.proto
package scannerpb
import (
"bytes"
"errors"
"fmt"
"net"
"net/mail"
"net/url"
"regexp"
"sort"
"strings"
"time"
"unicode/utf8"
"google.golang.org/protobuf/types/known/anypb"
)
// ensure the imports are used
var (
_ = bytes.MinRead
_ = errors.New("")
_ = fmt.Print
_ = utf8.UTFMax
_ = (*regexp.Regexp)(nil)
_ = (*strings.Reader)(nil)
_ = net.IPv4len
_ = time.Duration(0)
_ = (*url.URL)(nil)
_ = (*mail.Address)(nil)
_ = anypb.Any{}
_ = sort.Sort
)
// Validate checks the field values on HeartbeatRequest with the rules defined
// in the proto definition for this message. If any rules are violated, the
// first error encountered is returned, or nil if there are no violations.
func (m *HeartbeatRequest) Validate() error {
return m.validate(false)
}
// ValidateAll checks the field values on HeartbeatRequest with the rules
// defined in the proto definition for this message. If any rules are
// violated, the result is a list of violation errors wrapped in
// HeartbeatRequestMultiError, or nil if none found.
func (m *HeartbeatRequest) ValidateAll() error {
return m.validate(true)
}
func (m *HeartbeatRequest) validate(all bool) error {
if m == nil {
return nil
}
var errors []error
// no validation rules for Status
// no validation rules for Reason
// no validation rules for Version
if len(errors) > 0 {
return HeartbeatRequestMultiError(errors)
}
return nil
}
// HeartbeatRequestMultiError is an error wrapping multiple validation errors
// returned by HeartbeatRequest.ValidateAll() if the designated constraints
// aren't met.
type HeartbeatRequestMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m HeartbeatRequestMultiError) Error() string {
var msgs []string
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
// AllErrors returns a list of validation violation errors.
func (m HeartbeatRequestMultiError) AllErrors() []error { return m }
// HeartbeatRequestValidationError is the validation error returned by
// HeartbeatRequest.Validate if the designated constraints aren't met.
type HeartbeatRequestValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e HeartbeatRequestValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e HeartbeatRequestValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e HeartbeatRequestValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e HeartbeatRequestValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e HeartbeatRequestValidationError) ErrorName() string { return "HeartbeatRequestValidationError" }
// Error satisfies the builtin error interface
func (e HeartbeatRequestValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sHeartbeatRequest.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = HeartbeatRequestValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = HeartbeatRequestValidationError{}
// Validate checks the field values on HeartbeatResponse with the rules defined
// in the proto definition for this message. If any rules are violated, the
// first error encountered is returned, or nil if there are no violations.
func (m *HeartbeatResponse) Validate() error {
return m.validate(false)
}
// ValidateAll checks the field values on HeartbeatResponse with the rules
// defined in the proto definition for this message. If any rules are
// violated, the result is a list of violation errors wrapped in
// HeartbeatResponseMultiError, or nil if none found.
func (m *HeartbeatResponse) ValidateAll() error {
return m.validate(true)
}
func (m *HeartbeatResponse) validate(all bool) error {
if m == nil {
return nil
}
var errors []error
if len(errors) > 0 {
return HeartbeatResponseMultiError(errors)
}
return nil
}
// HeartbeatResponseMultiError is an error wrapping multiple validation errors
// returned by HeartbeatResponse.ValidateAll() if the designated constraints
// aren't met.
type HeartbeatResponseMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m HeartbeatResponseMultiError) Error() string {
var msgs []string
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
// AllErrors returns a list of validation violation errors.
func (m HeartbeatResponseMultiError) AllErrors() []error { return m }
// HeartbeatResponseValidationError is the validation error returned by
// HeartbeatResponse.Validate if the designated constraints aren't met.
type HeartbeatResponseValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e HeartbeatResponseValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e HeartbeatResponseValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e HeartbeatResponseValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e HeartbeatResponseValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e HeartbeatResponseValidationError) ErrorName() string {
return "HeartbeatResponseValidationError"
}
// Error satisfies the builtin error interface
func (e HeartbeatResponseValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sHeartbeatResponse.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = HeartbeatResponseValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = HeartbeatResponseValidationError{}
@@ -0,0 +1,117 @@
package trufflehogenterprisescanner
import (
"context"
"crypto/tls"
"crypto/x509"
"regexp"
"strings"
"github.com/pkg/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/trufflehogenterprisescanner/scannerpb"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
)
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(`\bthog-agent-[0-9a-f]{32}\b`)
groupPat = regexp.MustCompile(`\bthog-scanner-[a-zA-Z]+\b`)
addressPat = regexp.MustCompile(`\b[a-z]+-[a-z]+-[a-z]+.[a-z]+\.[a-z][0-9]\.[a-z]+\.trufflehog\.org:[0-9]{4}\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"thog"}
}
// FromData will find and optionally verify TrufflehogEnterpriseScanner secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
keyMatches := keyPat.FindAllStringSubmatch(dataStr, -1)
groupMatches := groupPat.FindAllStringSubmatch(dataStr, -1)
addressMatches := addressPat.FindAllStringSubmatch(dataStr, -1)
for _, keyMatch := range keyMatches {
if len(keyMatch) != 1 {
continue
}
resKeyMatch := strings.TrimSpace(keyMatch[0])
for _, groupMatch := range groupMatches {
if len(groupMatch) != 1 {
continue
}
resGroupMatch := strings.TrimSpace(groupMatch[0])
for _, addressMatch := range addressMatches {
if len(addressMatch) != 1 {
continue
}
resAddressMatch := strings.TrimSpace(addressMatch[0])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_TrufflehogEnterpriseScanner,
Raw: []byte(resKeyMatch),
}
if verify {
err := grpcHeartbeat(resAddressMatch, resGroupMatch, resKeyMatch)
if err == nil {
s1.Verified = true
}
}
results = append(results, s1)
}
}
}
return results, nil
}
func (s Scanner) Type() detectorspb.DetectorType {
return detectorspb.DetectorType_TrufflehogEnterpriseScanner
}
func grpcHeartbeat(address, group, token string) error {
ctx := context.Background()
ctx = metadata.NewOutgoingContext(ctx,
metadata.New(map[string]string{
"name": strings.TrimSpace(group),
"authorization": strings.TrimSpace(token),
}))
systemRoots, err := x509.SystemCertPool()
if err != nil {
panic(errors.Wrap(err, "cannot load root CA certs"))
}
creds := credentials.NewTLS(&tls.Config{
RootCAs: systemRoots,
})
conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))
if err != nil {
return errors.Wrap(err, "cannot dial")
}
defer conn.Close()
c := scannerpb.NewAgentServiceClient(conn)
_, err = c.Heartbeat(ctx, &scannerpb.HeartbeatRequest{Status: "GOOD", Reason: "", Version: "v1.0.0"})
if err != nil {
return errors.Wrap(err, "cannot heartbeat")
}
return nil
}
@@ -0,0 +1,121 @@
//go:build detectors
// +build detectors
package trufflehogenterprisescanner
import (
"context"
"fmt"
"testing"
"time"
"github.com/kylelemons/godebug/pretty"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
)
func TestTrufflehogEnterpriseScanner_FromChunk(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5")
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}
address := testSecrets.MustGetField("THOG_SCANNER_ADDRESS")
group := testSecrets.MustGetField("THOG_SCANNER_GROUP")
token := testSecrets.MustGetField("THOG_SCANNER_TOKEN")
inactiveToken := testSecrets.MustGetField("THOG_SCANNER_TOKEN_INACTIVE")
type args struct {
ctx context.Context
data []byte
verify bool
}
tests := []struct {
name string
s Scanner
args args
want []detectors.Result
wantErr bool
}{
{
name: "found, verified",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a thog scanner secret %s for %s at %s within", token, group, address)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_TrufflehogEnterpriseScanner,
Verified: true,
},
},
wantErr: false,
},
{
name: "found, unverified",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("You can find a thog scanner secret %s for %s at %s within but not valid", inactiveToken, group, address)), // the secret would satisfy the regex but not pass validation
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_TrufflehogEnterpriseScanner,
Verified: false,
},
},
wantErr: false,
},
{
name: "not found",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte("You cannot find the secret within"),
verify: true,
},
want: nil,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := Scanner{}
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("Trufflehogenterprisescanner.FromData() error = %v, wantErr %v", err, tt.wantErr)
return
}
for i := range got {
if len(got[i].Raw) == 0 {
t.Fatalf("no raw secret present: \n %+v", got[i])
}
got[i].Raw = nil
}
if diff := pretty.Compare(got, tt.want); diff != "" {
t.Errorf("Trufflehogenterprisescanner.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
}
})
}
}
func BenchmarkFromData(benchmark *testing.B) {
ctx := context.Background()
s := Scanner{}
for name, data := range detectors.MustGetBenchmarkData() {
benchmark.Run(name, func(b *testing.B) {
for n := 0; n < b.N; n++ {
_, err := s.FromData(ctx, false, data)
if err != nil {
b.Fatal(err)
}
}
})
}
}
+12 -6
View File
@@ -992,6 +992,7 @@ const (
DetectorType_Prefect DetectorType = 918
DetectorType_Docusign DetectorType = 919
DetectorType_Couchbase DetectorType = 920
DetectorType_TrufflehogEnterpriseScanner DetectorType = 922
)
// Enum value maps for DetectorType.
@@ -1914,6 +1915,7 @@ var (
918: "Prefect",
919: "Docusign",
920: "Couchbase",
922: "TrufflehogEnterpriseScanner",
}
DetectorType_value = map[string]int32{
"Alibaba": 0,
@@ -2833,6 +2835,7 @@ var (
"Prefect": 918,
"Docusign": 919,
"Couchbase": 920,
"TrufflehogEnterpriseScanner": 922,
}
)
@@ -3197,7 +3200,7 @@ var file_detectors_proto_rawDesc = []byte{
0x0a, 0x0b, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a,
0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c,
0x41, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x41, 0x53, 0x45, 0x36, 0x34, 0x10,
0x02, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x54, 0x46, 0x31, 0x36, 0x10, 0x03, 0x2a, 0x89, 0x73, 0x0a,
0x02, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x54, 0x46, 0x31, 0x36, 0x10, 0x03, 0x2a, 0xab, 0x73, 0x0a,
0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a,
0x07, 0x41, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x4d,
0x51, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x57, 0x53, 0x10, 0x02, 0x12, 0x09, 0x0a,
@@ -4118,11 +4121,14 @@ var file_detectors_proto_rawDesc = []byte{
0x0a, 0x0a, 0x05, 0x41, 0x69, 0x76, 0x65, 0x6e, 0x10, 0x95, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x50,
0x72, 0x65, 0x66, 0x65, 0x63, 0x74, 0x10, 0x96, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x6f, 0x63,
0x75, 0x73, 0x69, 0x67, 0x6e, 0x10, 0x97, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x75, 0x63,
0x68, 0x62, 0x61, 0x73, 0x65, 0x10, 0x98, 0x07, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65,
0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f,
0x67, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x64, 0x65, 0x74, 0x65,
0x63, 0x74, 0x6f, 0x72, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x68, 0x62, 0x61, 0x73, 0x65, 0x10, 0x98, 0x07, 0x12, 0x20, 0x0a, 0x1b, 0x54, 0x72, 0x75, 0x66,
0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65,
0x53, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x10, 0x9a, 0x07, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65,
0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65,
0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x64, 0x65,
0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
+19
View File
@@ -0,0 +1,19 @@
syntax = "proto3";
package api;
option go_package = "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/trufflehogenterprisescanner/scannerpb";
message HeartbeatRequest {
string status = 1;
string reason = 2;
string version = 3;
}
message HeartbeatResponse {}
service AgentService {
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
}
+1
View File
@@ -929,6 +929,7 @@ enum DetectorType {
Prefect = 918;
Docusign = 919;
Couchbase = 920;
TrufflehogEnterpriseScanner = 922;
}
message Result {
+7
View File
@@ -37,3 +37,10 @@ protoc -I proto/ \
--go_out=plugins=grpc:./pkg/pb/custom_detectorspb --go_opt=paths=source_relative \
--validate_out="lang=go,paths=source_relative:./pkg/pb/custom_detectorspb" \
proto/custom_detectors.proto
protoc -I proto/ \
-I ${GOPATH}/src \
-I /usr/local/include \
-I ${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate \
--go_out=plugins=grpc:./pkg/detectors/trufflehogenterprisescanner/scannerpb --go_opt=paths=source_relative \
--validate_out="lang=go,paths=source_relative:./pkg/detectors/trufflehogenterprisescanner/scannerpb" \
proto/api.proto