Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4efe5313f4 | |||
| 7373954ddf | |||
| d2d03426ed | |||
| dd39848709 | |||
| c5b4d6f28b | |||
| ae2d510ced | |||
| 05f6bd369f | |||
| d151c1363e | |||
| ee5b028c67 | |||
| 38562df0f6 | |||
| 4f0e66f064 | |||
| 0b4e3a66b1 | |||
| a293033386 | |||
| d20f43b5c6 | |||
| 9ef9e9870d | |||
| f1582aafa9 | |||
| 9158dcaa80 | |||
| 012fdfe3a2 | |||
| ea71756e20 | |||
| ea40c0f306 | |||
| bcecbcd3d4 | |||
| 926f490c9f | |||
| bd17aa91e3 | |||
| 161e499142 | |||
| c6826c4574 | |||
| f2139a7615 | |||
| 26c455d302 | |||
| 57983aed4e | |||
| 4f13090c01 | |||
| ae14e4506f | |||
| 0c66d30c1f |
@@ -0,0 +1,19 @@
|
||||
# Testing
|
||||
|
||||
Most testing is handled automatically by our GitHub Actions workflows.
|
||||
|
||||
## Local GitHub Action Testing
|
||||
|
||||
In some cases you may wish to submit changes to the Trufflehog GitHub Action. Unfortunately GitHub does not provide a 1st-party testing environment for testing actions outside of GitHub Actions.
|
||||
|
||||
Fortunately [nektos/act](https://github.com/nektos/act) enables local testing of GitHub Actions.
|
||||
|
||||
### Instructions
|
||||
|
||||
1. Please follow [the installation instructions](http://https://github.com/nektos/act#installation) for your OS.
|
||||
2. The first run of `act` will ask you to specify an image. `Medium` should suffice.
|
||||
3. You'll need to configure a personal-access-token(PAT) with: `repo:status`, `repo_deployment`, and `public_repo` permissions.
|
||||
4. Set an environment variable named `GITHUB_TOKEN` with the PAT from the previous step as the value: `$ export GITHUB_TOKEN=<your_PAT>`
|
||||
5. Run the following command from the repository root: `act pull_request -j test -W .github/workflows/secrets.yml -s GITHUB_TOKEN --defaultbranch main`
|
||||
6. If the job was successful, you should expect to see output from the scanner showing several detected secrets.
|
||||
7. If you want to omit the context of a pull request event and just test that the action starts successfully, run: `act -j test -W .github/workflows/secrets.yml -s GITHUB_TOKEN --defaultbranch main`
|
||||
@@ -7,6 +7,7 @@ on:
|
||||
- v*
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
name: Smoke
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
smoke:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18'
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.head_ref }}
|
||||
- name: Smoke
|
||||
run: |
|
||||
set -e
|
||||
go run . git https://github.com/dustin-decker/secretsandstuff.git
|
||||
go run . github --repo https://github.com/dustin-decker/secretsandstuff.git
|
||||
@@ -100,6 +100,12 @@ trufflehog s3 --bucket=<bucket name> --only-verified
|
||||
docker run --rm -v "$HOME/.ssh:/root/.ssh:ro" trufflesecurity/trufflehog:latest git ssh://github.com/trufflesecurity/test_keys
|
||||
```
|
||||
|
||||
### Example 6: Scan individual files or directories
|
||||
|
||||
```bash
|
||||
trufflehog filesystem path/to/file1.txt path/to/file2.txt path/to/dir
|
||||
```
|
||||
|
||||
# What's new in v3?
|
||||
|
||||
TruffleHog v3 is a complete rewrite in Go with many new powerful features.
|
||||
@@ -167,10 +173,10 @@ TruffleHog has a sub-command for each source of data that you may want to scan:
|
||||
- github
|
||||
- gitlab
|
||||
- S3
|
||||
- filesystem
|
||||
- filesystem (files and directories)
|
||||
- syslog
|
||||
- circleci
|
||||
- file and stdin (coming soon)
|
||||
- stdin (coming soon)
|
||||
|
||||
Each subcommand can have options that you can see with the `--help` flag provided to the sub command:
|
||||
|
||||
@@ -311,7 +317,7 @@ detectors:
|
||||
```
|
||||
|
||||
```
|
||||
$ trufflehog filesystem --directory /tmp --config config.yaml --only-verified
|
||||
$ trufflehog filesystem /tmp --config config.yaml --only-verified
|
||||
🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷
|
||||
|
||||
Found verified result 🐷🔑
|
||||
|
||||
@@ -11,7 +11,7 @@ replace github.com/gitleaks/go-gitdiff => github.com/trufflesecurity/go-gitdiff
|
||||
require (
|
||||
cloud.google.com/go/secretmanager v1.10.0
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
|
||||
github.com/TheZeroSlave/zapsentry v1.12.0
|
||||
github.com/TheZeroSlave/zapsentry v1.14.0
|
||||
github.com/aws/aws-sdk-go v1.44.83
|
||||
github.com/bill-rich/disk-buffer-reader v0.1.7
|
||||
github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c
|
||||
@@ -22,7 +22,7 @@ require (
|
||||
github.com/envoyproxy/protoc-gen-validate v0.9.1
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/felixge/fgprof v0.9.3
|
||||
github.com/getsentry/sentry-go v0.17.0
|
||||
github.com/getsentry/sentry-go v0.18.0
|
||||
github.com/go-errors/errors v1.4.2
|
||||
github.com/go-git/go-git/v5 v5.5.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
@@ -41,25 +41,22 @@ require (
|
||||
github.com/jpillora/overseer v1.1.6
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7
|
||||
github.com/paulbellamy/ratecounter v0.2.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rabbitmq/amqp091-go v1.6.0
|
||||
github.com/rabbitmq/amqp091-go v1.7.0
|
||||
github.com/sergi/go-diff v1.3.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502
|
||||
github.com/xanzy/go-gitlab v0.78.0
|
||||
go.mongodb.org/mongo-driver v1.11.1
|
||||
github.com/xanzy/go-gitlab v0.80.2
|
||||
go.mongodb.org/mongo-driver v1.11.2
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.5.0
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7
|
||||
golang.org/x/oauth2 v0.4.0
|
||||
golang.org/x/oauth2 v0.5.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/text v0.6.0
|
||||
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c
|
||||
golang.org/x/text v0.7.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/h2non/gock.v1 v1.1.2
|
||||
@@ -116,6 +113,7 @@ require (
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.15.11 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
@@ -139,12 +137,13 @@ require (
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.3.0 // indirect
|
||||
google.golang.org/api v0.103.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect
|
||||
google.golang.org/grpc v1.51.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
||||
@@ -37,8 +37,8 @@ github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VM
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
|
||||
github.com/TheZeroSlave/zapsentry v1.12.0 h1:hhfwvD7pQbnCIOvAEGM4NXLiaX4b6W6ZWNtL6awSBGc=
|
||||
github.com/TheZeroSlave/zapsentry v1.12.0/go.mod h1:00uO/VpPrSJG/XigAfTi0F4WMFIw2DmP/IDVUhPBvNw=
|
||||
github.com/TheZeroSlave/zapsentry v1.14.0 h1:z6H0lIyKVpdXsP5K8J11b4/+V+QCDLDslZmtXsnduMk=
|
||||
github.com/TheZeroSlave/zapsentry v1.14.0/go.mod h1:0hUR1Et5tSroEYhWOZcxE2iBqcFkuG7jGGlUmOA7XAs=
|
||||
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
|
||||
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
@@ -101,8 +101,8 @@ github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNu
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/getsentry/sentry-go v0.17.0 h1:UustVWnOoDFHBS7IJUB2QK/nB5pap748ZEp0swnQJak=
|
||||
github.com/getsentry/sentry-go v0.17.0/go.mod h1:B82dxtBvxG0KaPD8/hfSV+VcHD+Lg/xUS4JuQn1P4cM=
|
||||
github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
|
||||
github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
||||
@@ -295,15 +295,13 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rabbitmq/amqp091-go v1.6.0 h1:fiFHcMcP+5/A+35MXniiagho1lEXX4+jpHGR+q+LeBU=
|
||||
github.com/rabbitmq/amqp091-go v1.6.0/go.mod h1:wfClAtY0C7bOHxd3GjmF26jEHn+rR/0B3+YV+Vn9/NI=
|
||||
github.com/rabbitmq/amqp091-go v1.7.0 h1:V5CF5qPem5OGSnEo8BoSbsDGwejg6VUJsKEdneaoTUo=
|
||||
github.com/rabbitmq/amqp091-go v1.7.0/go.mod h1:wfClAtY0C7bOHxd3GjmF26jEHn+rR/0B3+YV+Vn9/NI=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
|
||||
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
|
||||
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
|
||||
@@ -335,8 +333,8 @@ github.com/trufflesecurity/overseer v1.1.7-custom5/go.mod h1:nT9w37AiO1Nop2VhVhN
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/xanzy/go-gitlab v0.78.0 h1:8jUHfQVAprG04Av5g0PxVd3CNsZ5hCbojIax7Hba1mE=
|
||||
github.com/xanzy/go-gitlab v0.78.0/go.mod h1:DlByVTSXhPsJMYL6+cm8e8fTJjeBmhrXdC/yvkKKt6M=
|
||||
github.com/xanzy/go-gitlab v0.80.2 h1:CH1Q7NDklqZllox4ICVF4PwlhQGfPtE+w08Jsb74ZX0=
|
||||
github.com/xanzy/go-gitlab v0.80.2/go.mod h1:DlByVTSXhPsJMYL6+cm8e8fTJjeBmhrXdC/yvkKKt6M=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
@@ -352,8 +350,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8=
|
||||
go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
||||
go.mongodb.org/mongo-driver v1.11.2 h1:+1v2rDQUWNcGW7/7E0Jvdz51V38XXxJfhzbV17aNHCw=
|
||||
go.mongodb.org/mongo-driver v1.11.2/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
@@ -377,8 +375,8 @@ golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7 h1:lhh9BuEmjIBOdOhMIGSQzdW5LbTtFbUV1k9O/Rlq3SE=
|
||||
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
@@ -411,11 +409,11 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
|
||||
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
|
||||
golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
|
||||
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -458,21 +456,21 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"text/template"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
@@ -24,7 +26,7 @@ func main() {
|
||||
log.SetPrefix("😲 [generate] ")
|
||||
|
||||
kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||
nameTitle = strings.Title(*name)
|
||||
nameTitle = cases.Title(language.AmericanEnglish).String(*name)
|
||||
nameLower = strings.ToLower(*name)
|
||||
nameUpper = strings.ToUpper(*name)
|
||||
|
||||
@@ -65,7 +67,7 @@ type templateJob struct {
|
||||
}
|
||||
|
||||
func mustWriteTemplates(jobs []templateJob) {
|
||||
log.Printf("Generating %s %s\n", strings.Title(*kind), nameTitle)
|
||||
log.Printf("Generating %s %s\n", cases.Title(language.AmericanEnglish).String(*kind), nameTitle)
|
||||
|
||||
// Make the folder.
|
||||
log.Printf("Creating folder %s\n", folderPath())
|
||||
@@ -84,7 +86,7 @@ func mustWriteTemplates(jobs []templateJob) {
|
||||
|
||||
for _, rplString := range job.ReplaceString {
|
||||
tmplRaw = strings.ReplaceAll(tmplRaw, strings.ToLower(rplString), "<<.NameLower>>")
|
||||
tmplRaw = strings.ReplaceAll(tmplRaw, strings.Title(rplString), "<<.NameTitle>>")
|
||||
tmplRaw = strings.ReplaceAll(tmplRaw, cases.Title(language.AmericanEnglish).String(rplString), "<<.NameTitle>>")
|
||||
tmplRaw = strings.ReplaceAll(tmplRaw, strings.ToUpper(rplString), "<<.NameUpper>>")
|
||||
}
|
||||
|
||||
|
||||
+37
-18
@@ -11,7 +11,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/paulbellamy/ratecounter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
@@ -19,6 +18,7 @@ import (
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/decoders"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/engine"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/log"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||
@@ -42,6 +42,20 @@ var (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// setup logger
|
||||
logger, flush := log.New("trufflehog", log.WithConsoleSink(os.Stderr))
|
||||
// make it the default logger for contexts
|
||||
context.SetDefaultLogger(logger)
|
||||
defer func() { _ = flush() }()
|
||||
logFatal := func(err error, message string, keyAndVals ...any) {
|
||||
logger.Error(err, message, keyAndVals...)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Hour*2)
|
||||
var cancelOnce sync.Once
|
||||
defer cancelOnce.Do(cancel)
|
||||
@@ -68,19 +82,19 @@ func main() {
|
||||
} else {
|
||||
_, ok := allScanners[input]
|
||||
if !ok {
|
||||
log.Fatal("could not find scanner by that name")
|
||||
logFatal(fmt.Errorf("invalid input"), "could not find scanner by that name")
|
||||
}
|
||||
selectedScanners[input] = allScanners[input]
|
||||
}
|
||||
if len(selectedScanners) == 0 {
|
||||
log.Fatal("no detectors selected")
|
||||
logFatal(fmt.Errorf("invalid input"), "no detectors selected")
|
||||
}
|
||||
|
||||
for _, excluded := range *scanCmdExclude {
|
||||
delete(selectedScanners, excluded)
|
||||
}
|
||||
|
||||
log.Infof("loaded %d secret detectors", len(selectedScanners)+3)
|
||||
logger.Info("loaded secret detectors", "count", len(selectedScanners)+3)
|
||||
|
||||
var wgScanners sync.WaitGroup
|
||||
|
||||
@@ -92,7 +106,7 @@ func main() {
|
||||
time.Sleep(60 * time.Second)
|
||||
counter.Incr(int64(chunkCounter - prev))
|
||||
prev = chunkCounter
|
||||
log.Infof("chunk scan rate: %d/sec", counter.Rate()/60)
|
||||
logger.Info("chunk scan rate per second", "rate", counter.Rate()/60)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -122,7 +136,7 @@ func main() {
|
||||
|
||||
res, err := scanner.FromData(ctx, *scanVerify, decoded.Data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
logFatal(err, "error scanning chunk")
|
||||
}
|
||||
if len(res) > 0 {
|
||||
if resCounter[name] == nil {
|
||||
@@ -131,16 +145,19 @@ func main() {
|
||||
}
|
||||
atomic.AddUint64(resCounter[name], uint64(len(res)))
|
||||
if *scanThreshold != 0 && int(*resCounter[name]) > *scanThreshold {
|
||||
log.WithField("scanner", name).Errorf("exceeded result threshold of %d", *scanThreshold)
|
||||
logger.Error(
|
||||
fmt.Errorf("exceeded result threshold"), "snifftest failed",
|
||||
"scanner", name, "threshold", *scanThreshold,
|
||||
)
|
||||
failed = true
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *scanPrintRes {
|
||||
for _, r := range res {
|
||||
logger := log.WithField("secret", name).WithField("meta", chunk.SourceMetadata).WithField("result", string(r.Raw))
|
||||
logger := logger.WithValues("secret", name, "meta", chunk.SourceMetadata, "result", string(r.Raw))
|
||||
if *scanPrintChunkRes {
|
||||
logger = logger.WithField("chunk", string(decoded.Data))
|
||||
logger = logger.WithValues("chunk", string(decoded.Data))
|
||||
}
|
||||
logger.Info("result")
|
||||
}
|
||||
@@ -156,18 +173,20 @@ func main() {
|
||||
}
|
||||
|
||||
for _, repo := range strings.Split(*scanCmdRepo, ",") {
|
||||
sem.Acquire(ctx, 1)
|
||||
if err := sem.Acquire(ctx, 1); err != nil {
|
||||
logFatal(err, "timed out waiting for semaphore")
|
||||
}
|
||||
wgChunkers.Add(1)
|
||||
go func(r string) {
|
||||
defer sem.Release(1)
|
||||
defer wgChunkers.Done()
|
||||
log.Infof("cloning %s", r)
|
||||
logger.Info("cloning repo", "repo", r)
|
||||
path, repo, err := git.CloneRepoUsingUnauthenticated(ctx, r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
logFatal(err, "error cloning repo", "repo", r)
|
||||
}
|
||||
|
||||
log.Infof("cloned %s", r)
|
||||
logger.Info("cloned repo", "repo", r)
|
||||
|
||||
s := git.NewGit(sourcespb.SourceType_SOURCE_TYPE_GIT, 0, 0, "snifftest", false, runtime.NumCPU(),
|
||||
func(file, email, commit, timestamp, repository string, line int64) *source_metadatapb.MetaData {
|
||||
@@ -184,12 +203,12 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
log.Infof("scanning %s", r)
|
||||
logger.Info("scanning repo", "repo", r)
|
||||
err = s.ScanRepo(ctx, repo, path, git.NewScanOptions(), chunksChan)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
logFatal(err, "error scanning repo")
|
||||
}
|
||||
log.Infof("scanned %s", r)
|
||||
logger.Info("scanned repo", "repo", r)
|
||||
defer os.RemoveAll(path)
|
||||
}(repo)
|
||||
}
|
||||
@@ -201,9 +220,9 @@ func main() {
|
||||
|
||||
wgScanners.Wait()
|
||||
|
||||
log.WithField("chunks", chunkCounter).Info("completed")
|
||||
logger.Info("completed snifftest", "chunks", chunkCounter)
|
||||
for scanner, resultsCount := range resCounter {
|
||||
log.WithField("results", *resultsCount).Info(scanner)
|
||||
logger.Info(scanner, "results", *resultsCount)
|
||||
}
|
||||
|
||||
if failed {
|
||||
|
||||
@@ -12,19 +12,21 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/felixge/fgprof"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/jpillora/overseer"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/config"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/decoders"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/engine"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/handlers"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/log"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/output"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/updater"
|
||||
@@ -47,11 +49,11 @@ var (
|
||||
printAvgDetectorTime = cli.Flag("print-avg-detector-time", "Print the average time spent on each detector.").Bool()
|
||||
noUpdate = cli.Flag("no-update", "Don't check for updates.").Bool()
|
||||
fail = cli.Flag("fail", "Exit with code 183 if results are found.").Bool()
|
||||
archiveMaxSize = cli.Flag("archive-max-size", "Maximum size of archive to scan.").Bytes()
|
||||
archiveMaxSize = cli.Flag("archive-max-size", "Maximum size of archive to scan. (Byte units eg. 512B, 2KB, 4MB)").Bytes()
|
||||
archiveMaxDepth = cli.Flag("archive-max-depth", "Maximum depth of archive to scan.").Int()
|
||||
archiveTimeout = cli.Flag("archive-timeout", "Maximum time to spend extracting an archive.").Duration()
|
||||
includeDetectors = cli.Flag("include-detectors", "Comma separated list of detector types to include. Types must exist in detectors.proto").String()
|
||||
excludeDetectors = cli.Flag("exclude-detectors", "Comma separated list of detector types to exclude. Types must exist in detectors.proto").String()
|
||||
includeDetectors = cli.Flag("include-detectors", "Comma separated list of detector types to include. Protobuf name or IDs may be used, as well as ranges.").Default("all").String()
|
||||
excludeDetectors = cli.Flag("exclude-detectors", "Comma separated list of detector types to exclude. Protobuf name or IDs may be used, as well as ranges. IDs defined here take precedence over the include list.").String()
|
||||
|
||||
gitScan = cli.Command("git", "Find credentials in git repositories.")
|
||||
gitScanURI = gitScan.Arg("uri", "Git repository URL. https://, file://, or ssh:// schema expected.").Required().String()
|
||||
@@ -64,15 +66,17 @@ var (
|
||||
_ = gitScan.Flag("entropy", "No-op flag for backwards compat.").Bool()
|
||||
_ = gitScan.Flag("regex", "No-op flag for backwards compat.").Bool()
|
||||
|
||||
githubScan = cli.Command("github", "Find credentials in GitHub repositories.")
|
||||
githubScanEndpoint = githubScan.Flag("endpoint", "GitHub endpoint.").Default("https://api.github.com").String()
|
||||
githubScanRepos = githubScan.Flag("repo", `GitHub repository to scan. You can repeat this flag. Example: "https://github.com/dustin-decker/secretsandstuff"`).Strings()
|
||||
githubScanOrgs = githubScan.Flag("org", `GitHub organization to scan. You can repeat this flag. Example: "trufflesecurity"`).Strings()
|
||||
githubScanToken = githubScan.Flag("token", "GitHub token. Can be provided with environment variable GITHUB_TOKEN.").Envar("GITHUB_TOKEN").String()
|
||||
githubIncludeForks = githubScan.Flag("include-forks", "Include forks in scan.").Bool()
|
||||
githubIncludeMembers = githubScan.Flag("include-members", "Include organization member repositories in scan.").Bool()
|
||||
githubIncludeRepos = githubScan.Flag("include-repos", `Repositories to include in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/trufflehog", "trufflesecurity/t*"`).Strings()
|
||||
githubExcludeRepos = githubScan.Flag("exclude-repos", `Repositories to exclude in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/driftwood", "trufflesecurity/d*"`).Strings()
|
||||
githubScan = cli.Command("github", "Find credentials in GitHub repositories.")
|
||||
githubScanEndpoint = githubScan.Flag("endpoint", "GitHub endpoint.").Default("https://api.github.com").String()
|
||||
githubScanRepos = githubScan.Flag("repo", `GitHub repository to scan. You can repeat this flag. Example: "https://github.com/dustin-decker/secretsandstuff"`).Strings()
|
||||
githubScanOrgs = githubScan.Flag("org", `GitHub organization to scan. You can repeat this flag. Example: "trufflesecurity"`).Strings()
|
||||
githubScanToken = githubScan.Flag("token", "GitHub token. Can be provided with environment variable GITHUB_TOKEN.").Envar("GITHUB_TOKEN").String()
|
||||
githubIncludeForks = githubScan.Flag("include-forks", "Include forks in scan.").Bool()
|
||||
githubIncludeMembers = githubScan.Flag("include-members", "Include organization member repositories in scan.").Bool()
|
||||
githubIncludeRepos = githubScan.Flag("include-repos", `Repositories to include in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/trufflehog", "trufflesecurity/t*"`).Strings()
|
||||
githubExcludeRepos = githubScan.Flag("exclude-repos", `Repositories to exclude in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/driftwood", "trufflesecurity/d*"`).Strings()
|
||||
githubScanIncludePaths = githubScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
||||
githubScanExcludePaths = githubScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
|
||||
|
||||
gitlabScan = cli.Command("gitlab", "Find credentials in GitLab repositories.")
|
||||
// TODO: Add more GitLab options
|
||||
@@ -82,8 +86,10 @@ var (
|
||||
gitlabScanIncludePaths = gitlabScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
||||
gitlabScanExcludePaths = gitlabScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
|
||||
|
||||
filesystemScan = cli.Command("filesystem", "Find credentials in a filesystem.")
|
||||
filesystemDirectories = filesystemScan.Flag("directory", "Path to directory to scan. You can repeat this flag.").Required().Strings()
|
||||
filesystemScan = cli.Command("filesystem", "Find credentials in a filesystem.")
|
||||
filesystemPaths = filesystemScan.Arg("path", "Path to file or directory to scan.").Strings()
|
||||
// DEPRECATED: --directory is deprecated in favor of arguments.
|
||||
filesystemDirectories = filesystemScan.Flag("directory", "Path to directory to scan. You can repeat this flag.").Strings()
|
||||
// TODO: Add more filesystem scan options. Currently only supports scanning a list of directories.
|
||||
// filesystemScanRecursive = filesystemScan.Flag("recursive", "Scan recursively.").Short('r').Bool()
|
||||
filesystemScanIncludePaths = filesystemScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
||||
@@ -118,24 +124,26 @@ func init() {
|
||||
cli.Version("trufflehog " + version.BuildVersion)
|
||||
cmd = kingpin.MustParse(cli.Parse(os.Args[1:]))
|
||||
|
||||
if *jsonOut {
|
||||
logrus.SetFormatter(&logrus.JSONFormatter{})
|
||||
}
|
||||
switch {
|
||||
case *trace:
|
||||
log.SetLevel(5)
|
||||
logrus.SetLevel(logrus.TraceLevel)
|
||||
logrus.Debugf("running version %s", version.BuildVersion)
|
||||
case *debug:
|
||||
log.SetLevel(2)
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
logrus.Debugf("running version %s", version.BuildVersion)
|
||||
default:
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// setup logger
|
||||
logFormat := log.WithConsoleSink
|
||||
if *jsonOut {
|
||||
logFormat = log.WithJSONSink
|
||||
}
|
||||
logger, sync := log.New("trufflehog", logFormat(os.Stderr))
|
||||
// make it the default logger for contexts
|
||||
context.SetDefaultLogger(logger)
|
||||
defer func() { _ = sync() }()
|
||||
logFatal := logFatalFunc(logger)
|
||||
|
||||
updateCfg := overseer.Config{
|
||||
Program: run,
|
||||
Debug: *debug,
|
||||
@@ -153,14 +161,16 @@ func main() {
|
||||
|
||||
err := overseer.RunErr(updateCfg)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("error occured with trufflehog updater 🐷")
|
||||
logFatal(err, "error occured with trufflehog updater 🐷")
|
||||
}
|
||||
}
|
||||
|
||||
func run(state overseer.State) {
|
||||
if *debug {
|
||||
logrus.Debugf("trufflehog %s", version.BuildVersion)
|
||||
}
|
||||
ctx := context.Background()
|
||||
logger := ctx.Logger()
|
||||
logFatal := logFatalFunc(logger)
|
||||
|
||||
logger.V(2).Info(fmt.Sprintf("trufflehog %s", version.BuildVersion))
|
||||
|
||||
if *githubScanToken != "" {
|
||||
// NOTE: this kludge is here to do an authenticated shallow commit
|
||||
@@ -178,27 +188,19 @@ func run(state overseer.State) {
|
||||
router := mux.NewRouter()
|
||||
router.PathPrefix("/debug/pprof").Handler(http.DefaultServeMux)
|
||||
router.PathPrefix("/debug/fgprof").Handler(fgprof.Handler())
|
||||
logrus.Info("starting pprof and fgprof server on :18066 /debug/pprof and /debug/fgprof")
|
||||
logger.Info("starting pprof and fgprof server on :18066 /debug/pprof and /debug/fgprof")
|
||||
if err := http.ListenAndServe(":18066", router); err != nil {
|
||||
logrus.Error(err)
|
||||
logger.Error(err, "error serving pprof and fgprof")
|
||||
}
|
||||
}()
|
||||
}
|
||||
logFormat := log.WithConsoleSink
|
||||
if *jsonOut {
|
||||
logFormat = log.WithJSONSink
|
||||
}
|
||||
logger, sync := log.New("trufflehog", logFormat(os.Stderr))
|
||||
context.SetDefaultLogger(logger)
|
||||
defer func() { _ = sync() }()
|
||||
|
||||
conf := &config.Config{}
|
||||
if *configFilename != "" {
|
||||
var err error
|
||||
conf, err = config.Read(*configFilename)
|
||||
if err != nil {
|
||||
logger.Error(err, "error parsing the provided configuration file")
|
||||
os.Exit(1)
|
||||
logFatal(err, "error parsing the provided configuration file")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,32 +214,41 @@ func run(state overseer.State) {
|
||||
handlers.SetArchiveMaxTimeout(*archiveTimeout)
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
var detectorsOption engine.EngineOption
|
||||
|
||||
detectorCfg, err := engine.NewDetectorsConfig(*includeDetectors, *excludeDetectors)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to create detectors config")
|
||||
os.Exit(1)
|
||||
// Build include and exclude detector filter sets.
|
||||
var includeDetectorTypes, excludeDetectorTypes map[detectorspb.DetectorType]struct{}
|
||||
{
|
||||
includeList, err := config.ParseDetectors(*includeDetectors)
|
||||
if err != nil {
|
||||
// Exit if there was an error to inform the user of the misconfiguration.
|
||||
logger.Error(err, "invalid include list detector configuration")
|
||||
os.Exit(1)
|
||||
}
|
||||
excludeList, err := config.ParseDetectors(*excludeDetectors)
|
||||
if err != nil {
|
||||
// Exit if there was an error to inform the user of the misconfiguration.
|
||||
logger.Error(err, "invalid exclude list detector configuration")
|
||||
os.Exit(1)
|
||||
}
|
||||
includeDetectorTypes = detectorTypeToSet(includeList)
|
||||
excludeDetectorTypes = detectorTypeToSet(excludeList)
|
||||
}
|
||||
dts, err := engine.Detectors(ctx, detectorCfg)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to create detectors")
|
||||
os.Exit(1)
|
||||
includeFilter := func(d detectors.Detector) bool {
|
||||
_, ok := includeDetectorTypes[d.Type()]
|
||||
return ok
|
||||
}
|
||||
|
||||
if len(dts) > 0 {
|
||||
detectorsOption = engine.WithDetectors(!*noVerification, dts...)
|
||||
} else {
|
||||
detectorsOption = engine.WithDetectors(!*noVerification, engine.DefaultDetectors()...)
|
||||
excludeFilter := func(d detectors.Detector) bool {
|
||||
_, ok := excludeDetectorTypes[d.Type()]
|
||||
return !ok
|
||||
}
|
||||
|
||||
e := engine.Start(ctx,
|
||||
engine.WithConcurrency(*concurrency),
|
||||
engine.WithDecoders(decoders.DefaultDecoders()...),
|
||||
engine.WithDetectors(!*noVerification, engine.DefaultDetectors()...),
|
||||
engine.WithDetectors(!*noVerification, conf.Detectors...),
|
||||
engine.WithFilterDetectors(includeFilter),
|
||||
engine.WithFilterDetectors(excludeFilter),
|
||||
engine.WithFilterUnverified(*filterUnverified),
|
||||
detectorsOption,
|
||||
)
|
||||
|
||||
var repoPath string
|
||||
@@ -246,11 +257,11 @@ func run(state overseer.State) {
|
||||
case gitScan.FullCommand():
|
||||
filter, err := common.FilterFromFiles(*gitScanIncludePaths, *gitScanExcludePaths)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("could not create filter")
|
||||
logFatal(err, "could not create filter")
|
||||
}
|
||||
repoPath, remote, err = git.PrepareRepoSinceCommit(ctx, *gitScanURI, *gitScanSinceCommit)
|
||||
if err != nil || repoPath == "" {
|
||||
logrus.WithError(err).Fatal("error preparing git repo for scanning")
|
||||
logFatal(err, "error preparing git repo for scanning")
|
||||
}
|
||||
if remote {
|
||||
defer os.RemoveAll(repoPath)
|
||||
@@ -264,11 +275,15 @@ func run(state overseer.State) {
|
||||
Filter: filter,
|
||||
}
|
||||
if err = e.ScanGit(ctx, cfg); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to scan Git.")
|
||||
logFatal(err, "Failed to scan Git.")
|
||||
}
|
||||
case githubScan.FullCommand():
|
||||
filter, err := common.FilterFromFiles(*githubScanIncludePaths, *githubScanExcludePaths)
|
||||
if err != nil {
|
||||
logFatal(err, "could not create filter")
|
||||
}
|
||||
if len(*githubScanOrgs) == 0 && len(*githubScanRepos) == 0 {
|
||||
logrus.Fatal("You must specify at least one organization or repository.")
|
||||
logFatal(fmt.Errorf("invalid config"), "You must specify at least one organization or repository.")
|
||||
}
|
||||
|
||||
cfg := sources.GithubConfig{
|
||||
@@ -281,14 +296,15 @@ func run(state overseer.State) {
|
||||
IncludeRepos: *githubIncludeRepos,
|
||||
Repos: *githubScanRepos,
|
||||
Orgs: *githubScanOrgs,
|
||||
Filter: filter,
|
||||
}
|
||||
if err := e.ScanGitHub(ctx, cfg); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to scan Github.")
|
||||
logFatal(err, "Failed to scan Github.")
|
||||
}
|
||||
case gitlabScan.FullCommand():
|
||||
filter, err := common.FilterFromFiles(*gitlabScanIncludePaths, *gitlabScanExcludePaths)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("could not create filter")
|
||||
logFatal(err, "could not create filter")
|
||||
}
|
||||
|
||||
cfg := sources.GitlabConfig{
|
||||
@@ -298,20 +314,25 @@ func run(state overseer.State) {
|
||||
Filter: filter,
|
||||
}
|
||||
if err := e.ScanGitLab(ctx, cfg); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to scan GitLab.")
|
||||
logFatal(err, "Failed to scan GitLab.")
|
||||
}
|
||||
case filesystemScan.FullCommand():
|
||||
filter, err := common.FilterFromFiles(*filesystemScanIncludePaths, *filesystemScanExcludePaths)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("could not create filter")
|
||||
logFatal(err, "could not create filter")
|
||||
}
|
||||
|
||||
if len(*filesystemDirectories) > 0 {
|
||||
ctx.Logger().Info("--directory flag is deprecated, please pass directories as arguments")
|
||||
}
|
||||
paths := make([]string, 0, len(*filesystemPaths)+len(*filesystemDirectories))
|
||||
paths = append(paths, *filesystemPaths...)
|
||||
paths = append(paths, *filesystemDirectories...)
|
||||
cfg := sources.FilesystemConfig{
|
||||
Directories: *filesystemDirectories,
|
||||
Filter: filter,
|
||||
Paths: paths,
|
||||
Filter: filter,
|
||||
}
|
||||
if err = e.ScanFileSystem(ctx, cfg); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to scan filesystem")
|
||||
logFatal(err, "Failed to scan filesystem")
|
||||
}
|
||||
case s3Scan.FullCommand():
|
||||
cfg := sources.S3Config{
|
||||
@@ -321,7 +342,7 @@ func run(state overseer.State) {
|
||||
CloudCred: *s3ScanCloudEnv,
|
||||
}
|
||||
if err := e.ScanS3(ctx, cfg); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to scan S3.")
|
||||
logFatal(err, "Failed to scan S3.")
|
||||
}
|
||||
case syslogScan.FullCommand():
|
||||
cfg := sources.SyslogConfig{
|
||||
@@ -333,11 +354,11 @@ func run(state overseer.State) {
|
||||
Concurrency: *concurrency,
|
||||
}
|
||||
if err := e.ScanSyslog(ctx, cfg); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to scan syslog.")
|
||||
logFatal(err, "Failed to scan syslog.")
|
||||
}
|
||||
case circleCiScan.FullCommand():
|
||||
if err := e.ScanCircleCI(ctx, *circleCiScanToken); err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to scan CircleCI.")
|
||||
logFatal(err, "Failed to scan CircleCI.")
|
||||
}
|
||||
}
|
||||
// asynchronously wait for scanning to finish and cleanup
|
||||
@@ -356,24 +377,30 @@ func run(state overseer.State) {
|
||||
}
|
||||
foundResults = true
|
||||
|
||||
var err error
|
||||
switch {
|
||||
case *jsonLegacy:
|
||||
output.PrintLegacyJSON(ctx, &r)
|
||||
err = output.PrintLegacyJSON(ctx, &r)
|
||||
case *jsonOut:
|
||||
output.PrintJSON(&r)
|
||||
err = output.PrintJSON(&r)
|
||||
default:
|
||||
output.PrintPlainOutput(&r)
|
||||
err = output.PrintPlainOutput(&r)
|
||||
}
|
||||
if err != nil {
|
||||
logFatal(err, "error printing results")
|
||||
}
|
||||
}
|
||||
logrus.Debugf("scanned %d chunks", e.ChunksScanned())
|
||||
logrus.Debugf("scanned %d bytes", e.BytesScanned())
|
||||
logger.V(2).Info("finished scanning",
|
||||
"chunks", e.ChunksScanned(),
|
||||
"bytes", e.BytesScanned(),
|
||||
)
|
||||
|
||||
if *printAvgDetectorTime {
|
||||
printAverageDetectorTime(e)
|
||||
}
|
||||
|
||||
if foundResults && *fail {
|
||||
logrus.Debug("exiting with code 183 because results were found")
|
||||
logger.V(2).Info("exiting with code 183 because results were found")
|
||||
os.Exit(183)
|
||||
}
|
||||
}
|
||||
@@ -389,3 +416,24 @@ func printAverageDetectorTime(e *engine.Engine) {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s\n", detectorName, avgDuration)
|
||||
}
|
||||
}
|
||||
|
||||
// logFatalFunc returns a log.Fatal style function. Calling the returned
|
||||
// function will terminate the program without cleanup.
|
||||
func logFatalFunc(logger logr.Logger) func(error, string, ...any) {
|
||||
return func(err error, message string, keyAndVals ...any) {
|
||||
logger.Error(err, message, keyAndVals...)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
func detectorTypeToSet(detectors []detectorspb.DetectorType) map[detectorspb.DetectorType]struct{} {
|
||||
output := make(map[detectorspb.DetectorType]struct{}, len(detectors))
|
||||
for _, d := range detectors {
|
||||
output[d] = struct{}{}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
)
|
||||
|
||||
type Filter struct {
|
||||
@@ -20,7 +20,8 @@ type FilterRuleSet []regexp.Regexp
|
||||
func FilterEmpty() *Filter {
|
||||
filter, err := FilterFromFiles("", "")
|
||||
if err != nil {
|
||||
log.WithError(err).Fatalf("could not create empty filter")
|
||||
context.Background().Logger().Error(err, "could not create empty filter")
|
||||
os.Exit(1)
|
||||
}
|
||||
return filter
|
||||
}
|
||||
@@ -60,13 +61,16 @@ func FilterRulesFromFile(source string) (*FilterRuleSet, error) {
|
||||
emptyLinePattern := regexp.MustCompile(`^\s*$`)
|
||||
|
||||
file, err := os.Open(source)
|
||||
logger := context.Background().Logger().WithValues("file", source)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatalf("unable to open filter file: %s", source)
|
||||
logger.Error(err, "unable to open filter file", "file", source)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
log.WithError(err).Fatalf("unable to close filter file: %s", source)
|
||||
logger.Error(err, "unable to close filter file")
|
||||
os.Exit(1)
|
||||
}
|
||||
}(file)
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const EmailPattern = `\b(?:[a-z0-9!#$%&'*+/=?^_\x60{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_\x60{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])\b`
|
||||
@@ -24,7 +22,7 @@ func BuildRegex(pattern string, specialChar string, length int) string {
|
||||
|
||||
func BuildRegexJWT(firstRange, secondRange, thirdRange string) string {
|
||||
if RangeValidation(firstRange) || RangeValidation(secondRange) || RangeValidation(thirdRange) {
|
||||
log.Error("Min value should not be greater than or equal to max")
|
||||
panic("Min value should not be greater than or equal to max")
|
||||
}
|
||||
return fmt.Sprintf(`\b(ey[%s]{%s}.ey[%s-\/_]{%s}.[%s-\/_]{%s})\b`, AlphaNumPattern, firstRange, AlphaNumPattern, secondRange, AlphaNumPattern, thirdRange)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"time"
|
||||
|
||||
secretmanager "cloud.google.com/go/secretmanager/apiv1"
|
||||
"cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/pkg/errors"
|
||||
secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
|
||||
)
|
||||
|
||||
type Secret struct{ kv map[string]string }
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
dpb "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var (
|
||||
specialGroups = map[string][]dpb.DetectorType{
|
||||
"all": allDetectors(),
|
||||
}
|
||||
|
||||
detectorTypeValue = make(map[string]dpb.DetectorType, len(dpb.DetectorType_value))
|
||||
validDetectors = make(map[dpb.DetectorType]struct{}, len(dpb.DetectorType_value))
|
||||
maxDetectorType dpb.DetectorType
|
||||
)
|
||||
|
||||
// Setup package local global variables.
|
||||
func init() {
|
||||
for k, v := range dpb.DetectorType_value {
|
||||
dt := dpb.DetectorType(v)
|
||||
detectorTypeValue[strings.ToLower(k)] = dt
|
||||
validDetectors[dt] = struct{}{}
|
||||
if dt > maxDetectorType {
|
||||
maxDetectorType = dt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ParseDetectors parses user supplied string into a list of detectors types.
|
||||
// "all" will return the list of all available detectors. The input is comma
|
||||
// separated and may use the case-insensitive detector name defined in the
|
||||
// protobuf, or the protobuf enum number. A range may be used as well in the
|
||||
// form "start-end". Order is preserved and duplicates are ignored.
|
||||
func ParseDetectors(input string) ([]dpb.DetectorType, error) {
|
||||
var output []dpb.DetectorType
|
||||
seenDetector := map[dpb.DetectorType]struct{}{}
|
||||
for _, item := range strings.Split(input, ",") {
|
||||
item = strings.TrimSpace(item)
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
detectors, ok := specialGroups[strings.ToLower(item)]
|
||||
if !ok {
|
||||
var err error
|
||||
detectors, err = asRange(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, d := range detectors {
|
||||
if _, ok := seenDetector[d]; ok {
|
||||
continue
|
||||
}
|
||||
seenDetector[d] = struct{}{}
|
||||
output = append(output, d)
|
||||
}
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// allDetectors reutrns an ordered slice of all detector types.
|
||||
func allDetectors() []dpb.DetectorType {
|
||||
all := make([]dpb.DetectorType, 0, len(dpb.DetectorType_name))
|
||||
for id := range dpb.DetectorType_name {
|
||||
all = append(all, dpb.DetectorType(id))
|
||||
}
|
||||
slices.Sort(all)
|
||||
return all
|
||||
}
|
||||
|
||||
// asRange converts a single input into a slice of detector types. If the input
|
||||
// is not in range format, a slice of length 1 is returned. Unbounded ranges
|
||||
// are allowed.
|
||||
func asRange(input string) ([]dpb.DetectorType, error) {
|
||||
// Check if it's a single detector type.
|
||||
dt, err := asDetectorType(input)
|
||||
if err == nil {
|
||||
return []dpb.DetectorType{dt}, nil
|
||||
}
|
||||
|
||||
// Check if it's a range; if not return the error from above.
|
||||
start, end, found := strings.Cut(input, "-")
|
||||
if !found {
|
||||
return nil, err
|
||||
}
|
||||
start, end = strings.TrimSpace(start), strings.TrimSpace(end)
|
||||
|
||||
// Convert the range start and end to a DetectorType.
|
||||
dtStart, err := asDetectorType(start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dtEnd, err := asDetectorType(end)
|
||||
// If end is empty it's an unbounded range.
|
||||
if err != nil && end != "" {
|
||||
return nil, err
|
||||
}
|
||||
if end == "" {
|
||||
dtEnd = maxDetectorType
|
||||
}
|
||||
|
||||
step := dpb.DetectorType(1)
|
||||
if dtStart > dtEnd {
|
||||
step = -1
|
||||
}
|
||||
var output []dpb.DetectorType
|
||||
for dt := dtStart; dt != dtEnd; dt += step {
|
||||
if _, ok := validDetectors[dt]; !ok {
|
||||
continue
|
||||
}
|
||||
output = append(output, dt)
|
||||
}
|
||||
return append(output, dtEnd), nil
|
||||
}
|
||||
|
||||
// asDetectorType converts the case-insensitive input into a detector type.
|
||||
// Name or ID may be used.
|
||||
func asDetectorType(input string) (dpb.DetectorType, error) {
|
||||
if input == "" {
|
||||
return 0, fmt.Errorf("empty detector")
|
||||
}
|
||||
// Check if it's a named detector.
|
||||
if dt, ok := detectorTypeValue[strings.ToLower(input)]; ok {
|
||||
return dt, nil
|
||||
}
|
||||
// Check if it's a detector ID.
|
||||
if i, err := strconv.ParseInt(input, 10, 32); err == nil {
|
||||
dt := dpb.DetectorType(i)
|
||||
if _, ok := validDetectors[dt]; !ok {
|
||||
return 0, fmt.Errorf("invalid detector ID: %s", input)
|
||||
}
|
||||
return dt, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unrecognized detector type: %s", input)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
dpb "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||
)
|
||||
|
||||
func TestDetectorParsing(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
input string
|
||||
expected []dpb.DetectorType
|
||||
}{
|
||||
"all": {"AlL", allDetectors()},
|
||||
"trailing range": {"0-", allDetectors()},
|
||||
"all after 1": {"1-", allDetectors()[1:]},
|
||||
"named and valid range": {"aWs,8-9", []dpb.DetectorType{dpb.DetectorType_AWS, dpb.DetectorType_Github, dpb.DetectorType_Gitlab}},
|
||||
"duplicate order preserved": {"9, 8, 9", []dpb.DetectorType{9, 8}},
|
||||
"named range": {"github - gitlab", []dpb.DetectorType{dpb.DetectorType_Github, dpb.DetectorType_Gitlab}},
|
||||
"range preserved": {"8-9, 7-10", []dpb.DetectorType{8, 9, 7, 10}},
|
||||
"reverse range": {"9-8", []dpb.DetectorType{9, 8}},
|
||||
"range preserved with all": {"10-,all", append(allDetectors()[10:], allDetectors()[:10]...)},
|
||||
"empty list item": {"8, ,9", []dpb.DetectorType{8, 9}},
|
||||
"invalid end range": {"0-1337", nil},
|
||||
"invalid name": {"foo", nil},
|
||||
"negative": {"-1", nil},
|
||||
}
|
||||
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotErr := ParseDetectors(tt.input)
|
||||
if tt.expected == nil {
|
||||
assert.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ var (
|
||||
|
||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"browserstack", "key", "automate", "local"}) + `\b([0-9a-zA-Z]{20})\b`)
|
||||
userPat = regexp.MustCompile(detectors.PrefixRegex([]string{"browserstack", "user", "automate", "local"}) + `\b(^[a-zA-Z\d]+([._-]?[a-zA-Z\d]+)*[a-zA-Z\d]+$)\b`)
|
||||
userPat = regexp.MustCompile(detectors.PrefixRegex([]string{"browserstack", "user", "automate", "local"}) + `\b([a-zA-Z\d]{3,18}[._-]?[a-zA-Z\d]{6})\b`)
|
||||
)
|
||||
|
||||
// Keywords are used for efficiently pre-filtering chunks.
|
||||
|
||||
@@ -51,6 +51,7 @@ func TestBrowserStack_FromChunk(t *testing.T) {
|
||||
{
|
||||
DetectorType: detectorspb.DetectorType_BrowserStack,
|
||||
Verified: true,
|
||||
RawV2: []byte(fmt.Sprintf("%s%s", secret, secretUser)),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
@@ -67,6 +68,7 @@ func TestBrowserStack_FromChunk(t *testing.T) {
|
||||
{
|
||||
DetectorType: detectorspb.DetectorType_BrowserStack,
|
||||
Verified: false,
|
||||
RawV2: []byte(fmt.Sprintf("%s%s", inactiveSecret, secretUser)),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
|
||||
@@ -44,8 +44,6 @@ func New() Scanner {
|
||||
}
|
||||
|
||||
type Scanner struct {
|
||||
wordList []string
|
||||
badList []string
|
||||
programmingBookWords []string
|
||||
excludeMatchers []*regexp.Regexp
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package moonclerck
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"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 (
|
||||
client = common.SaneHttpClient()
|
||||
|
||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"moonclerck"}) + `\b([0-9a-z]{32})\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{"moonclerck"}
|
||||
}
|
||||
|
||||
// FromData will find and optionally verify Moonclerck 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)
|
||||
|
||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
||||
|
||||
for _, match := range matches {
|
||||
if len(match) != 2 {
|
||||
continue
|
||||
}
|
||||
resMatch := strings.TrimSpace(match[1])
|
||||
|
||||
s1 := detectors.Result{
|
||||
DetectorType: detectorspb.DetectorType_Moonclerk,
|
||||
Raw: []byte(resMatch),
|
||||
}
|
||||
|
||||
if verify {
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.moonclerk.com/forms", nil)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
req.Header.Add("Accept", "application/vnd.moonclerk+json;version=1")
|
||||
req.Header.Add("Authorization", "Token token="+resMatch)
|
||||
res, err := client.Do(req)
|
||||
if err == nil {
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||
s1.Verified = true
|
||||
} else {
|
||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results = append(results, s1)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (s Scanner) Type() detectorspb.DetectorType {
|
||||
return detectorspb.DetectorType_Moonclerk
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
//go:build detectors
|
||||
// +build detectors
|
||||
|
||||
package moonclerck
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||
)
|
||||
|
||||
func TestMoonclerck_FromChunk(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
||||
if err != nil {
|
||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
||||
}
|
||||
secret := testSecrets.MustGetField("MOONCLERCK")
|
||||
inactiveSecret := testSecrets.MustGetField("MOONCLERCK_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 moonclerck secret %s within", secret)),
|
||||
verify: true,
|
||||
},
|
||||
want: []detectors.Result{
|
||||
{
|
||||
DetectorType: detectorspb.DetectorType_Moonclerk,
|
||||
Verified: true,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "found, unverified",
|
||||
s: Scanner{},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
data: []byte(fmt.Sprintf("You can find a moonclerck secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
||||
verify: true,
|
||||
},
|
||||
want: []detectors.Result{
|
||||
{
|
||||
DetectorType: detectorspb.DetectorType_Moonclerk,
|
||||
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("Moonclerck.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("Moonclerck.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++ {
|
||||
s.FromData(ctx, false, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||
@@ -66,8 +65,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) ([]dete
|
||||
if data != nil {
|
||||
secret.Verified = true
|
||||
}
|
||||
} else {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,6 @@ var (
|
||||
client = common.SaneHttpClient()
|
||||
)
|
||||
|
||||
type proxyRes struct {
|
||||
Verified bool `json:"verified"`
|
||||
}
|
||||
|
||||
// Keywords are used for efficiently pre-filtering chunks.
|
||||
// Use identifiers in the secret preferably, or the provider name.
|
||||
func (s Scanner) Keywords() []string {
|
||||
|
||||
@@ -405,7 +405,6 @@ import (
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/monday"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/mongodb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/monkeylearn"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/moonclerck"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/moonclerk"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/moosend"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/mrticktock"
|
||||
@@ -747,9 +746,7 @@ func DefaultDetectors() []detectors.Detector {
|
||||
&mailchimp.Scanner{},
|
||||
&okta.Scanner{},
|
||||
&onelogin.Scanner{},
|
||||
&heroku.Scanner{},
|
||||
&dropbox.Scanner{},
|
||||
&linearapi.Scanner{},
|
||||
&stripe.Scanner{},
|
||||
&square.Scanner{},
|
||||
&squareapp.Scanner{},
|
||||
@@ -1273,7 +1270,6 @@ func DefaultDetectors() []detectors.Detector {
|
||||
teamworkdesk.Scanner{},
|
||||
tallyfy.Scanner{},
|
||||
apimatic.Scanner{},
|
||||
moonclerck.Scanner{},
|
||||
boostnote.Scanner{},
|
||||
freshbooks.Scanner{},
|
||||
cashboard.Scanner{},
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
)
|
||||
|
||||
// DetectorFilter allows for include/exclude detectors.
|
||||
type DetectorFilter interface {
|
||||
detectors() []string
|
||||
filter(map[string]struct{}) ([]detectors.Detector, error)
|
||||
}
|
||||
|
||||
// IncludeDetectorFilter is a detector filter that only includes the specified detectors.
|
||||
type IncludeDetectorFilter struct {
|
||||
includeDetectors []string
|
||||
}
|
||||
|
||||
func (i *IncludeDetectorFilter) detectors() []string {
|
||||
return i.includeDetectors
|
||||
}
|
||||
|
||||
func (i *IncludeDetectorFilter) filter(include map[string]struct{}) ([]detectors.Detector, error) {
|
||||
ds := make([]detectors.Detector, 0, len(i.includeDetectors))
|
||||
for _, d := range DefaultDetectors() {
|
||||
if _, ok := include[strings.ToLower(d.Type().String())]; ok {
|
||||
ds = append(ds, d)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ds) != len(include) {
|
||||
return nil, fmt.Errorf("1 or more detectors are invalid, please check your detector types")
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
// ExcludeDetectorFilter is a detector filter that excludes the specified detectors.
|
||||
type ExcludeDetectorFilter struct {
|
||||
excludeDetectors []string
|
||||
}
|
||||
|
||||
func (e *ExcludeDetectorFilter) detectors() []string {
|
||||
return e.excludeDetectors
|
||||
}
|
||||
|
||||
func (e *ExcludeDetectorFilter) filter(exclude map[string]struct{}) ([]detectors.Detector, error) {
|
||||
defaultDetectors := DefaultDetectors()
|
||||
l := len(defaultDetectors) - len(exclude)
|
||||
result := make([]detectors.Detector, 0, l)
|
||||
for _, detector := range defaultDetectors {
|
||||
if _, ok := exclude[strings.ToLower(detector.Type().String())]; !ok {
|
||||
result = append(result, detector)
|
||||
}
|
||||
}
|
||||
|
||||
if len(result) != l {
|
||||
return nil, fmt.Errorf("1 or more detectors are invalid, please check your detector types")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// NewDetectorsConfig creates a new detector filter based on the include/exclude arguments.
|
||||
func NewDetectorsConfig(include, exclude string) (DetectorFilter, error) {
|
||||
if len(include) == 0 && len(exclude) == 0 {
|
||||
return nil, fmt.Errorf("no detectors specified")
|
||||
}
|
||||
|
||||
if len(include) > 0 && len(exclude) > 0 {
|
||||
return nil, fmt.Errorf("cannot specify both include and exclude detectors")
|
||||
}
|
||||
|
||||
// Determine the detector filter type.
|
||||
if len(include) > len(exclude) {
|
||||
return &IncludeDetectorFilter{includeDetectors: strings.Split(include, ",")}, nil
|
||||
}
|
||||
return &ExcludeDetectorFilter{excludeDetectors: strings.Split(exclude, ",")}, nil
|
||||
}
|
||||
|
||||
// Detectors only returns a specific set of detectors if they are specified in the
|
||||
// detector list and are valid. Otherwise, an error is returned.
|
||||
func Detectors(ctx context.Context, dt DetectorFilter) ([]detectors.Detector, error) {
|
||||
configured := setDetectors(ctx, dt.detectors())
|
||||
|
||||
if len(configured) == 0 {
|
||||
return nil, fmt.Errorf("no detectors specified")
|
||||
}
|
||||
|
||||
return dt.filter(configured)
|
||||
}
|
||||
|
||||
func setDetectors(ctx context.Context, dts []string) map[string]struct{} {
|
||||
valid := make(map[string]struct{}, len(dts))
|
||||
for _, d := range dts {
|
||||
ctx.Logger().Info("setting detector", "detector-name", d)
|
||||
valid[strings.ToLower(d)] = struct{}{}
|
||||
}
|
||||
|
||||
return valid
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/aws"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/azure"
|
||||
)
|
||||
|
||||
func TestNewDectorsConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inc string
|
||||
exc string
|
||||
expected DetectorFilter
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "No dts specified, returns error",
|
||||
inc: "",
|
||||
exc: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Include dts specified, returns config with include",
|
||||
inc: "AWS",
|
||||
expected: &IncludeDetectorFilter{includeDetectors: []string{"AWS"}},
|
||||
},
|
||||
{
|
||||
name: "Exclude dts specified, returns config with exclude",
|
||||
exc: "AWS",
|
||||
expected: &ExcludeDetectorFilter{excludeDetectors: []string{"AWS"}},
|
||||
},
|
||||
{
|
||||
name: "Include and exclude dts specified, returns error",
|
||||
inc: "AWS",
|
||||
exc: "Azure",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
result, err := NewDetectorsConfig(test.inc, test.exc)
|
||||
if err != nil && !test.wantErr {
|
||||
t.Errorf("NewDetectorsConfig(%v, %v) got %v, want %v", test.inc, test.exc, err, test.expected)
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
if !reflect.DeepEqual(result, test.expected) {
|
||||
t.Errorf("NewDetectorsConfig(%v, %v) got %v, want %v", test.inc, test.exc, result, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectors(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
tests := []struct {
|
||||
name string
|
||||
dt DetectorFilter
|
||||
expected []detectors.Detector
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "No dts specified, returns default set",
|
||||
dt: &IncludeDetectorFilter{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Valid include detectors (1) specified, returns valid set",
|
||||
dt: &IncludeDetectorFilter{includeDetectors: []string{"AWS"}},
|
||||
expected: []detectors.Detector{aws.New()},
|
||||
},
|
||||
{
|
||||
name: "Valid include detectors (2) specified, returns valid set",
|
||||
dt: &IncludeDetectorFilter{includeDetectors: []string{"AWS", "Azure"}},
|
||||
expected: []detectors.Detector{aws.New(), &azure.Scanner{}},
|
||||
},
|
||||
{
|
||||
name: "Invalid include detectors specified, returns error",
|
||||
dt: &IncludeDetectorFilter{includeDetectors: []string{"AWS", "Azure", "Invalid"}},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Valid exlude detectors (1) specified, returns valid set",
|
||||
dt: &ExcludeDetectorFilter{excludeDetectors: []string{"AWS"}},
|
||||
expected: excludeDetectors(map[string]struct{}{"aws": {}}),
|
||||
},
|
||||
{
|
||||
name: "Valid exclude detectors (2) specified, returns valid set",
|
||||
dt: &ExcludeDetectorFilter{excludeDetectors: []string{"AWS", "Azure"}},
|
||||
expected: excludeDetectors(map[string]struct{}{"aws": {}, "azure": {}}),
|
||||
},
|
||||
{
|
||||
name: "Invalid exclude detector specified, returns error",
|
||||
dt: &ExcludeDetectorFilter{excludeDetectors: []string{"AWS", "Azure", "Invalid"}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
result, err := Detectors(ctx, test.dt)
|
||||
if err != nil && !test.wantErr {
|
||||
t.Errorf("Detectors(%v) got %v, want %v", test.dt, err, test.expected)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(result, test.expected) {
|
||||
t.Errorf("Detectors(%v) got %v, want %v", test.dt, result, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func excludeDetectors(exclude map[string]struct{}) []detectors.Detector {
|
||||
defaultDetectors := DefaultDetectors()
|
||||
result := make([]detectors.Detector, 0, len(defaultDetectors)-len(exclude))
|
||||
for _, detector := range defaultDetectors {
|
||||
if _, ok := exclude[strings.ToLower(detector.Type().String())]; !ok {
|
||||
result = append(result, detector)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -73,6 +73,31 @@ func WithFilterUnverified(filter bool) EngineOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithFilterDetectors applies a filter to the configured list of detectors. If
|
||||
// the filterFunc returns true, the detector will be included for scanning.
|
||||
// This option applies to the existing list of detectors configured, so the
|
||||
// order this option appears matters. All filtering happens before scanning.
|
||||
func WithFilterDetectors(filterFunc func(detectors.Detector) bool) EngineOption {
|
||||
return func(e *Engine) {
|
||||
// If no detectors are configured, do nothing.
|
||||
if e.detectors == nil {
|
||||
return
|
||||
}
|
||||
e.detectors[true] = filterDetectors(filterFunc, e.detectors[true])
|
||||
e.detectors[false] = filterDetectors(filterFunc, e.detectors[false])
|
||||
}
|
||||
}
|
||||
|
||||
func filterDetectors(filterFunc func(detectors.Detector) bool, input []detectors.Detector) []detectors.Detector {
|
||||
var output []detectors.Detector
|
||||
for _, detector := range input {
|
||||
if filterFunc(detector) {
|
||||
output = append(output, detector)
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, options ...EngineOption) *Engine {
|
||||
e := &Engine{
|
||||
chunks: make(chan *sources.Chunk),
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
// ScanFileSystem scans a given file system.
|
||||
func (e *Engine) ScanFileSystem(ctx context.Context, c sources.FilesystemConfig) error {
|
||||
connection := &sourcespb.Filesystem{
|
||||
Directories: c.Directories,
|
||||
Paths: c.Paths,
|
||||
}
|
||||
var conn anypb.Any
|
||||
err := anypb.MarshalFrom(&conn, connection, proto.MarshalOptions{})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
gogit "github.com/go-git/go-git/v5"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
|
||||
@@ -8,6 +9,7 @@ import (
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/github"
|
||||
)
|
||||
|
||||
@@ -37,6 +39,7 @@ func (e *Engine) ScanGitHub(ctx context.Context, c sources.GithubConfig) error {
|
||||
ctx.Logger().Error(err, "failed to marshal github connection")
|
||||
return err
|
||||
}
|
||||
|
||||
ctx = context.WithValues(ctx,
|
||||
"source_type", source.Type().String(),
|
||||
"source_name", "github",
|
||||
@@ -47,6 +50,14 @@ func (e *Engine) ScanGitHub(ctx context.Context, c sources.GithubConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
logOptions := &gogit.LogOptions{}
|
||||
opts := []git.ScanOption{
|
||||
git.ScanOptionFilter(c.Filter),
|
||||
git.ScanOptionLogOptions(logOptions),
|
||||
}
|
||||
scanOptions := git.NewScanOptions(opts...)
|
||||
source.WithScanOptions(scanOptions)
|
||||
|
||||
e.sourcesWg.Add(1)
|
||||
go func() {
|
||||
defer common.RecoverWithExit(ctx)
|
||||
|
||||
+16
-12
@@ -11,8 +11,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
)
|
||||
@@ -174,14 +172,14 @@ func (c *Parser) executeCommand(ctx context.Context, cmd *exec.Cmd) (chan Commit
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stdErr)
|
||||
for scanner.Scan() {
|
||||
log.Debug(scanner.Text())
|
||||
ctx.Logger().V(2).Info(scanner.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
c.fromReader(ctx, stdOut, commitChan)
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.WithError(err).Debugf("Error waiting for git command to complete.")
|
||||
ctx.Logger().V(2).Info("Error waiting for git command to complete.", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -227,7 +225,7 @@ func (c *Parser) fromReader(ctx context.Context, stdOut io.Reader, commitChan ch
|
||||
case isDateLine(line):
|
||||
date, err := time.Parse(c.dateFormat, strings.TrimSpace(string(line[6:])))
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not parse date from git stream.")
|
||||
ctx.Logger().V(2).Info("Could not parse date from git stream.", "error", err)
|
||||
}
|
||||
currentCommit.Date = date
|
||||
case isDiffLine(line):
|
||||
@@ -243,14 +241,17 @@ func (c *Parser) fromReader(ctx context.Context, stdOut io.Reader, commitChan ch
|
||||
totalSize += diff.Content.Len()
|
||||
}
|
||||
if totalSize > c.maxCommitSize {
|
||||
oldCommit := currentCommit
|
||||
commitChan <- *currentCommit
|
||||
currentCommit = &Commit{
|
||||
Hash: currentCommit.Hash,
|
||||
Author: currentCommit.Author,
|
||||
Date: currentCommit.Date,
|
||||
Message: currentCommit.Message,
|
||||
Message: strings.Builder{},
|
||||
Diffs: []Diff{},
|
||||
}
|
||||
// Message needs to be recreated here otherwise writing to it again will result in a panic.
|
||||
currentCommit.Message.WriteString(oldCommit.Message.String())
|
||||
}
|
||||
}
|
||||
currentDiff = &Diff{}
|
||||
@@ -259,7 +260,7 @@ func (c *Parser) fromReader(ctx context.Context, stdOut io.Reader, commitChan ch
|
||||
case isIndexLine(line):
|
||||
// NoOp
|
||||
case isPlusFileLine(line):
|
||||
currentDiff.PathB = strings.TrimRight(string(line[6:]), "\n")
|
||||
currentDiff.PathB = strings.TrimRight(strings.TrimRight(string(line[6:]), "\n"), "\t") // Trim the newline and tab characters. https://github.com/trufflesecurity/trufflehog/issues/1060
|
||||
case isMinusFileLine(line):
|
||||
// NoOp
|
||||
case isPlusDiffLine(line):
|
||||
@@ -293,7 +294,9 @@ func (c *Parser) fromReader(ctx context.Context, stdOut io.Reader, commitChan ch
|
||||
}
|
||||
}
|
||||
if currentDiff.Content.Len() > c.maxDiffSize {
|
||||
log.Debugf("Diff for %s exceeded MaxDiffSize(%d)", currentDiff.PathB, c.maxDiffSize)
|
||||
ctx.Logger().V(2).Info(fmt.Sprintf(
|
||||
"Diff for %s exceeded MaxDiffSize(%d)", currentDiff.PathB, c.maxDiffSize,
|
||||
))
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -421,13 +424,14 @@ func isLineNumberDiffLine(line []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get the b/ file path.
|
||||
// Get the b/ file path. Ignoring the edge case of files having `and /b` in the name for simplicity.
|
||||
func pathFromBinaryLine(line []byte) string {
|
||||
sbytes := bytes.Split(line, []byte(" and "))
|
||||
logger := context.Background().Logger()
|
||||
sbytes := bytes.Split(line, []byte(" and b/"))
|
||||
if len(sbytes) != 2 {
|
||||
log.Debugf("Expected binary line to be in 'Binary files a/filaA and b/fileB differ' format. Got: %s", line)
|
||||
logger.V(2).Info("Expected binary line to be in 'Binary files a/fileA and b/fileB differ' format.", "got", line)
|
||||
return ""
|
||||
}
|
||||
bRaw := sbytes[1]
|
||||
return string(bRaw[2 : len(bRaw)-7]) // drop the "b/" and " differ"
|
||||
return string(bRaw[:len(bRaw)-7]) // drop the "b/" and " differ"
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mholt/archiver/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||
logContext "github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
)
|
||||
|
||||
type ctxKey int
|
||||
@@ -55,6 +55,7 @@ func (d *Archive) FromFile(originalCtx context.Context, data io.Reader) chan ([]
|
||||
archiveChan := make(chan ([]byte), 512)
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(originalCtx, maxTimeout)
|
||||
logger := logContext.AddLogger(ctx).Logger()
|
||||
defer cancel()
|
||||
defer close(archiveChan)
|
||||
err := d.openArchive(ctx, 0, data, archiveChan)
|
||||
@@ -62,7 +63,7 @@ func (d *Archive) FromFile(originalCtx context.Context, data io.Reader) chan ([]
|
||||
if errors.Is(err, archiver.ErrNoMatch) {
|
||||
return
|
||||
}
|
||||
log.WithError(err).Debug("Error unarchiving chunk.")
|
||||
logger.V(2).Info("Error unarchiving chunk.")
|
||||
}
|
||||
}()
|
||||
return archiveChan
|
||||
@@ -129,7 +130,8 @@ func (d *Archive) IsFiletype(ctx context.Context, reader io.Reader) (io.Reader,
|
||||
// extractorHandler is applied to each file in an archiver.Extractor file.
|
||||
func (d *Archive) extractorHandler(archiveChan chan ([]byte)) func(context.Context, archiver.File) error {
|
||||
return func(ctx context.Context, f archiver.File) error {
|
||||
log.WithField("filename", f.Name()).Trace("Handling extracted file.")
|
||||
logger := logContext.AddLogger(ctx).Logger()
|
||||
logger.V(5).Info("Handling extracted file.", "filename", f.Name())
|
||||
depth := 0
|
||||
if ctxDepth, ok := ctx.Value(depthKey).(int); ok {
|
||||
depth = ctxDepth
|
||||
@@ -159,19 +161,20 @@ func (d *Archive) ReadToMax(ctx context.Context, reader io.Reader) (data []byte,
|
||||
// rardecode. There is a bug somewhere with rar decoder format 29
|
||||
// that can lead to a panic. An issue is open in rardecode repo
|
||||
// https://github.com/nwaples/rardecode/issues/30.
|
||||
logger := logContext.AddLogger(ctx).Logger()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("Panic occurred when reading archive: %v", r)
|
||||
// Return an error from ReadToMax.
|
||||
if e, ok := r.(error); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = fmt.Errorf("Panic occurred: %v", r)
|
||||
}
|
||||
logger.Error(err, "Panic occurred when reading archive")
|
||||
}
|
||||
}()
|
||||
fileContent := bytes.Buffer{}
|
||||
log.Tracef("Remaining buffer capacity: %d", maxSize-d.size)
|
||||
logger.V(5).Info("Remaining buffer capacity", "bytes", maxSize-d.size)
|
||||
for i := 0; i <= maxSize/512; i++ {
|
||||
if common.IsDone(ctx) {
|
||||
return nil, ctx.Err()
|
||||
@@ -189,7 +192,7 @@ func (d *Archive) ReadToMax(ctx context.Context, reader io.Reader) (data []byte,
|
||||
return fileContent.Bytes(), nil
|
||||
}
|
||||
if d.size >= maxSize && bRead == 512 {
|
||||
log.Debug("Max archive size reached.")
|
||||
logger.V(2).Info("Max archive size reached.")
|
||||
return fileContent.Bytes(), nil
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -4,15 +4,13 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
|
||||
)
|
||||
|
||||
func PrintJSON(r *detectors.ResultWithMetadata) {
|
||||
func PrintJSON(r *detectors.ResultWithMetadata) error {
|
||||
v := &struct {
|
||||
// SourceMetadata contains source-specific contextual information.
|
||||
SourceMetadata *source_metadatapb.MetaData
|
||||
@@ -52,7 +50,8 @@ func PrintJSON(r *detectors.ResultWithMetadata) {
|
||||
}
|
||||
out, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("could not marshal result")
|
||||
return fmt.Errorf("could not marshal result: %w", err)
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
}
|
||||
|
||||
+27
-20
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||
@@ -20,7 +19,7 @@ import (
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
|
||||
)
|
||||
|
||||
func PrintLegacyJSON(ctx context.Context, r *detectors.ResultWithMetadata) {
|
||||
func PrintLegacyJSON(ctx context.Context, r *detectors.ResultWithMetadata) error {
|
||||
var repo string
|
||||
switch r.SourceType {
|
||||
case sourcespb.SourceType_SOURCE_TYPE_GIT:
|
||||
@@ -30,27 +29,31 @@ func PrintLegacyJSON(ctx context.Context, r *detectors.ResultWithMetadata) {
|
||||
case sourcespb.SourceType_SOURCE_TYPE_GITLAB:
|
||||
repo = r.SourceMetadata.GetGitlab().Repository
|
||||
default:
|
||||
logrus.Errorf("unsupported source type for legacy json output: %s", r.SourceType)
|
||||
return fmt.Errorf("unsupported source type for legacy json output: %s", r.SourceType)
|
||||
}
|
||||
|
||||
// cloning the repo again here is not great and only works with unauthed repos
|
||||
repoPath, remote, err := git.PrepareRepo(ctx, repo)
|
||||
if err != nil || repoPath == "" {
|
||||
logrus.WithError(err).Fatal("error preparing git repo for scanning")
|
||||
return fmt.Errorf("error preparing git repo for scanning: %w", err)
|
||||
}
|
||||
if remote {
|
||||
defer os.RemoveAll(repoPath)
|
||||
}
|
||||
|
||||
legacy := ConvertToLegacyJSON(r, repoPath)
|
||||
legacy, err := ConvertToLegacyJSON(r, repoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not convert to legacy JSON: %w", err)
|
||||
}
|
||||
out, err := json.Marshal(legacy)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("could not marshal result")
|
||||
return fmt.Errorf("could not marshal result: %w", err)
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ConvertToLegacyJSON(r *detectors.ResultWithMetadata, repoPath string) *LegacyJSONOutput {
|
||||
func ConvertToLegacyJSON(r *detectors.ResultWithMetadata, repoPath string) (*LegacyJSONOutput, error) {
|
||||
var source LegacyJSONCompatibleSource
|
||||
switch r.SourceType {
|
||||
case sourcespb.SourceType_SOURCE_TYPE_GIT:
|
||||
@@ -60,14 +63,14 @@ func ConvertToLegacyJSON(r *detectors.ResultWithMetadata, repoPath string) *Lega
|
||||
case sourcespb.SourceType_SOURCE_TYPE_GITLAB:
|
||||
source = r.SourceMetadata.GetGitlab()
|
||||
default:
|
||||
log.Fatalf("legacy JSON output can not be used with this source: %s", r.SourceName)
|
||||
return nil, fmt.Errorf("legacy JSON output can not be used with this source: %s", r.SourceName)
|
||||
}
|
||||
|
||||
// The repo will be needed to gather info needed for the legacy output that isn't included in the new
|
||||
// output format.
|
||||
repo, err := gogit.PlainOpenWithOptions(repoPath, &gogit.PlainOpenOptions{DetectDotGit: true})
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatalf("could not open repo: %s", repoPath)
|
||||
return nil, fmt.Errorf("could not open repo %q: %w", repoPath, err)
|
||||
}
|
||||
|
||||
fileName := source.GetFile()
|
||||
@@ -96,7 +99,7 @@ func ConvertToLegacyJSON(r *detectors.ResultWithMetadata, repoPath string) *Lega
|
||||
Reason: r.Result.DetectorType.String(),
|
||||
StringsFound: []string{foundString},
|
||||
}
|
||||
return output
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// BranchHeads creates a map of branch names to their head commit. This can be used to find if a commit is an ancestor
|
||||
@@ -108,16 +111,17 @@ func BranchHeads(repo *gogit.Repository) (map[string]*object.Commit, error) {
|
||||
return branches, err
|
||||
}
|
||||
|
||||
logger := context.Background().Logger()
|
||||
err = branchIter.ForEach(func(branchRef *plumbing.Reference) error {
|
||||
branchName := branchRef.Name().String()
|
||||
headHash, err := repo.ResolveRevision(plumbing.Revision(branchName))
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("unable to resolve head of branch: %s", branchRef.Name().String())
|
||||
logger.Error(err, "unable to resolve head of branch", "branch", branchRef.Name().String())
|
||||
return nil
|
||||
}
|
||||
headCommit, err := repo.CommitObject(*headHash)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("unable to get commit: %s", headCommit.String())
|
||||
logger.Error(err, "unable to get commit", "commit", headCommit.String())
|
||||
return nil
|
||||
}
|
||||
branches[branchName] = headCommit
|
||||
@@ -128,15 +132,17 @@ func BranchHeads(repo *gogit.Repository) (map[string]*object.Commit, error) {
|
||||
|
||||
// FindBranch returns the first branch a commit is a part of. Not the most accurate, but it should work similar to pre v3.0.
|
||||
func FindBranch(commit *object.Commit, repo *gogit.Repository) string {
|
||||
logger := context.Background().Logger()
|
||||
branches, err := BranchHeads(repo)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("could not list branches")
|
||||
logger.Error(err, "could not list branches")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for name, head := range branches {
|
||||
isAncestor, err := commit.IsAncestor(head)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("could not determine if %s is an ancestor of %s", commit.Hash.String(), head.Hash.String())
|
||||
logger.Error(err, fmt.Sprintf("could not determine if %s is an ancestor of %s", commit.Hash.String(), head.Hash.String()))
|
||||
continue
|
||||
}
|
||||
if isAncestor {
|
||||
@@ -149,12 +155,13 @@ func FindBranch(commit *object.Commit, repo *gogit.Repository) string {
|
||||
// GenerateDiff will take a commit and create a string diff between the commit and its first parent.
|
||||
func GenerateDiff(commit *object.Commit, fileName string) string {
|
||||
var diff string
|
||||
logger := context.Background().Logger().WithValues("file", fileName)
|
||||
|
||||
// First grab the first parent of the commit. If there are none, we are at the first commit and should diff against
|
||||
// an empty file.
|
||||
parent, err := commit.Parent(0)
|
||||
if err != object.ErrParentNotFound && err != nil {
|
||||
logrus.WithError(err).Errorf("could not find parent of %s", commit.Hash.String())
|
||||
logger.Error(err, "could not find parent", "commit", commit.Hash.String())
|
||||
}
|
||||
|
||||
// Now get the files from the commit and its parent.
|
||||
@@ -162,13 +169,13 @@ func GenerateDiff(commit *object.Commit, fileName string) string {
|
||||
if parent != nil {
|
||||
parentFile, err = parent.File(fileName)
|
||||
if err != nil && err != object.ErrFileNotFound {
|
||||
logrus.WithError(err).Errorf("could not get previous version of file: %q", fileName)
|
||||
logger.Error(err, "could not get previous version of file")
|
||||
return diff
|
||||
}
|
||||
}
|
||||
commitFile, err := commit.File(fileName)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("could not get current version of file: %q", fileName)
|
||||
logger.Error(err, "could not get current version of file")
|
||||
return diff
|
||||
}
|
||||
|
||||
@@ -179,14 +186,14 @@ func GenerateDiff(commit *object.Commit, fileName string) string {
|
||||
if parentFile != nil {
|
||||
oldContent, err = parentFile.Contents()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("could not get contents of previous version of file: %q", fileName)
|
||||
logger.Error(err, "could not get contents of previous version of file")
|
||||
}
|
||||
}
|
||||
// commitFile should never be nil at this point, but double-checking so we don't get a nil error.
|
||||
if commitFile != nil {
|
||||
newContent, _ = commitFile.Contents()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("could not get contents of current version of file: %q", fileName)
|
||||
logger.Error(err, "could not get contents of current version of file")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +206,7 @@ func GenerateDiff(commit *object.Commit, fileName string) string {
|
||||
// The String() method URL escapes the diff, so it needs to be undone.
|
||||
patchDiff, err := url.QueryUnescape(patch.String())
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("unable to unescape diff")
|
||||
logger.Error(err, "unable to unescape diff")
|
||||
}
|
||||
diff += patchDiff
|
||||
}
|
||||
|
||||
+3
-3
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
@@ -21,7 +20,7 @@ var (
|
||||
whitePrinter = color.New(color.FgWhite)
|
||||
)
|
||||
|
||||
func PrintPlainOutput(r *detectors.ResultWithMetadata) {
|
||||
func PrintPlainOutput(r *detectors.ResultWithMetadata) error {
|
||||
out := outputFormat{
|
||||
DetectorType: r.Result.DetectorType.String(),
|
||||
DecoderType: r.Result.DecoderType.String(),
|
||||
@@ -32,7 +31,7 @@ func PrintPlainOutput(r *detectors.ResultWithMetadata) {
|
||||
|
||||
meta, err := structToMap(out.MetaData.Data)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("could not marshal result")
|
||||
return fmt.Errorf("could not marshal result: %w", err)
|
||||
}
|
||||
|
||||
printer := greenPrinter
|
||||
@@ -61,6 +60,7 @@ func PrintPlainOutput(r *detectors.ResultWithMetadata) {
|
||||
printer.Printf("%s: %v\n", cases.Title(language.AmericanEnglish).String(k), aggregateData[k])
|
||||
}
|
||||
fmt.Println("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func structToMap(obj interface{}) (m map[string]map[string]interface{}, err error) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1267,6 +1267,117 @@ var _ interface {
|
||||
ErrorName() string
|
||||
} = GitlabValidationError{}
|
||||
|
||||
// Validate checks the field values on GoogleDrive 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 *GoogleDrive) Validate() error {
|
||||
return m.validate(false)
|
||||
}
|
||||
|
||||
// ValidateAll checks the field values on GoogleDrive 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 GoogleDriveMultiError, or
|
||||
// nil if none found.
|
||||
func (m *GoogleDrive) ValidateAll() error {
|
||||
return m.validate(true)
|
||||
}
|
||||
|
||||
func (m *GoogleDrive) validate(all bool) error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var errors []error
|
||||
|
||||
// no validation rules for File
|
||||
|
||||
// no validation rules for Link
|
||||
|
||||
// no validation rules for Email
|
||||
|
||||
// no validation rules for Timestamp
|
||||
|
||||
// no validation rules for Shared
|
||||
|
||||
// no validation rules for LastModifiedBy
|
||||
|
||||
if len(errors) > 0 {
|
||||
return GoogleDriveMultiError(errors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GoogleDriveMultiError is an error wrapping multiple validation errors
|
||||
// returned by GoogleDrive.ValidateAll() if the designated constraints aren't met.
|
||||
type GoogleDriveMultiError []error
|
||||
|
||||
// Error returns a concatenation of all the error messages it wraps.
|
||||
func (m GoogleDriveMultiError) 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 GoogleDriveMultiError) AllErrors() []error { return m }
|
||||
|
||||
// GoogleDriveValidationError is the validation error returned by
|
||||
// GoogleDrive.Validate if the designated constraints aren't met.
|
||||
type GoogleDriveValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e GoogleDriveValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e GoogleDriveValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e GoogleDriveValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e GoogleDriveValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e GoogleDriveValidationError) ErrorName() string { return "GoogleDriveValidationError" }
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e GoogleDriveValidationError) 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 %sGoogleDrive.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = GoogleDriveValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = GoogleDriveValidationError{}
|
||||
|
||||
// Validate checks the field values on GCS 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.
|
||||
|
||||
+532
-408
File diff suppressed because it is too large
Load Diff
@@ -705,6 +705,10 @@ func (m *Confluence) validate(all bool) error {
|
||||
|
||||
// no validation rules for InsecureSkipVerifyTls
|
||||
|
||||
// no validation rules for IncludeAttachments
|
||||
|
||||
// no validation rules for SkipHistory
|
||||
|
||||
switch m.Credential.(type) {
|
||||
|
||||
case *Confluence_Unauthenticated:
|
||||
@@ -1883,6 +1887,112 @@ var _ interface {
|
||||
ErrorName() string
|
||||
} = GitHubValidationError{}
|
||||
|
||||
// Validate checks the field values on GoogleDrive 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 *GoogleDrive) Validate() error {
|
||||
return m.validate(false)
|
||||
}
|
||||
|
||||
// ValidateAll checks the field values on GoogleDrive 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 GoogleDriveMultiError, or
|
||||
// nil if none found.
|
||||
func (m *GoogleDrive) ValidateAll() error {
|
||||
return m.validate(true)
|
||||
}
|
||||
|
||||
func (m *GoogleDrive) validate(all bool) error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var errors []error
|
||||
|
||||
switch m.Credential.(type) {
|
||||
|
||||
case *GoogleDrive_RefreshToken:
|
||||
// no validation rules for RefreshToken
|
||||
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return GoogleDriveMultiError(errors)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GoogleDriveMultiError is an error wrapping multiple validation errors
|
||||
// returned by GoogleDrive.ValidateAll() if the designated constraints aren't met.
|
||||
type GoogleDriveMultiError []error
|
||||
|
||||
// Error returns a concatenation of all the error messages it wraps.
|
||||
func (m GoogleDriveMultiError) 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 GoogleDriveMultiError) AllErrors() []error { return m }
|
||||
|
||||
// GoogleDriveValidationError is the validation error returned by
|
||||
// GoogleDrive.Validate if the designated constraints aren't met.
|
||||
type GoogleDriveValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e GoogleDriveValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e GoogleDriveValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e GoogleDriveValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e GoogleDriveValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e GoogleDriveValidationError) ErrorName() string { return "GoogleDriveValidationError" }
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e GoogleDriveValidationError) 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 %sGoogleDrive.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = GoogleDriveValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = GoogleDriveValidationError{}
|
||||
|
||||
// Validate checks the field values on JIRA 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.
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -32,7 +30,6 @@ func Chunker(originalChunk *Chunk) chan *Chunk {
|
||||
chunk := *originalChunk
|
||||
n, err := reader.Read(chunkBytes)
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
logrus.WithError(err).Error("Error chunking reader.")
|
||||
break
|
||||
}
|
||||
peekData, _ := reader.Peek(PeekSize)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sources
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -29,3 +30,7 @@ func (s *ScanErrors) Count() uint64 {
|
||||
defer s.mu.RUnlock()
|
||||
return uint64(len(s.errors))
|
||||
}
|
||||
|
||||
func (s *ScanErrors) String() string {
|
||||
return fmt.Sprintf("%v", s.errors)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sources
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -147,3 +148,12 @@ func TestScanErrorsCount(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanErrorsString(t *testing.T) {
|
||||
se := NewScanErrors()
|
||||
se.Add(nil)
|
||||
want := "[<nil>]"
|
||||
if got := fmt.Sprintf("%v", se); got != want {
|
||||
t.Errorf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,7 @@ func (s *Source) Init(aCtx context.Context, name string, jobId, sourceId int64,
|
||||
if err := anypb.UnmarshalTo(connection, &conn, proto.UnmarshalOptions{}); err != nil {
|
||||
return errors.WrapPrefix(err, "error unmarshalling connection", 0)
|
||||
}
|
||||
|
||||
s.paths = conn.Directories
|
||||
s.paths = append(conn.Paths, conn.Directories...)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -83,100 +82,122 @@ func (s *Source) WithFilter(filter *common.Filter) {
|
||||
// Chunks emits chunks of bytes over a channel.
|
||||
func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) error {
|
||||
for i, path := range s.paths {
|
||||
logger := ctx.Logger().WithValues("path", path)
|
||||
if common.IsDone(ctx) {
|
||||
return nil
|
||||
}
|
||||
s.SetProgressComplete(i, len(s.paths), fmt.Sprintf("Path: %s", path), "")
|
||||
|
||||
cleanPath := filepath.Clean(path)
|
||||
done := false
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
done = true
|
||||
}()
|
||||
fileInfo, err := os.Stat(cleanPath)
|
||||
if err != nil {
|
||||
logger.Error(err, "unable to get file info")
|
||||
continue
|
||||
}
|
||||
|
||||
err := fs.WalkDir(os.DirFS(cleanPath), ".", func(relativePath string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
path := filepath.Join(cleanPath, relativePath)
|
||||
logger := ctx.Logger().WithValues("file", path)
|
||||
|
||||
fileStat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
logger.Error(err, "unable to stat file")
|
||||
return nil
|
||||
}
|
||||
if !fileStat.Mode().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.filter != nil && !s.filter.Pass(path) {
|
||||
return nil
|
||||
}
|
||||
|
||||
inputFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
logger.V(2).Info("error opening file", "error", err)
|
||||
return nil
|
||||
}
|
||||
defer inputFile.Close()
|
||||
logger.V(5).Info("scanning file")
|
||||
|
||||
reReader, err := diskbufferreader.New(inputFile)
|
||||
if err != nil {
|
||||
logger.Error(err, "Could not create re-readable reader.")
|
||||
}
|
||||
defer reReader.Close()
|
||||
|
||||
chunkSkel := &sources.Chunk{
|
||||
SourceType: s.Type(),
|
||||
SourceName: s.name,
|
||||
SourceID: s.SourceID(),
|
||||
SourceMetadata: &source_metadatapb.MetaData{
|
||||
Data: &source_metadatapb.MetaData_Filesystem{
|
||||
Filesystem: &source_metadatapb.Filesystem{
|
||||
File: sanitizer.UTF8(path),
|
||||
},
|
||||
},
|
||||
},
|
||||
Verify: s.verify,
|
||||
}
|
||||
if handlers.HandleFile(ctx, reReader, chunkSkel, chunksChan) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := reReader.Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
reReader.Stop()
|
||||
data, err := io.ReadAll(reReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chunksChan <- &sources.Chunk{
|
||||
SourceType: s.Type(),
|
||||
SourceName: s.name,
|
||||
SourceID: s.SourceID(),
|
||||
Data: data,
|
||||
SourceMetadata: &source_metadatapb.MetaData{
|
||||
Data: &source_metadatapb.MetaData_Filesystem{
|
||||
Filesystem: &source_metadatapb.Filesystem{
|
||||
File: sanitizer.UTF8(path),
|
||||
},
|
||||
},
|
||||
},
|
||||
Verify: s.verify,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if fileInfo.IsDir() {
|
||||
err = s.scanDir(ctx, cleanPath, chunksChan)
|
||||
} else {
|
||||
err = s.scanFile(ctx, cleanPath, chunksChan)
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
return errors.New(err)
|
||||
logger.Info("error scanning filesystem", "error", err)
|
||||
}
|
||||
|
||||
if done {
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Source) scanDir(ctx context.Context, path string, chunksChan chan *sources.Chunk) error {
|
||||
return fs.WalkDir(os.DirFS(path), ".", func(relativePath string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
fullPath := filepath.Join(path, relativePath)
|
||||
|
||||
// Skip over non-regular files. We do this check here to suppress noisy
|
||||
// logs for trying to scan directories and other non-regular files in
|
||||
// our traversal.
|
||||
fileStat, err := os.Stat(fullPath)
|
||||
if err != nil {
|
||||
ctx.Logger().Info("unable to stat file", "path", fullPath, "error", err)
|
||||
return nil
|
||||
}
|
||||
if !fileStat.Mode().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
if s.filter != nil && !s.filter.Pass(fullPath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = s.scanFile(ctx, fullPath, chunksChan); err != nil {
|
||||
ctx.Logger().Info("error scanning file", "path", fullPath, "error", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Source) scanFile(ctx context.Context, path string, chunksChan chan *sources.Chunk) error {
|
||||
logger := ctx.Logger().WithValues("path", path)
|
||||
fileStat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to stat file: %w", err)
|
||||
}
|
||||
if !fileStat.Mode().IsRegular() {
|
||||
return fmt.Errorf("not a regular file")
|
||||
}
|
||||
|
||||
inputFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to open file: %w", err)
|
||||
}
|
||||
defer inputFile.Close()
|
||||
logger.V(3).Info("scanning file")
|
||||
|
||||
reReader, err := diskbufferreader.New(inputFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create re-readable reader: %w", err)
|
||||
}
|
||||
defer reReader.Close()
|
||||
|
||||
chunkSkel := &sources.Chunk{
|
||||
SourceType: s.Type(),
|
||||
SourceName: s.name,
|
||||
SourceID: s.SourceID(),
|
||||
SourceMetadata: &source_metadatapb.MetaData{
|
||||
Data: &source_metadatapb.MetaData_Filesystem{
|
||||
Filesystem: &source_metadatapb.Filesystem{
|
||||
File: sanitizer.UTF8(path),
|
||||
},
|
||||
},
|
||||
},
|
||||
Verify: s.verify,
|
||||
}
|
||||
if handlers.HandleFile(ctx, reReader, chunkSkel, chunksChan) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := reReader.Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
reReader.Stop()
|
||||
data, err := io.ReadAll(reReader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read file: %w", err)
|
||||
}
|
||||
chunksChan <- &sources.Chunk{
|
||||
SourceType: s.Type(),
|
||||
SourceName: s.name,
|
||||
SourceID: s.SourceID(),
|
||||
Data: data,
|
||||
SourceMetadata: &source_metadatapb.MetaData{
|
||||
Data: &source_metadatapb.MetaData_Filesystem{
|
||||
Filesystem: &source_metadatapb.Filesystem{
|
||||
File: sanitizer.UTF8(path),
|
||||
},
|
||||
},
|
||||
},
|
||||
Verify: s.verify,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestSource_Scan(t *testing.T) {
|
||||
init: init{
|
||||
name: "this repo",
|
||||
connection: &sourcespb.Filesystem{
|
||||
Directories: []string{"."},
|
||||
Paths: []string{"."},
|
||||
},
|
||||
verify: true,
|
||||
},
|
||||
|
||||
@@ -137,7 +137,7 @@ func TestSource_Scan(t *testing.T) {
|
||||
}
|
||||
chunksCh := make(chan *sources.Chunk, 1)
|
||||
go func() {
|
||||
s.Chunks(ctx, chunksCh)
|
||||
assert.NoError(t, s.Chunks(ctx, chunksCh))
|
||||
}()
|
||||
gotChunk := <-chunksCh
|
||||
gotChunk.Data = nil
|
||||
|
||||
@@ -55,6 +55,7 @@ type Source struct {
|
||||
includeRepos,
|
||||
ignoreRepos []string
|
||||
git *git.Git
|
||||
scanOptions *git.ScanOptions
|
||||
httpClient *http.Client
|
||||
log logr.Logger
|
||||
conn *sourcespb.GitHub
|
||||
@@ -67,6 +68,10 @@ type Source struct {
|
||||
sources.Progress
|
||||
}
|
||||
|
||||
func (s *Source) WithScanOptions(scanOptions *git.ScanOptions) {
|
||||
s.scanOptions = scanOptions
|
||||
}
|
||||
|
||||
// Ensure the Source satisfies the interface at compile time
|
||||
var _ sources.Source = (*Source)(nil)
|
||||
var endsWithGithub = regexp.MustCompile(`github\.com/?$`)
|
||||
@@ -514,6 +519,11 @@ func (s *Source) scan(ctx context.Context, installationClient *github.Client, ch
|
||||
reposToScan, progressIndexOffset := sources.FilterReposToResume(s.repos, s.GetProgress().EncodedResumeInfo)
|
||||
s.repos = reposToScan
|
||||
|
||||
// Setup scan options if it wasn't provided.
|
||||
if s.scanOptions == nil {
|
||||
s.scanOptions = &git.ScanOptions{}
|
||||
}
|
||||
|
||||
var scanErrs []error
|
||||
for i, repoURL := range s.repos {
|
||||
i, repoURL := i, repoURL
|
||||
@@ -551,13 +561,11 @@ func (s *Source) scan(ctx context.Context, installationClient *github.Client, ch
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// Base and head will only exist from incoming webhooks.
|
||||
scanOptions := git.NewScanOptions(
|
||||
git.ScanOptionBaseHash(s.conn.Base),
|
||||
git.ScanOptionHeadCommit(s.conn.Head),
|
||||
)
|
||||
|
||||
if err = s.git.ScanRepo(ctx, repo, path, scanOptions, chunksChan); err != nil {
|
||||
s.scanOptions.BaseHash = s.conn.Base
|
||||
s.scanOptions.HeadHash = s.conn.Head
|
||||
|
||||
if err = s.git.ScanRepo(ctx, repo, path, s.scanOptions, chunksChan); err != nil {
|
||||
logger.Error(err, "unable to scan repo, continuing")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -78,6 +78,8 @@ type GithubConfig struct {
|
||||
ExcludeRepos,
|
||||
// IncludeRepos is a list of repositories to include in the scan.
|
||||
IncludeRepos []string
|
||||
// Filter is the filter to use to scan the source.
|
||||
Filter *common.Filter
|
||||
}
|
||||
|
||||
// GitlabConfig defines the optional configuration for a gitlab source.
|
||||
@@ -94,8 +96,8 @@ type GitlabConfig struct {
|
||||
|
||||
// FilesystemConfig defines the optional configuration for a filesystem source.
|
||||
type FilesystemConfig struct {
|
||||
// Directories is the list of directories to scan.
|
||||
Directories []string
|
||||
// Paths is the list of files and directories to scan.
|
||||
Paths []string
|
||||
// Filter is the filter to use to scan the source.
|
||||
Filter *common.Filter
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/bill-rich/go-syslog/pkg/syslogparser/rfc3164"
|
||||
"github.com/crewjam/rfc5424"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
@@ -215,7 +214,7 @@ func (s *Source) monitorConnection(ctx context.Context, conn net.Conn, chunksCha
|
||||
}
|
||||
err := conn.SetDeadline(time.Now().Add(time.Second))
|
||||
if err != nil {
|
||||
logrus.WithError(err).Debug("could not set connection deadline deadline")
|
||||
ctx.Logger().V(2).Info("could not set connection deadline", "error", err)
|
||||
}
|
||||
input := make([]byte, 8096)
|
||||
remote := conn.RemoteAddr()
|
||||
@@ -226,10 +225,10 @@ func (s *Source) monitorConnection(ctx context.Context, conn net.Conn, chunksCha
|
||||
}
|
||||
continue
|
||||
}
|
||||
logrus.Trace(string(input))
|
||||
ctx.Logger().V(5).Info(string(input))
|
||||
metadata, err := s.parseSyslogMetadata(input, remote.String())
|
||||
if err != nil {
|
||||
logrus.WithError(err).Debug("failed to generate metadata")
|
||||
ctx.Logger().V(2).Info("failed to generate metadata", "error", err)
|
||||
}
|
||||
chunksChan <- &sources.Chunk{
|
||||
SourceName: s.syslog.sourceName,
|
||||
@@ -249,7 +248,7 @@ func (s *Source) acceptTCPConnections(ctx context.Context, netListener net.Liste
|
||||
}
|
||||
conn, err := netListener.Accept()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Debug("failed to accept TCP connection")
|
||||
ctx.Logger().V(2).Info("failed to accept TCP connection", "error", err)
|
||||
continue
|
||||
}
|
||||
go s.monitorConnection(ctx, conn, chunksChan)
|
||||
@@ -271,7 +270,7 @@ func (s *Source) acceptUDPConnections(ctx context.Context, netListener net.Packe
|
||||
}
|
||||
metadata, err := s.parseSyslogMetadata(input, remote.String())
|
||||
if err != nil {
|
||||
logrus.WithError(err).Debug("failed to parse metadata")
|
||||
ctx.Logger().V(2).Info("failed to parse metadata", "error", err)
|
||||
}
|
||||
chunksChan <- &sources.Chunk{
|
||||
SourceName: s.syslog.sourceName,
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jpillora/overseer/fetcher"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/version"
|
||||
)
|
||||
|
||||
@@ -78,7 +78,7 @@ func (g *OSS) Fetch() (io.Reader, error) {
|
||||
return nil, errors.New("already up to date")
|
||||
}
|
||||
|
||||
log.Debug("fetching trufflehog update")
|
||||
context.Background().Logger().V(2).Info("fetching trufflehog update")
|
||||
|
||||
newBinBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
|
||||
@@ -111,6 +111,15 @@ message Gitlab {
|
||||
int64 line = 7;
|
||||
}
|
||||
|
||||
message GoogleDrive {
|
||||
string file = 1;
|
||||
string link = 2;
|
||||
string email = 3;
|
||||
string timestamp = 4;
|
||||
bool shared = 5;
|
||||
string last_modified_by = 6;
|
||||
}
|
||||
|
||||
message GCS {
|
||||
string bucket = 1;
|
||||
string file = 2;
|
||||
|
||||
+13
-1
@@ -40,6 +40,7 @@ enum SourceType {
|
||||
SOURCE_TYPE_SYSLOG = 25;
|
||||
SOURCE_TYPE_PUBLIC_EVENT_MONITORING = 26;
|
||||
SOURCE_TYPE_SLACK_REALTIME = 27;
|
||||
SOURCE_TYPE_GOOGLE_DRIVE = 28;
|
||||
}
|
||||
|
||||
message LocalSource {
|
||||
@@ -97,6 +98,8 @@ message Confluence {
|
||||
bool insecure_skip_verify_tls = 6;
|
||||
repeated string spaces = 7;
|
||||
repeated string ignore_spaces = 8;
|
||||
bool include_attachments = 9;
|
||||
bool skip_history = 10;
|
||||
}
|
||||
|
||||
message DockerHub {
|
||||
@@ -113,8 +116,11 @@ message ECR {
|
||||
repeated string registries = 2;
|
||||
}
|
||||
|
||||
message Filesystem{
|
||||
message Filesystem {
|
||||
// DEPRECATED: directories is deprecated and can be removed / renamed to
|
||||
// paths when we no longer depend on the name in enterprise configs.
|
||||
repeated string directories = 1;
|
||||
repeated string paths = 2;
|
||||
}
|
||||
|
||||
message GCS {
|
||||
@@ -162,6 +168,12 @@ message GitHub {
|
||||
repeated string includeRepos = 12;
|
||||
}
|
||||
|
||||
message GoogleDrive {
|
||||
oneof credential {
|
||||
string refresh_token = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message JIRA {
|
||||
string endpoint = 1 [(validate.rules).string.uri_ref = true];
|
||||
oneof credential {
|
||||
|
||||
Reference in New Issue
Block a user