diff --git a/.github/actions/ci/build/action.yml b/.github/actions/ci/build/action.yml new file mode 100644 index 0000000..bab2180 --- /dev/null +++ b/.github/actions/ci/build/action.yml @@ -0,0 +1,24 @@ +name: Build and Setup + +description: Build and Setup + +inputs: + go_version: + description: 'Version of Go to use for this build' + required: true + +runs: + using: composite + steps: + - name: Setup Repo + uses: ./.github/actions/ci/setup + with: + go_version: ${{ inputs.go_version }} + + - name: Build Code + shell: bash + run: go build -v ./... + + - name: Run Tests + shell: bash + run: go test -v ./... diff --git a/.github/actions/ci/leaks/action.yml b/.github/actions/ci/leaks/action.yml new file mode 100644 index 0000000..babf823 --- /dev/null +++ b/.github/actions/ci/leaks/action.yml @@ -0,0 +1,19 @@ +name: Check Leaks + +description: Check Leaks + +inputs: + gitleaks_license: + description: "A gitleaks-action license" + required: true + +runs: + using: composite + steps: + - name: Check Leaks + uses: gitleaks/gitleaks-action@v2 + env: + GITLEAKS_LICENSE: ${{ inputs.gitleaks_license }} + GITLEAKS_CONFIG: .github/actions/ci/leaks/gitleaks.toml + GITLEAKS_ENABLE_SUMMARY: "false" + GITLEAKS_ENABLE_UPLOAD_ARTIFACT: "false" diff --git a/.github/actions/ci/leaks/gitleaks.toml b/.github/actions/ci/leaks/gitleaks.toml new file mode 100644 index 0000000..7155137 --- /dev/null +++ b/.github/actions/ci/leaks/gitleaks.toml @@ -0,0 +1,655 @@ +title = "gitleaks config" + +[[rules]] +id = "gitlab-pat" +description = "GitLab Personal Access Token" +regex = '''glpat-[0-9a-zA-Z\-\_]{20}''' +keywords = ["glpat"] + +[[rules]] +id = "aws-access-token" +description = "AWS" +regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' +keywords = [ + "AKIA", + "AGPA", + "AIDA", + "AROA", + "AIPA", + "ANPA", + "ANVA", + "ASIA", +] + +[[rules]] +id = "PKCS8-PK" +description = "PKCS8 private key" +regex = '''-----BEGIN PRIVATE KEY-----''' +keywords = ["BEGIN PRIVATE"] + +[[rules]] +id = "RSA-PK" +description = "RSA private key" +regex = '''-----BEGIN RSA PRIVATE KEY-----''' +keywords = ["BEGIN RSA"] + +[[rules]] +id = "OPENSSH-PK" +description = "SSH private key" +regex = '''-----BEGIN OPENSSH PRIVATE KEY-----''' +keywords = ["BEGIN OPENSSH"] + +[[rules]] +id = "PGP-PK" +description = "PGP private key" +regex = '''-----BEGIN PGP PRIVATE KEY BLOCK-----''' +keywords = ["BEGIN PGP"] + +[[rules]] +id = "github-pat" +description = "GitHub Personal Access Token" +regex = '''ghp_[0-9a-zA-Z]{36}''' +keywords = ["ghp_"] + +[[rules]] +id = "github-oauth" +description = "GitHub OAuth Access Token" +regex = '''gho_[0-9a-zA-Z]{36}''' +keywords = ["gho_"] + + +[[rules]] +id = "SSH-DSA-PK" +description = "SSH (DSA) private key" +regex = '''-----BEGIN DSA PRIVATE KEY-----''' +keywords = ["BEGIN DSA"] + +[[rules]] +id = "SSH-EC-PK" +description = "SSH (EC) private key" +regex = '''-----BEGIN EC PRIVATE KEY-----''' +keywords = ["BEGIN EC"] + + +[[rules]] +id = "github-app-token" +description = "GitHub App Token" +regex = '''(ghu|ghs)_[0-9a-zA-Z]{36}''' +keywords = [ + "ghu_", + "ghs_" +] + +[[rules]] +id = "github-refresh-token" +description = "GitHub Refresh Token" +regex = '''ghr_[0-9a-zA-Z]{76}''' +keywords = ["ghr_"] + +[[rules]] +id = "shopify-shared-secret" +description = "Shopify shared secret" +regex = '''shpss_[a-fA-F0-9]{32}''' +keywords = ["shpss_"] + +[[rules]] +id = "shopify-access-token" +description = "Shopify access token" +regex = '''shpat_[a-fA-F0-9]{32}''' +keywords = ["shpat_"] + +[[rules]] +id = "shopify-custom-access-token" +description = "Shopify custom app access token" +regex = '''shpca_[a-fA-F0-9]{32}''' +keywords = ["shpca_"] + +[[rules]] +id = "shopify-private-app-access-token" +description = "Shopify private app access token" +regex = '''shppa_[a-fA-F0-9]{32}''' +keywords = ["shppa_"] + +[[rules]] +id = "slack-access-token" +description = "Slack token" +regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})?''' +keywords = [ + "xoxb", + "xoxa", + "xoxp", + "xoxr", + "xoxs" + ] + +[[rules]] +id = "stripe-access-token" +description = "Stripe" +regex = '''(?i)(sk|pk)_(test|live)_[0-9a-z]{10,32}''' +keywords = [ + "sk_test", + "pk_test", + "sk_live", + "pk_live" +] + +[[rules]] +id = "pypi-upload-token" +description = "PyPI upload token" +regex = '''pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}''' +keywords = ["pypi-AgEIcHlwaS5vcmc"] + +[[rules]] +id = "gcp-service-account" +description = "Google (GCP) Service-account" +regex = '''\"type\": \"service_account\"''' +keywords = ["\"type\": \"service_account\""] + +[[rules]] +id = "heroku-api-key" +description = "Heroku API Key" +regex = ''' (?i)(heroku[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})['\"]''' +secretGroup = 3 +keywords = ["heroku"] + +[[rules]] +id = "slack-web-hook" +description = "Slack Webhook" +regex = '''https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8,12}/[a-zA-Z0-9_]{24}''' +keywords = ["https://hooks.slack.com/services/"] + +[[rules]] +id = "twilio-api-key" +description = "Twilio API Key" +regex = '''SK[0-9a-fA-F]{32}''' +keywords = ["twilio"] + +[[rules]] +id = "age-secret-key" +description = "Age secret key" +regex = '''AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}''' +keywords = ["AGE-SECRET-KEY-1"] + +[[rules]] +id = "facebook-token" +description = "Facebook token" +regex = '''(?i)(facebook[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]''' +secretGroup = 3 +keywords = ["facebook"] + +[[rules]] +id = "twitter-token" +description = "Twitter token" +regex = '''(?i)(twitter[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{35,44})['\"]''' +secretGroup = 3 +keywords = ["twitter"] + +[[rules]] +id = "adobe-client-id" +description = "Adobe Client ID (Oauth Web)" +regex = '''(?i)(adobe[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]''' +secretGroup = 3 +keywords = ["adobe"] + +[[rules]] +id = "adobe-client-secret" +description = "Adobe Client Secret" +regex = '''(p8e-)(?i)[a-z0-9]{32}''' +keywords = ["p8e-"] + +[[rules]] +id = "alibaba-access-key-id" +description = "Alibaba AccessKey ID" +regex = '''(LTAI)(?i)[a-z0-9]{20}''' +keywords = ["LTAI"] + +[[rules]] +id = "alibaba-secret-key" +description = "Alibaba Secret Key" +regex = '''(?i)(alibaba[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{30})['\"]''' +secretGroup = 3 +keywords = ["alibaba"] + +[[rules]] +id = "asana-client-id" +description = "Asana Client ID" +regex = '''(?i)(asana[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9]{16})['\"]''' +secretGroup = 3 +keywords = ["asana"] + +[[rules]] +id = "asana-client-secret" +description = "Asana Client Secret" +regex = '''(?i)(asana[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{32})['\"]''' +secretGroup = 3 +keywords = ["asana"] + +[[rules]] +id = "atlassian-api-token" +description = "Atlassian API token" +regex = '''(?i)(atlassian[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{24})['\"]''' +secretGroup = 3 +keywords = ["atlassian"] + +[[rules]] +id = "bitbucket-client-id" +description = "Bitbucket client ID" +regex = '''(?i)(bitbucket[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{32})['\"]''' +secretGroup = 3 +keywords = ["bitbucket"] + +[[rules]] +id = "bitbucket-client-secret" +description = "Bitbucket client secret" +regex = '''(?i)(bitbucket[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9_\-]{64})['\"]''' +secretGroup = 3 +keywords = ["bitbucket"] + +[[rules]] +id = "beamer-api-token" +description = "Beamer API token" +regex = '''(?i)(beamer[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](b_[a-z0-9=_\-]{44})['\"]''' +secretGroup = 3 +keywords = ["beamer"] + +[[rules]] +id = "clojars-api-token" +description = "Clojars API token" +regex = '''(CLOJARS_)(?i)[a-z0-9]{60}''' +keywords = ["clojars"] + +[[rules]] +id = "contentful-delivery-api-token" +description = "Contentful delivery API token" +regex = '''(?i)(contentful[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9\-=_]{43})['\"]''' +secretGroup = 3 +keywords = ["contentful"] + +[[rules]] +id = "databricks-api-token" +description = "Databricks API token" +regex = '''dapi[a-h0-9]{32}''' +keywords = ["dapi"] + +[[rules]] +id = "discord-api-token" +description = "Discord API key" +regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{64})['\"]''' +secretGroup = 3 +keywords = ["discord"] + +[[rules]] +id = "discord-client-id" +description = "Discord client ID" +regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9]{18})['\"]''' +secretGroup = 3 +keywords = ["discord"] + +[[rules]] +id = "discord-client-secret" +description = "Discord client secret" +regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9=_\-]{32})['\"]''' +secretGroup = 3 +keywords = ["discord"] + +[[rules]] +id = "doppler-api-token" +description = "Doppler API token" +regex = '''['\"](dp\.pt\.)(?i)[a-z0-9]{43}['\"]''' +keywords = ["doppler"] + +[[rules]] +id = "dropbox-api-secret" +description = "Dropbox API secret/key" +regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{15})['\"]''' +keywords = ["dropbox"] + +[[rules]] +id = "dropbox--api-key" +description = "Dropbox API secret/key" +regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{15})['\"]''' +keywords = ["dropbox"] + +[[rules]] +id = "dropbox-short-lived-api-token" +description = "Dropbox short lived API token" +regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](sl\.[a-z0-9\-=_]{135})['\"]''' +keywords = ["dropbox"] + +[[rules]] +id = "dropbox-long-lived-api-token" +description = "Dropbox long lived API token" +regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"][a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43}['\"]''' +keywords = ["dropbox"] + +[[rules]] +id = "duffel-api-token" +description = "Duffel API token" +regex = '''['\"]duffel_(test|live)_(?i)[a-z0-9_-]{43}['\"]''' +keywords = ["duffel"] + +[[rules]] +id = "dynatrace-api-token" +description = "Dynatrace API token" +regex = '''['\"]dt0c01\.(?i)[a-z0-9]{24}\.[a-z0-9]{64}['\"]''' +keywords = ["dynatrace"] + +[[rules]] +id = "easypost-api-token" +description = "EasyPost API token" +regex = '''['\"]EZAK(?i)[a-z0-9]{54}['\"]''' +keywords = ["EZAK"] + +[[rules]] +id = "easypost-test-api-token" +description = "EasyPost test API token" +regex = '''['\"]EZTK(?i)[a-z0-9]{54}['\"]''' +keywords = ["EZTK"] + +[[rules]] +id = "fastly-api-token" +description = "Fastly API token" +regex = '''(?i)(fastly[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9\-=_]{32})['\"]''' +secretGroup = 3 +keywords = ["fastly"] + +[[rules]] +id = "finicity-client-secret" +description = "Finicity client secret" +regex = '''(?i)(finicity[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{20})['\"]''' +secretGroup = 3 +keywords = ["finicity"] + +[[rules]] +id = "finicity-api-token" +description = "Finicity API token" +regex = '''(?i)(finicity[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]''' +secretGroup = 3 +keywords = ["finicity"] + +[[rules]] +id = "flutterwave-public-key" +description = "Flutterwave public key" +regex = '''FLWPUBK_TEST-(?i)[a-h0-9]{32}-X''' +keywords = ["FLWPUBK_TEST"] + +[[rules]] +id = "flutterwave-secret-key" +description = "Flutterwave secret key" +regex = '''FLWSECK_TEST-(?i)[a-h0-9]{32}-X''' +keywords = ["FLWSECK_TEST"] + +[[rules]] +id = "flutterwave-enc-key" +description = "Flutterwave encrypted key" +regex = '''FLWSECK_TEST[a-h0-9]{12}''' +keywords = ["FLWSECK_TEST"] + +[[rules]] +id = "frameio-api-token" +description = "Frame.io API token" +regex = '''fio-u-(?i)[a-z0-9\-_=]{64}''' +keywords = ["fio-u-"] + +[[rules]] +id = "gocardless-api-token" +description = "GoCardless API token" +regex = '''['\"]live_(?i)[a-z0-9\-_=]{40}['\"]''' +keywords = ["live_"] + +[[rules]] +id = "hashicorp-tf-api-token" +description = "HashiCorp Terraform user/org API token" +regex = '''['\"](?i)[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}['\"]''' +keywords = ["atlasv1"] + +[[rules]] +id = "hubspot-api-token" +description = "HubSpot API token" +regex = '''(?i)(hubspot[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{8}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{12})['\"]''' +secretGroup = 3 +keywords = ["hubspot"] + +[[rules]] +id = "intercom-api-token" +description = "Intercom API token" +regex = '''(?i)(intercom[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9=_]{60})['\"]''' +secretGroup = 3 +keywords = ["intercom"] + +[[rules]] +id = "intercom-client-secret" +description = "Intercom client secret/ID" +regex = '''(?i)(intercom[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{8}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{12})['\"]''' +secretGroup = 3 +keywords = ["intercom"] + +[[rules]] +id = "ionic-api-token" +description = "Ionic API token" +regex = '''(?i)(ionic[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](ion_[a-z0-9]{42})['\"]''' +keywords = ["ionic"] + +[[rules]] +id = "linear-api-token" +description = "Linear API token" +regex = '''lin_api_(?i)[a-z0-9]{40}''' +keywords = ["lin_api_"] + +[[rules]] +id = "linear-client-secret" +description = "Linear client secret/ID" +regex = '''(?i)(linear[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]''' +secretGroup = 3 +keywords = ["linear"] + +[[rules]] +id = "lob-api-key" +description = "Lob API Key" +regex = '''(?i)(lob[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]((live|test)_[a-f0-9]{35})['\"]''' +secretGroup = 3 +keywords = ["lob"] + +[[rules]] +id = "lob-pub-api-key" +description = "Lob Publishable API Key" +regex = '''(?i)(lob[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]((test|live)_pub_[a-f0-9]{31})['\"]''' +secretGroup = 3 +keywords = [ + "test_pub", + "live_pub", + "_pub" +] + +[[rules]] +id = "mailchimp-api-key" +description = "Mailchimp API key" +regex = '''(?i)(mailchimp[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32}-us20)['\"]''' +secretGroup = 3 +keywords = ["mailchimp"] + +[[rules]] +id = "mailgun-private-api-token" +description = "Mailgun private API token" +regex = '''(?i)(mailgun[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](key-[a-f0-9]{32})['\"]''' +secretGroup = 3 +keywords = [ + "mailgun", + "key-" +] + +[[rules]] +id = "mailgun-pub-key" +description = "Mailgun public validation key" +regex = '''(?i)(mailgun[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](pubkey-[a-f0-9]{32})['\"]''' +secretGroup = 3 +keywords = [ + "mailgun", + "pubkey-" +] + +[[rules]] +id = "mailgun-signing-key" +description = "Mailgun webhook signing key" +regex = '''(?i)(mailgun[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})['\"]''' +secretGroup = 3 +keywords = ["mailgun"] + +[[rules]] +id = "mapbox-api-token" +description = "Mapbox API token" +regex = '''(?i)(pk\.[a-z0-9]{60}\.[a-z0-9]{22})''' +keywords = ["mapbox"] + +[[rules]] +id = "messagebird-api-token" +description = "MessageBird API token" +regex = '''(?i)(messagebird[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{25})['\"]''' +secretGroup = 3 +keywords = [ + "messagebird", + "message_bird", + "message-bird" +] + +[[rules]] +id = "messagebird-client-id" +description = "MessageBird API client ID" +regex = '''(?i)(messagebird[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{8}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{12})['\"]''' +secretGroup = 3 +keywords = [ + "messagebird", + "message_bird", + "message-bird" +] + +[[rules]] +id = "new-relic-user-api-key" +description = "New Relic user API Key" +regex = '''['\"](NRAK-[A-Z0-9]{27})['\"]''' +keywords = ["NRAK-"] + +[[rules]] +id = "new-relic-user-api-id" +description = "New Relic user API ID" +regex = '''(?i)(newrelic[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([A-Z0-9]{64})['\"]''' +secretGroup = 3 +keywords = ["newrelic"] + +[[rules]] +id = "new-relic-browser-api-token" +description = "New Relic ingest browser API token" +regex = '''['\"](NRJS-[a-f0-9]{19})['\"]''' +keywords = ["NRJS-"] + +[[rules]] +id = "npm-access-token" +description = "npm access token" +regex = '''['\"](npm_(?i)[a-z0-9]{36})['\"]''' +keywords = ["npm_"] + +[[rules]] +id = "planetscale-password" +description = "PlanetScale password" +regex = '''pscale_pw_(?i)[a-z0-9\-_\.]{43}''' +keywords = ["pscale_pw_"] + +[[rules]] +id = "planetscale-api-token" +description = "PlanetScale API token" +regex = '''pscale_tkn_(?i)[a-z0-9\-_\.]{43}''' +keywords = ["pscale_tkn_"] + +[[rules]] +id = "postman-api-token" +description = "Postman API token" +regex = '''PMAK-(?i)[a-f0-9]{24}\-[a-f0-9]{34}''' +keywords = ["PMAK-"] + +[[rules]] +id = "pulumi-api-token" +description = "Pulumi API token" +regex = '''pul-[a-f0-9]{40}''' +keywords = ["pul-"] + +[[rules]] +id = "rubygems-api-token" +description = "Rubygem API token" +regex = '''rubygems_[a-f0-9]{48}''' +keywords = ["rubygems_"] + +[[rules]] +id = "sendgrid-api-token" +description = "SendGrid API token" +regex = '''SG\.(?i)[a-z0-9_\-\.]{66}''' +keywords = ["sendgrid"] + +[[rules]] +id = "sendinblue-api-token" +description = "Sendinblue API token" +regex = '''xkeysib-[a-f0-9]{64}\-(?i)[a-z0-9]{16}''' +keywords = ["xkeysib-"] + +[[rules]] +id = "shippo-api-token" +description = "Shippo API token" +regex = '''shippo_(live|test)_[a-f0-9]{40}''' +keywords = ["shippo_"] + +[[rules]] +id = "linkedin-client-secret" +description = "LinkedIn Client secret" +regex = '''(?i)(linkedin[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z]{16})['\"]''' +secretGroup = 3 +keywords = ["linkedin"] + +[[rules]] +id = "linkedin-client-id" +description = "LinkedIn Client ID" +regex = '''(?i)(linkedin[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{14})['\"]''' +secretGroup = 3 +keywords = ["linkedin"] + +[[rules]] +id = "twitch-api-token" +description = "Twitch API token" +regex = '''(?i)(twitch[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{30})['\"]''' +secretGroup = 3 +keywords = ["twitch"] + +[[rules]] +id = "typeform-api-token" +description = "Typeform API token" +regex = '''(?i)(typeform[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}(tfp_[a-z0-9\-_\.=]{59})''' +secretGroup = 3 +keywords = ["tpf_"] + +[[rules]] +id = "generic-api-key" +description = "Generic API Key" +regex = '''(?i)(([^config]Key|api[^Version]|token|secret|password|auth)[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\-_=]{8,64})['\"]''' +entropy = 3.7 +secretGroup = 4 +keywords = [ + "key", + "api", + "token", + "secret", + "password", + "auth", +] + +[allowlist] +description = "global allow lists" +regexes = [ + '''219-09-9999''', + '''078-05-1120''', + '''(9[0-9]{2}|666)-\d{2}-\d{4}''', +] +paths = [ + '''gitleaks.toml''', + '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', + '''(go.mod|go.sum)$''', + "vendor/", + ".vscode/targets.log", +] diff --git a/.github/actions/ci/lint/action.yml b/.github/actions/ci/lint/action.yml new file mode 100644 index 0000000..bf54389 --- /dev/null +++ b/.github/actions/ci/lint/action.yml @@ -0,0 +1,24 @@ +name: Run Linter + +description: Run Linter + +inputs: + go_version: + description: 'Version of Go to use for this build' + required: true + +runs: + using: composite + steps: + - name: Setup Repo + uses: ./.github/actions/ci/setup + with: + go_version: ${{ inputs.go_version }} + + - name: Run Linter + uses: golangci/golangci-lint-action@v6 + with: + version: v1.60.3 + skip-pkg-cache: true + skip-build-cache: true + args: --config=.github/actions/ci/lint/golangci.yml diff --git a/.github/actions/ci/lint/golangci.yml b/.github/actions/ci/lint/golangci.yml new file mode 100644 index 0000000..8d064cb --- /dev/null +++ b/.github/actions/ci/lint/golangci.yml @@ -0,0 +1,70 @@ +run: + timeout: 3m + +linters-settings: + gofmt: + simplify: false + revive: + rules: + - name: blank-imports + - name: context-as-argument + - name: defer + arguments: [["loop", "return"]] + - name: context-keys-type # Might cause slowness in lint + - name: dot-imports + - name: duplicated-imports + - name: error-naming + - name: error-return + - name: error-strings + - name: errorf # Might cause slowness in lint + - name: if-return + - name: indent-error-flow + - name: range + - name: receiver-naming + - name: time-naming # Might cause slowness in lint + - name: unconditional-recursion + - name: unreachable-code + # - name: unused-parameter # Temporarily disabled + - name: var-declaration # Might cause slowness in lint + - name: waitgroup-by-value + +linters: + disable-all: true + enable: + - copyloopvar + - durationcheck + - errcheck + - forcetypeassert + - godox + - gofmt + - goimports + - gosimple + # - govet # Temporarily disabled + - ineffassign + - makezero + - misspell + - nilerr + - predeclared + - revive + - staticcheck + - tenv + - unconvert + - unparam + - unused + +issues: + # Independently from option `exclude` we use default exclude patterns, + # it can be disabled by this option. To list all + # excluded by default patterns execute `golangci-lint run --help`. + # Default value for this option is true. + exclude-use-default: false + + # Maximum issues count per one linter. + # Set to 0 to disable. + # Default: 50 + max-issues-per-linter: 0 + + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 0 diff --git a/.github/actions/ci/setup/action.yml b/.github/actions/ci/setup/action.yml new file mode 100644 index 0000000..8d6d827 --- /dev/null +++ b/.github/actions/ci/setup/action.yml @@ -0,0 +1,25 @@ +name: Setup Repo + +description: Setup Repo + +inputs: + go_version: + description: 'Version of Go to use for this build' + required: true + +runs: + using: composite + steps: + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ${{ inputs.go_version }} + cache: false + + - name: Enable Cache + uses: actions/cache@v4 + with: + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ed5099f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: CI + +on: + push: + paths-ignore: + - "README.md" + +permissions: + contents: read + +jobs: + build: + name: Build and Setup + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + - name: Build + uses: ./.github/actions/ci/build + with: + go_version: '1.22' + + lint: + name: Run Linter + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + - name: Run Linter + uses: ./.github/actions/ci/lint + with: + go_version: '1.22' + + leaks: + name: Check Leaks + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Check Leaks + uses: ./.github/actions/ci/leaks + with: + gitleaks_license: ${{ secrets.GITLEAKS_LICENSE }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 6876f10..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,79 +0,0 @@ -# Terraform Provider testing workflow. -name: Tests - -# This GitHub action runs your tests for each pull request and push. -# Optionally, you can turn it on using a schedule for regular testing. -on: - pull_request: - paths-ignore: - - "README.md" - -# Testing only needs permissions to read the repository contents. -permissions: - contents: read - -jobs: - # Ensure project builds before running testing matrix - build: - name: Build - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 - with: - go-version-file: "go.mod" - cache: true - - run: go mod download - - run: go build -v . - - name: Run linters - uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 - with: - version: latest - - generate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 - with: - go-version-file: "go.mod" - cache: true - - run: go generate ./... - - name: git diff - run: | - git diff --compact-summary --exit-code || \ - (echo; echo "Unexpected difference in directories after code generation. Run 'go generate ./...' command and commit."; exit 1) - - # Run acceptance tests in a matrix with Terraform CLI versions - # test: - # name: Terraform Provider Acceptance Tests - # needs: build - # runs-on: ubuntu-latest - # timeout-minutes: 15 - # strategy: - # fail-fast: false - # matrix: - # terraform: - # - "1.6.*" - # - "1.7.*" - # - "1.8.*" - # - "1.9.*" - # - "1.10.*" - # steps: - # - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - # - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 - # with: - # go-version-file: "go.mod" - # cache: true - # - uses: hashicorp/setup-terraform@651471c36a6092792c552e8b1bef71e592b462d8 # v3.1.1 - # with: - # terraform_version: ${{ matrix.terraform }} - # terraform_wrapper: false - # - run: go mod download - # - env: - # DESCOPE_PROJECT_ID: ${{ secrets.DESCOPE_PROJECT_ID }} - # DESCOPE_MANAGEMENT_KEY: ${{ secrets.DESCOPE_MANAGEMENT_KEY }} - # TF_ACC: "1" - # run: go test -v -cover ./provider/ - # timeout-minutes: 10 diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index 4c6bb5a..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Visit https://golangci-lint.run/ for usage documentation -# and information on other useful linters -issues: - max-per-linter: 0 - max-same-issues: 0 - -linters: - disable-all: true - enable: - - durationcheck - - errcheck - - exportloopref - - forcetypeassert - - godot - - gofmt - - gosimple - - ineffassign - - makezero - - misspell - - nilerr - - predeclared - - staticcheck - - tenv - - unconvert - - unparam - - unused - - vet diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index d553691..a918ff2 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -15,7 +15,7 @@ var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServe "descope": providerserver.NewProtocol6WithError(New("test")()), } -func testAccPreCheck(t *testing.T) { +func testAccPreCheck(_ *testing.T) { // You can add code here to run prior to any test case execution, for example assertions // about the appropriate environment variables being set are common to see in a pre-check // function. diff --git a/internal/provider/resource_project.go b/internal/provider/resource_project.go index 604dc91..fadaec4 100644 --- a/internal/provider/resource_project.go +++ b/internal/provider/resource_project.go @@ -26,7 +26,7 @@ type projectResource struct { client *infra.Client } -func (r *projectResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *projectResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) { if client, ok := req.ProviderData.(*infra.Client); ok { r.client = client }