├── .java-version ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── test-fixtures ├── src │ └── testFixtures │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ └── org.junit.jupiter.api.extension.Extension │ │ └── kotlin │ │ └── com │ │ └── faire │ │ └── gradle │ │ └── test │ │ └── UseRootProjectGradleDependencyConfigurationTestExtension.kt └── build.gradle.kts ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── kotlinc.xml ├── encodings.xml └── icon.svg ├── gradle.properties ├── .github ├── dependabot.yml └── workflows │ ├── gitleaks.yml │ ├── release.yml │ └── ci.yml ├── settings.gradle.kts ├── gradle-build.detekt.yaml ├── LICENSE ├── .gitignore ├── README.md ├── gradlew.bat ├── gradlew ├── detekt.yaml └── .gitleaks.toml /.java-version: -------------------------------------------------------------------------------- 1 | 21.0 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faire/build-targets-gradle-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /test-fixtures/src/testFixtures/resources/META-INF/services/org.junit.jupiter.api.extension.Extension: -------------------------------------------------------------------------------- 1 | com.faire.gradle.test.UseRootProjectGradleDependencyConfigurationTestExtension 2 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-XX:MaxMetaspaceSize=1024m -Xmx4096m -Dfile.encoding=UTF-8 2 | 3 | org.gradle.daemon=true 4 | org.gradle.parallel=true 5 | org.gradle.caching=true 6 | 7 | org.gradle.configuration-cache=true 8 | 9 | dependency.analysis.print.build.health=true 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /test-fixtures/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | id("faire.kotlin") 4 | `java-test-fixtures` 5 | } 6 | 7 | dependencies { 8 | testFixturesImplementation(kotlin("stdlib")) 9 | testFixturesImplementation(gradleTestKit()) 10 | 11 | testFixturesImplementation(libs.junit.jupiter.api) 12 | testFixturesImplementation(libs.navatwo.gradle.better.testing.junit5) 13 | } 14 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: '/' 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | timezone: Canada/Eastern 9 | labels: 10 | - dependencies 11 | - rubber-stamp 12 | 13 | - package-ecosystem: github-actions 14 | directory: '/' 15 | schedule: 16 | interval: daily 17 | time: "10:00" 18 | timezone: Canada/Eastern 19 | labels: 20 | - dependencies 21 | - rubber-stamp 22 | -------------------------------------------------------------------------------- /.github/workflows/gitleaks.yml: -------------------------------------------------------------------------------- 1 | name: gitleaks 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [ main ] 7 | workflow_dispatch: 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | scan: 13 | name: gitleaks 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v6 17 | with: 18 | fetch-depth: 0 19 | - uses: gitleaks/gitleaks-action@v2.3.9 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE}} 23 | 24 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "faire-build-targets-gradle-plugin" 2 | 3 | pluginManagement { 4 | includeBuild("./build-logic") 5 | 6 | repositories { 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | 12 | include( 13 | ":build-targets-gradle-plugin", 14 | ":test-fixtures", 15 | ) 16 | 17 | plugins { 18 | id("com.gradle.develocity") version("3.17.2") 19 | } 20 | 21 | develocity { 22 | buildScan { 23 | termsOfUseUrl.set("https://gradle.com/help/legal-terms-of-use") 24 | termsOfUseAgree.set("yes") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Trigger Release 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published] 7 | 8 | jobs: 9 | publish_archives: 10 | runs-on: ubuntu-latest 11 | 12 | permissions: 13 | contents: read 14 | 15 | env: 16 | RELEASE: true 17 | 18 | steps: 19 | - name: Checkout the repo 20 | uses: actions/checkout@v6 21 | 22 | - name: Set up JDK 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: temurin 26 | java-version-file: .java-version 27 | 28 | - name: Setup gradle 29 | uses: gradle/actions/setup-gradle@v5 30 | with: 31 | gradle-home-cache-cleanup: true 32 | 33 | - name: Verify build 34 | run: ./gradlew check 35 | 36 | - name: Publish the artifacts 37 | run: ./gradlew publishPlugins --no-configuration-cache 38 | env: 39 | GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} 40 | GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} 41 | -------------------------------------------------------------------------------- /gradle-build.detekt.yaml: -------------------------------------------------------------------------------- 1 | FaireRuleSet: 2 | PreventBannedImports: 3 | active: true 4 | autoCorrect: true 5 | # Reminder: add relevant entries to .idea/codeInsightSettings.xml, too, 6 | # so IntelliJ does not suggest them in autocomplete. 7 | withAlternatives: 8 | - com.github.jgonian.ipmath.Optional=java.util.Optional 9 | - com.google.common.base.Optional=java.util.Optional 10 | 11 | - jakarta.ws.rs=javax.ws.rs 12 | - java.lang.Integer.max=kotlin.math.max 13 | - java.lang.Integer.min=kotlin.math.min 14 | - java.lang.long.max=kotlin.math.max 15 | - java.lang.long.min=kotlin.math.min 16 | - net.bytebuddy.dynamic.DynamicType.Builder.FieldDefinition.Optional=java.util.Optional 17 | - net.bytebuddy.dynamic.DynamicType.Builder.MethodDefinition.ImplementationDefinition.Optional=java.util.Optional 18 | - net.bytebuddy.dynamic.DynamicType.Builder.RecordComponentDefinition.Optional=java.util.Optional 19 | - org.apache.commons.lang.time.StopWatch=com.google.common.base.Stopwatch 20 | - org.apache.http.HttpHeaders=com.google.common.net.HttpHeaders 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | 10 | permissions: read-all 11 | 12 | jobs: 13 | ci: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | gradle-version: ['current', '8.12.1', '7.6.4'] 18 | steps: 19 | - name: Check out repository code 20 | uses: actions/checkout@v6 21 | 22 | - name: Set up JDK 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: temurin 26 | java-version-file: .java-version 27 | 28 | - name: Setup Gradle 29 | uses: gradle/actions/setup-gradle@v5 30 | with: 31 | gradle-version: ${{ matrix.gradle-version }} 32 | 33 | - name: Compile classes 34 | run: ./gradlew classes testClasses --continue 35 | 36 | - name: Lint 37 | run: ./gradlew detektMain detektTest --continue 38 | 39 | - name: Check 40 | run: ./gradlew check --continue 41 | 42 | - name: Verify Dependencies 43 | run: ./gradlew buildHealth 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Faire 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .DS_Store 3 | 4 | # for files/dirs used in CI that shouldn't appear in git diffs 5 | /.ci/ 6 | 7 | bin/ 8 | target/ 9 | logs/ 10 | **/out/ 11 | 12 | npm-debug.log 13 | dependency-reduced-pom.xml 14 | 15 | build/ 16 | .gradle/ 17 | .kotlin/ 18 | 19 | .terraform/ 20 | *.hprof* 21 | hs_err_pid*.log 22 | 23 | # python virtualenv 24 | .venv 25 | 26 | ## VS Code gitignore 27 | .classpath 28 | .project 29 | .settings/ 30 | 31 | protos/ios-protos/ 32 | 33 | ## Opt out everything in .idea by default 34 | **/.idea/** 35 | 36 | ## Opt certain .idea files back in 37 | !**/.idea/codeInsightSettings.xml 38 | !**/.idea/encodings.xml 39 | !**/.idea/kotlinc.xml 40 | # We need to unksip the directoy in order to unskip its contents. 41 | # Don't use ** here so that people can have their own templates. 42 | !**/.idea/fileTemplates 43 | # Do NOT add contain slashes at the end as we want both the directories AND everything within. 44 | # Git doc: "It is not possible to re-include a file if a parent directory of that file is excluded." 45 | !**/.idea/codeStyles** 46 | !**/.idea/inspectionProfiles** 47 | !**/.idea/runConfigurations** 48 | !**/.idea/icon.svg 49 | 50 | # Python 51 | __pycache__/ 52 | 53 | # Node 54 | node_modules/ 55 | 56 | # local enviroment variables file 57 | .env 58 | 59 | #Jetbrains Fleet 60 | .fleet/ 61 | 62 | # Cockroach DB 63 | cockroach-data/ 64 | 65 | # don't check in appdash cli creds 66 | appdash-cookies.json 67 | 68 | .focus 69 | .focusGitBase 70 | .focusProjects 71 | .focusProjects.yaml 72 | .focusPlayground/ 73 | 74 | # don't check in product area attribution files 75 | **/.productarea.yml 76 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | 3 | assertj = "3.27.6" 4 | 5 | detekt = "1.23.6" 6 | 7 | gradle-better-testing = "0.0.6" 8 | 9 | junit-jupiter = "5.11.4" 10 | junit-platform = "1.10.2" 11 | 12 | kotlin = "2.2.21" 13 | 14 | [libraries] 15 | 16 | assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } 17 | 18 | detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } 19 | detekt-kotlin-compiler-wrapper = { module = "com.braisgabin.detekt:kotlin-compiler-wrapper", version = "0.0.4" } 20 | 21 | faire-detekt-rules = { module = "com.github.Faire:faire-detekt-rules", version = "v0.2.1" } 22 | 23 | gson = { module = "com.google.code.gson:gson", version = "2.13.2" } 24 | 25 | junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" } 26 | junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" } 27 | 28 | navatwo-gradle-better-testing-junit5 = { module = "net.navatwo.gradle:gradle-plugin-better-testing-junit5", version.ref = "gradle-better-testing" } 29 | navatwo-gradle-better-testing-asserts = { module = "net.navatwo.gradle:gradle-plugin-better-testing-assertj-asserts", version.ref = "gradle-better-testing" } 30 | 31 | pluginz-detekt = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } 32 | 33 | pluginz-gradle-plugin-publish = { module = "com.gradle.publish:plugin-publish-plugin", version = "1.2.1" } 34 | 35 | pluginz-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } 36 | 37 | [plugins] 38 | detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } 39 | kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } 40 | 41 | dependency-analysis = { id = "com.autonomousapps.dependency-analysis", version = "3.5.1" } 42 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # build-targets 2 | 3 | [![Gradle Plugin Portal Version](https://img.shields.io/gradle-plugin-portal/v/com.faire.build-targets)](https://plugins.gradle.org/plugin/com.faire.build-targets) 4 | [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/Faire/build-targets-gradle-plugin/ci.yml)](https://github.com/Faire/build-targets-gradle-plugin/actions/workflows/ci.yml) 5 | 6 | Generate build "targets" based on Git changes between different git refs. This plugin generates a mapping of dependent projects. After this is generated 7 | and cached, the code uses the project mapping to generate per-file mapping that can correlate against diffs. 8 | 9 | Currently, this plugin works against `application` projects. 10 | 11 | 12 | ## Usage 13 | 14 | In the root `build.gradle.kts` file, apply the plugin: 15 | 16 | ```kotlin 17 | plugins { 18 | id("com.faire.build-targets") version "1.0.+" 19 | } 20 | ``` 21 | 22 | For all projects with `application` applied, each has a task `showServiceChangeStatus` created. 23 | 24 | By running: 25 | 26 | ```shell 27 | ./gradlew showBuildTargetsForChange \ 28 | # Location where `${gradle_project_name}.status` files are created \ 29 | --outputDirectory=build/application_statuses \ 30 | # Commit ref to diff against, e.g. branch name, hash \ 31 | --currentCommitRef='deadbeef' \ 32 | # Optional: Defaults to '${currentCommitSha}~1` \ 33 | # --previousCommitRef='deadbeef~4' 34 | ``` 35 | 36 | A directory will be created at `outputDirectory` with a file for each project. The file contains a simple `true` or 37 | `false` if the project has changed between the specified references. 38 | 39 | ## Releasing 40 | 41 | 1. Create and land a PR bumping the version in `build.gradle.kts`, e.g. https://github.com/Faire/build-targets-gradle-plugin/pull/74 42 | 2. Create a [new release](https://github.com/Faire/build-targets-gradle-plugin/releases) 43 | 3. Verify published in [Gradle portal](https://plugins.gradle.org/plugin/com.faire.build-targets) 44 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /test-fixtures/src/testFixtures/kotlin/com/faire/gradle/test/UseRootProjectGradleDependencyConfigurationTestExtension.kt: -------------------------------------------------------------------------------- 1 | package com.faire.gradle.test 2 | 3 | import net.navatwo.gradle.testkit.junit5.GradleProject 4 | import org.gradle.testkit.runner.GradleRunner 5 | import org.junit.jupiter.api.extension.BeforeAllCallback 6 | import org.junit.jupiter.api.extension.ExtensionContext 7 | import org.junit.jupiter.api.extension.InvocationInterceptor 8 | import org.junit.jupiter.api.extension.ReflectiveInvocationContext 9 | import java.io.File 10 | import java.lang.reflect.Method 11 | import java.util.concurrent.TimeUnit 12 | 13 | /** 14 | * Configures the test gradle project to use the repo root version catalog (libs.versions.toml) and .java-version 15 | * NOTE: this extension is autoloaded when included in the classpath due to the resources/META-INF/services entry: 16 | * https://junit.org/junit5/docs/current/user-guide/#extensions-registration-automatic 17 | */ 18 | internal class UseRootProjectGradleDependencyConfigurationTestExtension : InvocationInterceptor, BeforeAllCallback { 19 | override fun beforeAll(context: ExtensionContext) { 20 | val testClass = context.requiredTestClass 21 | if (!testClass.methods.any { it.isAnnotationPresent(GradleProject::class.java) }) { 22 | // This class is only useful when there are @GradleProject tests to run 23 | return 24 | } 25 | 26 | val process = ProcessBuilder("git", "rev-parse", "--show-toplevel") 27 | .redirectOutput(ProcessBuilder.Redirect.PIPE) 28 | .redirectError(ProcessBuilder.Redirect.PIPE) 29 | .start() 30 | .apply { waitFor(10, TimeUnit.SECONDS) } 31 | val gitRoot = File(process.inputStream.bufferedReader().readText().trim()) 32 | 33 | context.getStore(ExtensionContext.Namespace.GLOBAL).put(REPO_ROOT_ABSOLUTE_PATH, gitRoot) 34 | } 35 | 36 | @Suppress("ForbiddenVoid") // Java override! 37 | override fun interceptTestMethod( 38 | invocation: InvocationInterceptor.Invocation, 39 | invocationContext: ReflectiveInvocationContext, 40 | context: ExtensionContext, 41 | ) { 42 | // since this class is loaded unconditionally, we need to check if the beforeAll() did anything first 43 | val gitRoot = context.getStore(ExtensionContext.Namespace.GLOBAL) 44 | .getOrDefault(REPO_ROOT_ABSOLUTE_PATH, File::class.java, null) 45 | 46 | if (gitRoot != null) { 47 | // to find the temporary test gradle project directory, we need to first figure out which parameter is the 48 | // GradleRunner 49 | val runnerParamIndex = context.requiredTestMethod.parameters.indexOfLast { 50 | it.isAnnotationPresent(GradleProject.Runner::class.java) 51 | } 52 | if (runnerParamIndex >= 0) { 53 | // then the invocationContext contains the actual parameter value 54 | val testProjectRoot = (invocationContext.arguments[runnerParamIndex] as GradleRunner).projectDir 55 | copyFilesToTestProject(gitRoot, testProjectRoot) 56 | } 57 | } 58 | 59 | invocation.proceed() 60 | } 61 | 62 | private fun copyFilesToTestProject(gitRoot: File, testProjectRoot: File) { 63 | for (f in FILES_TO_COPY) { gitRoot.resolve(f).copyTo(testProjectRoot.resolve(f), overwrite = true) } 64 | } 65 | 66 | companion object { 67 | private const val REPO_ROOT_ABSOLUTE_PATH = "repoRootAbsolutePath" 68 | private val FILES_TO_COPY = listOf( 69 | "gradle/libs.versions.toml", 70 | ".java-version", 71 | ) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 119 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /detekt.yaml: -------------------------------------------------------------------------------- 1 | # See https://github.com/detekt/detekt/blob/main/detekt-core/src/main/resources/default-detekt-config.yml 2 | # for default settings. 3 | 4 | #build: 5 | # maxIssues: 0 6 | # weights: 7 | # formatting: 1 8 | # complexity: 2 9 | # LongParameterList: 1 10 | # style: 1 11 | # comments: 1 12 | 13 | output-reports: 14 | active: true 15 | exclude: 16 | - HtmlOutputReport 17 | - TxtOutputReport 18 | - XmlOutputReport 19 | 20 | processors: 21 | active: false 22 | # exclude: 23 | # - FunctionCountProcessor 24 | # - PropertyCountProcessor 25 | # - ClassCountProcessor 26 | # - PackageCountProcessor 27 | # - KtFileCountProcessor 28 | 29 | console-reports: 30 | active: true 31 | # exclude: 32 | # - ProjectStatisticsReport 33 | # - ComplexityReport 34 | # - NotificationReport 35 | # - FindingsReport 36 | # - BuildFailureReport 37 | 38 | comments: 39 | active: true 40 | CommentOverPrivateFunction: 41 | active: false 42 | CommentOverPrivateProperty: 43 | active: false 44 | EndOfSentenceFormat: 45 | active: false 46 | endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!]$) 47 | UndocumentedPublicClass: 48 | active: true 49 | searchInNestedClass: true 50 | searchInInnerClass: true 51 | searchInInnerObject: true 52 | searchInInnerInterface: true 53 | UndocumentedPublicFunction: 54 | active: false 55 | UndocumentedPublicProperty: 56 | active: false 57 | 58 | complexity: 59 | active: true 60 | ComplexCondition: 61 | active: true 62 | threshold: 9 63 | ComplexInterface: 64 | active: true 65 | threshold: 120 66 | includeStaticDeclarations: false 67 | CyclomaticComplexMethod: 68 | active: true 69 | threshold: 180 70 | ignoreSingleWhenExpression: false 71 | ignoreSimpleWhenEntries: false 72 | LabeledExpression: 73 | active: false 74 | LargeClass: 75 | active: true 76 | threshold: 1000 77 | LongMethod: 78 | active: true 79 | threshold: 300 80 | LongParameterList: 81 | active: false 82 | ignoreDefaultParameters: false 83 | MethodOverloading: 84 | active: false 85 | threshold: 6 86 | NestedBlockDepth: 87 | active: false 88 | threshold: 4 89 | StringLiteralDuplication: 90 | active: false 91 | threshold: 3 92 | ignoreAnnotation: true 93 | excludeStringsWithLessThan5Characters: true 94 | ignoreStringsRegex: $^ 95 | TooManyFunctions: 96 | active: false 97 | thresholdInFiles: 11 98 | thresholdInClasses: 11 99 | thresholdInInterfaces: 11 100 | thresholdInObjects: 11 101 | thresholdInEnums: 11 102 | ignoreDeprecated: false 103 | ignorePrivate: false 104 | 105 | empty-blocks: 106 | EmptyTryBlock: 107 | active: true 108 | EmptyCatchBlock: 109 | active: true 110 | allowedExceptionNameRegex: ^(_|(ignore|expected).*) 111 | EmptyClassBlock: 112 | active: true 113 | EmptyDefaultConstructor: 114 | active: true 115 | EmptyDoWhileBlock: 116 | active: true 117 | EmptyElseBlock: 118 | active: true 119 | EmptyFinallyBlock: 120 | active: true 121 | EmptyForBlock: 122 | active: true 123 | EmptyFunctionBlock: 124 | active: true 125 | ignoreOverridden: true 126 | EmptyIfBlock: 127 | active: true 128 | EmptyInitBlock: 129 | active: true 130 | EmptyKtFile: 131 | active: true 132 | excludes: ["**/build.gradle.kts"] 133 | EmptySecondaryConstructor: 134 | active: true 135 | EmptyWhenBlock: 136 | active: true 137 | EmptyWhileBlock: 138 | active: true 139 | 140 | exceptions: 141 | active: false 142 | ExceptionRaisedInUnexpectedLocation: 143 | active: false 144 | methodNames: 145 | - toString 146 | - hashCode 147 | - equals 148 | - finalize 149 | InstanceOfCheckForException: 150 | active: false 151 | NotImplementedDeclaration: 152 | active: false 153 | PrintStackTrace: 154 | active: false 155 | RethrowCaughtException: 156 | active: false 157 | ReturnFromFinally: 158 | active: false 159 | SwallowedException: 160 | active: false 161 | ignoredExceptionTypes: 162 | - InterruptedException 163 | - NumberFormatException 164 | - ParseException 165 | - MalformedURLException 166 | ThrowingExceptionFromFinally: 167 | active: false 168 | ThrowingExceptionInMain: 169 | active: false 170 | ThrowingExceptionsWithoutMessageOrCause: 171 | active: false 172 | exceptions: 173 | - IllegalArgumentException 174 | - IllegalStateException 175 | - IOException 176 | ThrowingNewInstanceOfSameException: 177 | active: false 178 | TooGenericExceptionCaught: 179 | active: true 180 | exceptionNames: 181 | - ArrayIndexOutOfBoundsException 182 | - Error 183 | - Exception 184 | - IllegalMonitorStateException 185 | - NullPointerException 186 | - IndexOutOfBoundsException 187 | - RuntimeException 188 | - Throwable 189 | allowedExceptionNameRegex: ^(_|(ignore|expected).*) 190 | TooGenericExceptionThrown: 191 | active: true 192 | exceptionNames: 193 | - Error 194 | - Exception 195 | - Throwable 196 | - RuntimeException 197 | 198 | formatting: 199 | active: true 200 | android: false 201 | autoCorrect: true 202 | AnnotationOnSeparateLine: 203 | active: false 204 | AnnotationSpacing: 205 | active: false 206 | ArgumentListWrapping: 207 | active: false 208 | ChainWrapping: 209 | active: false 210 | autoCorrect: true 211 | CommentSpacing: 212 | active: true 213 | autoCorrect: true 214 | EnumEntryNameCase: 215 | active: true 216 | ignoreAnnotated: [kotlin.Deprecated] 217 | # Use MatchingDeclarationName instead. 218 | Filename: 219 | active: false 220 | FinalNewline: 221 | active: true 222 | autoCorrect: true 223 | ImportOrdering: 224 | active: true 225 | autoCorrect: true 226 | Indentation: 227 | active: false 228 | autoCorrect: true 229 | indentSize: 4 230 | # Use MaxLineLength instead. 231 | MaximumLineLength: 232 | active: false 233 | maxLineLength: 120 234 | ModifierOrdering: 235 | active: true 236 | autoCorrect: true 237 | MultiLineIfElse: 238 | active: true 239 | autoCorrect: true 240 | NoAnonymousArgumentAfterNamedArguments: 241 | active: true 242 | NoBlankLineBeforeRbrace: 243 | active: true 244 | autoCorrect: true 245 | NoConsecutiveBlankLines: 246 | active: true 247 | autoCorrect: true 248 | NoCreateWithPrefix: 249 | active: true 250 | NoEmptyClassBody: 251 | active: true 252 | autoCorrect: true 253 | NoEmptyFirstLineInMethodBlock: 254 | active: true 255 | NoLineBreakAfterElse: 256 | active: true 257 | autoCorrect: true 258 | NoLineBreakBeforeAssignment: 259 | active: true 260 | autoCorrect: true 261 | NoMultipleSpaces: 262 | active: true 263 | autoCorrect: true 264 | NoSemicolons: 265 | active: true 266 | autoCorrect: true 267 | NoTrailingSpaces: 268 | active: true 269 | autoCorrect: true 270 | NoUnitReturn: 271 | active: true 272 | autoCorrect: true 273 | NoUnusedImports: 274 | active: true 275 | autoCorrect: true 276 | NoWildcardImports: 277 | active: true 278 | autoCorrect: true 279 | PackageName: 280 | active: false 281 | autoCorrect: true 282 | ParameterListWrapping: 283 | active: true 284 | autoCorrect: true 285 | SpacingAroundAngleBrackets: 286 | active: true 287 | autoCorrect: true 288 | SpacingAroundColon: 289 | active: true 290 | autoCorrect: true 291 | SpacingAroundComma: 292 | active: true 293 | autoCorrect: true 294 | SpacingAroundCurly: 295 | active: true 296 | autoCorrect: true 297 | SpacingAroundKeyword: 298 | active: true 299 | autoCorrect: true 300 | SpacingAroundOperators: 301 | active: true 302 | autoCorrect: true 303 | SpacingAroundParens: 304 | active: true 305 | autoCorrect: true 306 | SpacingAroundRangeOperator: 307 | active: true 308 | autoCorrect: true 309 | SpacingBetweenDeclarationsWithAnnotations: 310 | active: false 311 | SpacingBetweenDeclarationsWithComments: 312 | active: false 313 | StringTemplate: 314 | active: true 315 | autoCorrect: true 316 | TrailingCommaOnCallSite: 317 | active: true 318 | autoCorrect: true 319 | TrailingCommaOnDeclarationSite: 320 | active: true 321 | autoCorrect: true 322 | Wrapping: 323 | active: true 324 | UnnecessaryParenthesesBeforeTrailingLambda: 325 | active: true 326 | PropertyWrapping: 327 | active: true 328 | excludes: 329 | - "**/*Test.kt" 330 | FunctionReturnTypeSpacing: 331 | active: true 332 | BlockCommentInitialStarAlignment: 333 | active: true 334 | CommentWrapping: 335 | active: true 336 | 337 | naming: 338 | active: true 339 | ClassNaming: 340 | active: true 341 | classPattern: "[A-Z$][a-zA-Z0-9$]*" 342 | ConstructorParameterNaming: 343 | active: false 344 | parameterPattern: "[a-z][A-Za-z0-9]*" 345 | privateParameterPattern: "[a-z][A-Za-z0-9]*" 346 | excludeClassPattern: $^ 347 | EnumNaming: 348 | active: false 349 | enumEntryPattern: ^[A-Z][_a-zA-Z0-9]* 350 | ForbiddenClassName: 351 | active: false 352 | FunctionMaxLength: 353 | active: false 354 | maximumFunctionNameLength: 30 355 | FunctionMinLength: 356 | active: false 357 | minimumFunctionNameLength: 3 358 | FunctionNaming: 359 | active: false 360 | functionPattern: ^([a-z$][a-zA-Z$0-9]*)|(`.*`)$ 361 | excludeClassPattern: $^ 362 | FunctionParameterNaming: 363 | active: false 364 | parameterPattern: "[a-z][A-Za-z0-9]*" 365 | excludeClassPattern: $^ 366 | InvalidPackageDeclaration: 367 | active: true 368 | MatchingDeclarationName: 369 | active: true 370 | MemberNameEqualsClassName: 371 | active: false 372 | ignoreOverridden: true 373 | NoNameShadowing: 374 | active: true 375 | ObjectPropertyNaming: 376 | active: true 377 | constantPattern: "[A-Za-z][_A-Za-z0-9]*" 378 | propertyPattern: "[A-Za-z][_A-Za-z0-9]*" 379 | privatePropertyPattern: (_)?[A-Za-z][_A-Za-z0-9]* 380 | PackageNaming: 381 | active: true 382 | packagePattern: ^[a-z]+(\.[a-z][a-zA-Z0-9_]*)*$ 383 | TopLevelPropertyNaming: 384 | active: false 385 | constantPattern: "[A-Z][_A-Z0-9]*" 386 | propertyPattern: "[A-Za-z][_A-Za-z0-9]*" 387 | privatePropertyPattern: (_)?[A-Za-z][A-Za-z0-9]* 388 | VariableMaxLength: 389 | active: true 390 | maximumVariableNameLength: 64 391 | VariableMinLength: 392 | active: true 393 | VariableNaming: 394 | active: false 395 | variablePattern: "[a-z][A-Za-z0-9]*" 396 | privateVariablePattern: (_)?[a-z][A-Za-z0-9]* 397 | excludeClassPattern: $^ 398 | 399 | performance: 400 | ArrayPrimitive: 401 | active: true 402 | CouldBeSequence: 403 | active: true 404 | ForEachOnRange: 405 | active: true 406 | SpreadOperator: 407 | active: false 408 | UnnecessaryTemporaryInstantiation: 409 | active: true 410 | 411 | potential-bugs: 412 | active: true 413 | AvoidReferentialEquality: 414 | active: true 415 | CastToNullableType: 416 | active: false 417 | DoubleMutabilityForCollection: 418 | active: true 419 | ElseCaseInsteadOfExhaustiveWhen: 420 | active: true 421 | EqualsAlwaysReturnsTrueOrFalse: 422 | active: true 423 | EqualsWithHashCodeExist: 424 | active: false 425 | ExplicitGarbageCollectionCall: 426 | active: true 427 | HasPlatformType: 428 | active: true 429 | IgnoredReturnValue: 430 | active: true 431 | ImplicitDefaultLocale: 432 | active: true 433 | InvalidRange: 434 | active: true 435 | IteratorHasNextCallsNextMethod: 436 | active: true 437 | IteratorNotThrowingNoSuchElementException: 438 | active: true 439 | LateinitUsage: 440 | active: false 441 | ignoreAnnotated: [""] 442 | ignoreOnClassesPattern: "" 443 | MapGetWithNotNullAssertionOperator: 444 | active: true 445 | MissingPackageDeclaration: 446 | active: true 447 | UnconditionalJumpStatementInLoop: 448 | active: false 449 | UnnecessaryNotNullOperator: 450 | active: true 451 | UnnecessarySafeCall: 452 | active: true 453 | UnreachableCode: 454 | active: true 455 | UnsafeCallOnNullableType: 456 | active: true 457 | UnsafeCast: 458 | active: true 459 | UselessPostfixExpression: 460 | active: true 461 | WrongEqualsTypeParameter: 462 | active: true 463 | 464 | style: 465 | active: true 466 | ClassOrdering: 467 | active: true 468 | CollapsibleIfStatements: 469 | active: true 470 | DataClassContainsFunctions: 471 | active: false 472 | conversionFunctionPrefix: [to] 473 | DataClassShouldBeImmutable: 474 | active: true 475 | DestructuringDeclarationWithTooManyEntries: 476 | active: true 477 | EqualsNullCall: 478 | active: true 479 | EqualsOnSignatureLine: 480 | active: true 481 | ExplicitItLambdaParameter: 482 | active: true 483 | ExpressionBodySyntax: 484 | active: true 485 | includeLineWrapping: false 486 | ForbiddenComment: 487 | active: true 488 | comments: 489 | - reason: "" 490 | value: "TODO:" 491 | - reason: "" 492 | value: "FIXME:" 493 | - reason: "" 494 | value: "STOPSHIP:" 495 | # We use PreventBannedImports instead which has autocorrect. 496 | ForbiddenImport: 497 | active: false 498 | imports: [] 499 | ForbiddenMethodCall: 500 | active: true 501 | ForbiddenVoid: 502 | active: true 503 | FunctionOnlyReturningConstant: 504 | active: true 505 | ignoreOverridableFunction: true 506 | excludedFunctions: [describeContents] 507 | LoopWithTooManyJumpStatements: 508 | active: false 509 | maxJumpCount: 1 510 | MagicNumber: 511 | active: true 512 | ignoreNumbers: ["-1", "0", "1", "2"] 513 | ignoreHashCodeFunction: true 514 | ignorePropertyDeclaration: false 515 | ignoreConstantDeclaration: true 516 | ignoreCompanionObjectPropertyDeclaration: true 517 | ignoreAnnotation: false 518 | ignoreNamedArgument: true 519 | ignoreEnums: false 520 | BracesOnIfStatements: 521 | active: true 522 | singleLine: always 523 | multiLine: always 524 | MaxLineLength: 525 | active: true 526 | maxLineLength: 120 527 | excludePackageStatements: true 528 | excludeImportStatements: true 529 | excludeCommentStatements: false 530 | MayBeConst: 531 | active: true 532 | ModifierOrder: 533 | active: true 534 | MultilineLambdaItParameter: 535 | active: true 536 | NestedClassesVisibility: 537 | active: false 538 | # Use FinalNewLine instead. 539 | NewLineAtEndOfFile: 540 | active: false 541 | NoTabs: 542 | active: false 543 | ObjectLiteralToLambda: 544 | active: true 545 | OptionalAbstractKeyword: 546 | active: true 547 | OptionalUnit: 548 | active: false 549 | PreferToOverPairSyntax: 550 | active: true 551 | ProtectedMemberInFinalClass: 552 | active: true 553 | RedundantVisibilityModifierRule: 554 | active: true 555 | ReturnCount: 556 | active: false 557 | max: 2 558 | excludedFunctions: [equals] 559 | excludeLabeled: false 560 | excludeReturnFromLambda: true 561 | SafeCast: 562 | active: true 563 | SerialVersionUIDInSerializableClass: 564 | active: false 565 | SpacingBetweenPackageAndImports: 566 | active: true 567 | ThrowsCount: 568 | active: true 569 | max: 2 570 | TrailingWhitespace: 571 | active: true 572 | UnnecessaryFilter: 573 | active: true 574 | UnderscoresInNumericLiterals: 575 | active: false 576 | UnnecessaryAbstractClass: 577 | active: false # Gradle requires this :sad: 578 | UnnecessaryApply: 579 | active: false 580 | UnnecessaryInheritance: 581 | active: true 582 | UnnecessaryAnnotationUseSiteTarget: 583 | active: true 584 | UnnecessaryLet: 585 | active: true 586 | UnnecessaryParentheses: 587 | active: true 588 | UntilInsteadOfRangeTo: 589 | active: true 590 | UnusedImports: 591 | # Has false positives with type resolution enabled. Redundant with NoUnusedImports rule. 592 | active: false 593 | UnusedPrivateClass: 594 | active: false 595 | UnusedPrivateMember: 596 | active: true 597 | allowedNames: (_|i|ignored|expected|serialVersionUID) 598 | UseAnyOrNoneInsteadOfFind: 599 | active: true 600 | UseCheckNotNull: 601 | active: true 602 | UseCheckOrError: 603 | active: true 604 | UseDataClass: 605 | active: true 606 | ignoreAnnotated: [""] 607 | UseIfInsteadOfWhen: 608 | active: true 609 | UseIsNullOrEmpty: 610 | active: true 611 | UseOrEmpty: 612 | active: true 613 | UseRequire: 614 | active: true 615 | UseRequireNotNull: 616 | active: true 617 | UselessCallOnNotNull: 618 | active: true 619 | UtilityClassWithPublicConstructor: 620 | active: true 621 | VarCouldBeVal: 622 | active: true 623 | ignoreAnnotated: [Column, Inject, JoinColumn, OneToMany, Parameter] 624 | WildcardImport: 625 | active: true 626 | excludeImports: [java.util.*, kotlinx.android.synthetic.*] 627 | UnusedPrivateProperty: 628 | active: true 629 | allowedNames: _|ignored|expected|serialVersionUID 630 | UnusedParameter: 631 | active: true 632 | 633 | coroutines: 634 | active: true 635 | GlobalCoroutineUsage: 636 | active: true 637 | InjectDispatcher: 638 | active: true 639 | SuspendFunWithCoroutineScopeReceiver: 640 | active: true 641 | 642 | FaireRuleSet: 643 | active: true 644 | AlwaysUseIsTrueOrIsFalse: 645 | active: true 646 | autoCorrect: true 647 | DoNotAccessVisibleForTesting: 648 | active: true 649 | excludes: ["**/*Test.kt"] 650 | DoNotSplitByRegex: 651 | active: true 652 | excludes: ["**/*Test.kt"] 653 | DoNotUseDirectReceiverReferenceInsideWith: 654 | active: true 655 | DoNotUseHasSizeForEmptyListInAssert: 656 | active: true 657 | autoCorrect: true 658 | DoNotUseIsEqualToWhenArgumentIsOne: 659 | active: true 660 | autoCorrect: true 661 | DoNotUseIsEqualToWhenArgumentIsZero: 662 | active: true 663 | autoCorrect: true 664 | DoNotUsePropertyAccessInAssert: 665 | active: true 666 | autoCorrect: true 667 | DoNotUseSingleOnFilter: 668 | active: true 669 | autoCorrect: true 670 | DoNotUseSizePropertyInAssert: 671 | active: true 672 | GetOrDefaultShouldBeReplacedWithGetOrElse: 673 | active: true 674 | NoNonPrivateGlobalVariables: 675 | active: true 676 | NoNullableLambdaWithDefaultNull: 677 | active: true 678 | NoPairWithAmbiguousTypes: 679 | active: true 680 | PreferIgnoreCase: 681 | active: true 682 | autoCorrect: true 683 | PreventBannedImports: 684 | active: true 685 | autoCorrect: true 686 | # Reminder: add relevant entries to .idea/codeInsightSettings.xml, too, 687 | # so IntelliJ does not suggest them in autocomplete. 688 | withAlternatives: 689 | - com.github.jgonian.ipmath.Optional=java.util.Optional 690 | - com.google.common.base.Optional=java.util.Optional 691 | 692 | # Injection annotations 693 | - com.google.inject.BindingAnnotation=jakarta.inject.Qualifier 694 | - com.google.inject.Inject=jakarta.inject.Inject 695 | - com.google.inject.ScopeAnnotation=jakarta.inject.Scope 696 | - com.google.inject.Singleton=jakarta.inject.Singleton 697 | 698 | - javax.inject.Inject=jakarta.inject.Inject 699 | - javax.inject.Named=jakarta.inject.Named 700 | - javax.inject.Provider=jakarta.inject.Provider 701 | - javax.inject.Scope=jakarta.inject.Scope 702 | - javax.inject.Singleton=jakarta.inject.Singleton 703 | - javax.inject.Qualifier=jakarta.inject.Qualifier 704 | 705 | - jakarta.ws.rs=javax.ws.rs 706 | - java.lang.Integer.max=kotlin.math.max 707 | - java.lang.Integer.min=kotlin.math.min 708 | - java.lang.long.max=kotlin.math.max 709 | - java.lang.long.min=kotlin.math.min 710 | - net.bytebuddy.dynamic.DynamicType.Builder.FieldDefinition.Optional=java.util.Optional 711 | - net.bytebuddy.dynamic.DynamicType.Builder.MethodDefinition.ImplementationDefinition.Optional=java.util.Optional 712 | - net.bytebuddy.dynamic.DynamicType.Builder.RecordComponentDefinition.Optional=java.util.Optional 713 | - org.apache.commons.lang.time.StopWatch=com.google.common.base.Stopwatch 714 | 715 | ReturnValueOfLetMustBeUsed: 716 | active: true 717 | UseEntriesInsteadOfValuesOnEnum: 718 | active: true 719 | autoCorrect: false 720 | UseFirstOrNullInsteadOfFind: 721 | active: true 722 | autoCorrect: true 723 | UseMapNotNullInsteadOfFilterNotNull: 724 | active: true 725 | autoCorrect: true 726 | UseOfCollectionInsteadOfEmptyCollection: 727 | active: true 728 | autoCorrect: true 729 | UseSetInsteadOfListToSet: 730 | active: true 731 | autoCorrect: true 732 | 733 | compiler: 734 | CompilerWarning: 735 | active: true 736 | -------------------------------------------------------------------------------- /.gitleaks.toml: -------------------------------------------------------------------------------- 1 | # Gitleaks rules 2 | 3 | title = "gitleaks config" 4 | 5 | [allowlist] 6 | description = "global allow lists" 7 | regexTarget = "line" 8 | regexes = [ 9 | '''219-09-9999''', 10 | '''078-05-1120''', 11 | '''(9[0-9]{2}|666)-\d{2}-\d{4}''', 12 | '''pub[a-zA-Z0-9]+''', 13 | '''[0-9]+\.[0-9]+\.[0-9]+-''', # version code 14 | '''[a-zA-Z0-9_-]*NOTAKEY[a-zA-Z0-9_-]*''', # Generic allowance for test keys 15 | '''gitleaks:ignore''', # gitleaks ignore comments 16 | ] 17 | paths = [ 18 | '''gitleaks.toml''', 19 | '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', # ignore file blobs 20 | '''gradle/libs.versions.toml''', # This is a build file that only contains build versions 21 | ] 22 | commits = [] 23 | 24 | [[rules]] 25 | description = "Generic API Key" 26 | id = "generic-api-key" 27 | regex = '''(?i)(?:key|api[^Version]|token|pat|secret|client|password|auth)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9a-z\-_.=]{10,150})['|\"|\n|\r|\s|\x60]''' 28 | secretGroup = 1 29 | entropy = 3.7 30 | keywords = [ 31 | "key", 32 | "api", 33 | "token", 34 | "secret", 35 | "client", 36 | "pat", 37 | "password", 38 | "auth", 39 | ] 40 | [rules.allowlist] 41 | regexes = [ 42 | '''[a-zA-Z0-9_-]*NOTAKEY[a-zA-Z0-9_-]*''', 43 | ] 44 | paths = [ 45 | '''.*\.kt$''', # ignore this definition in kotlin files, see below for kotlin file definition 46 | ] 47 | 48 | [[rules]] 49 | description = "Generic API Key in Kotlin String assignment" 50 | id = "generic-api-key-kotlin-string-assignment" 51 | regex = '''(?i)(?:key|api[^Version]|token|pat|secret|client|password|auth)(?:[0-9a-z\-_\s.]{0,20})(?:=|==)(?:[\s]{0,20})"([0-9a-z\-_.=]{10,150})"''' 52 | secretGroup = 1 53 | entropy = 3.7 54 | keywords = [ 55 | "key", 56 | "api", 57 | "token", 58 | "secret", 59 | "client", 60 | "pat", 61 | "password", 62 | "auth", 63 | ] 64 | paths = [ 65 | '''.*\.kt$''', # only do this in kotlin files 66 | ] 67 | [rules.allowlist] 68 | regexes = [ 69 | '''"[a-zA-Z0-9_]+(\.tsv)?\.gz"''', # data set file names 70 | '''[a-zA-Z0-9_-]*NOTAKEY[a-zA-Z0-9_-]*''', # Generic allowance for test keys 71 | ] 72 | stopwords = [] 73 | 74 | [[rules]] 75 | description = "Generic API Key in Kotlin String argument" 76 | id = "generic-api-key-kotlin-string-argument" 77 | regex = '''(?i)(?:key|api[^Version]|token|pat|secret|client|password|auth)(?:[0-9a-z\-_.<>]{0,20})(?:[\(\s]{0,20})"([0-9a-z\-_.=]{10,150})"[,\)]''' 78 | secretGroup = 1 79 | entropy = 3.7 80 | keywords = [ 81 | "key", 82 | "api", 83 | "token", 84 | "secret", 85 | "client", 86 | "pat", 87 | "password", 88 | "auth", 89 | ] 90 | paths = [ 91 | '''.*\.kt$''', # only do this in kotlin files 92 | ] 93 | [rules.allowlist] 94 | regexes = [ 95 | '''[a-zA-Z0-9_-]*NOTAKEY[a-zA-Z0-9_-]*''', # Generic allowance for test keys 96 | ] 97 | stopwords = [] 98 | commits = [] 99 | 100 | [[rules]] 101 | description = "Age secret key" 102 | id = "age secret key" 103 | regex = '''AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}''' 104 | keywords = ["AGE-SECRET-KEY-1"] 105 | 106 | [[rules]] 107 | description = "Adobe Client ID (Oauth Web)" 108 | id = "adobe-client-id" 109 | regex = '''(?i)(?:adobe)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})['|\"|\n|\r|\s|\x60]''' 110 | secretGroup = 1 111 | keywords = ["adobe"] 112 | 113 | [[rules]] 114 | description = "Adobe Client Secret" 115 | id = "adobe-client-secret" 116 | regex = '''(p8e-)(?i)[a-z0-9]{32}''' 117 | keywords = ["p8e-"] 118 | 119 | [[rules]] 120 | description = "Alibaba AccessKey ID" 121 | id = "alibaba-access-key-id" 122 | regex = '''(LTAI)(?i)[a-z0-9]{20}''' 123 | keywords = ["LTAI"] 124 | 125 | [[rules]] 126 | description = "Alibaba Secret Key" 127 | id = "alibaba-secret-key" 128 | regex = '''(?i)(?:alibaba)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})['|\"|\n|\r|\s|\x60]''' 129 | secretGroup = 1 130 | keywords = ["alibaba"] 131 | 132 | [[rules]] 133 | description = "Asana Client ID" 134 | id = "asana-client-id" 135 | regex = '''(?i)(?:asana)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9]{16})['|\"|\n|\r|\s|\x60]''' 136 | secretGroup = 1 137 | keywords = ["asana"] 138 | 139 | [[rules]] 140 | description = "Asana Client Secret" 141 | id = "asana-client-secret" 142 | regex = '''(?i)(?:asana)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})['|\"|\n|\r|\s|\x60]''' 143 | keywords = ["asana"] 144 | 145 | [[rules]] 146 | description = "Atlassian API token" 147 | id = "atlassian-api-token" 148 | regex = '''(?i)(?:atlassian)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})['|\"|\n|\r|\s|\x60]''' 149 | secretGroup = 1 150 | keywords = ["atlassian"] 151 | 152 | [[rules]] 153 | description = "AWS" 154 | id = "aws-access-token" 155 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' 156 | keywords = ["AKIA", "AGPA", "AIDA", "AROA", "AIPA", "ANPA", "ANVA", "ASIA"] 157 | 158 | [[rules]] 159 | description = "BitBucket Client ID" 160 | id = "bitbucket-client-id" 161 | regex = '''(?i)(?:bitbucket)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})['|\"|\n|\r|\s|\x60]''' 162 | secretGroup = 1 163 | keywords = ["bitbucket"] 164 | 165 | [[rules]] 166 | description = "BitBucket Client Secret" 167 | id = "bitbucket-client-secret" 168 | regex = '''(?i)(?:bitbucket)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_\-]{64})['|\"|\n|\r|\s|\x60]''' 169 | secretGroup = 1 170 | keywords = ["bitbucket"] 171 | 172 | [[rules]] 173 | description = "Beamer API token" 174 | id = "beamer-api-token" 175 | regex = '''(?i)(?:beamer)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(b_[a-z0-9=_\-]{44})['|\"|\n|\r|\s|\x60]''' 176 | secretGroup = 1 177 | keywords = ["beamer"] 178 | 179 | [[rules]] 180 | description = "Clojars API token" 181 | id = "clojars-api-token" 182 | regex = '''(CLOJARS_)(?i)[a-z0-9]{60}''' 183 | keywords = ["clojars"] 184 | 185 | [[rules]] 186 | description = "Contentful delivery API token" 187 | id = "contentful-delivery-api-token" 188 | regex = '''(?i)(?:contentful)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9\-=_]{43})['|\"|\n|\r|\s|\x60]''' 189 | secretGroup = 1 190 | keywords = ["contentful"] 191 | 192 | [[rules]] 193 | description = "Databricks API token" 194 | id = "databricks-api-token" 195 | regex = '''dapi[a-h0-9]{32}''' 196 | keywords = ["dapi"] 197 | 198 | [[rules]] 199 | description = "Discord API key" 200 | id = "discord-api-token" 201 | regex = '''(?i)(?:discord)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{64})['|\"|\n|\r|\s|\x60]''' 202 | secretGroup = 1 203 | keywords = ["discord"] 204 | 205 | [[rules]] 206 | description = "Discord client ID" 207 | id = "discord-client-id" 208 | regex = '''(?i)(?:discord)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9]{18})['|\"|\n|\r|\s|\x60]''' 209 | secretGroup = 1 210 | keywords = ["discord"] 211 | 212 | [[rules]] 213 | description = "Discord client secret" 214 | id = "discord-client-secret" 215 | regex = '''(?i)(?:discord)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})['|\"|\n|\r|\s|\x60]''' 216 | secretGroup = 1 217 | keywords = ["discord"] 218 | 219 | [[rules]] 220 | description = "Dropbox API secret" 221 | id = "doppler-api-token" 222 | regex = '''(?i)(?:dropbox)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{15})['|\"|\n|\r|\s|\x60]''' 223 | secretGroup = 1 224 | keywords = ["dropbox"] 225 | 226 | [[rules]] 227 | description = "Dropbox long lived API token" 228 | id = "dropbox-long-lived-api-token" 229 | regex = '''(?i)(?:dropbox)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43})['|\"|\n|\r|\s|\x60]''' 230 | keywords = ["dropbox"] 231 | 232 | [[rules]] 233 | description = "Dropbox short lived API token" 234 | id = "dropbox-short-lived-api-token" 235 | regex = '''(?i)(?:dropbox)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(sl\.[a-z0-9\-=_]{135})['|\"|\n|\r|\s|\x60]''' 236 | keywords = ["dropbox"] 237 | 238 | [[rules]] 239 | description = "Doppler API token" 240 | id = "doppler-api-token" 241 | regex = '''(dp\.pt\.)(?i)[a-z0-9]{43}''' 242 | keywords = ["doppler"] 243 | 244 | [[rules]] 245 | description = "Duffel API token" 246 | id = "duffel-api-token" 247 | regex = '''duffel_(test|live)_(?i)[a-z0-9_\-=]{43}''' 248 | keywords = ["duffel"] 249 | 250 | [[rules]] 251 | description = "Dynatrace API token" 252 | id = "dynatrace-api-token" 253 | regex = '''dt0c01\.(?i)[a-z0-9]{24}\.[a-z0-9]{64}''' 254 | keywords = ["dynatrace"] 255 | 256 | [[rules]] 257 | description = "EasyPost API token" 258 | id = "easypost-api-token" 259 | regex = '''EZAK(?i)[a-z0-9]{54}''' 260 | keywords = ["EZAK"] 261 | 262 | [[rules]] 263 | description = "EasyPost test API token" 264 | id = "easypost-test-api-token" 265 | regex = '''EZTK(?i)[a-z0-9]{54}''' 266 | keywords = ["EZTK"] 267 | 268 | [[rules]] 269 | description = "facebook" 270 | id = "facebook" 271 | regex = '''(?i)(?:facebook)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})['|\"|\n|\r|\s|\x60]''' 272 | secretGroup = 1 273 | keywords = ["facebook"] 274 | 275 | [[rules]] 276 | description = "Fastly API key" 277 | id = "fastly-api-token" 278 | regex = '''(?i)(?:fastly)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})['|\"|\n|\r|\s|\x60]''' 279 | secretGroup = 1 280 | keywords = ["fastly"] 281 | 282 | [[rules]] 283 | description = "Finicity Client Secret" 284 | id = "finicity-client-secret" 285 | regex = '''(?i)(?:finicity)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{20})['|\"|\n|\r|\s|\x60]''' 286 | secretGroup = 1 287 | keywords = ["finicity"] 288 | 289 | [[rules]] 290 | description = "Finicity API token" 291 | id = "finicity-api-token" 292 | regex = '''(?i)(?:finicity)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})['|\"|\n|\r|\s|\x60]''' 293 | secretGroup = 1 294 | keywords = ["finicity"] 295 | 296 | [[rules]] 297 | description = "Finicity Public Key" 298 | id = "flutterwave-public-key" 299 | regex = '''FLWPUBK_TEST-(?i)[a-h0-9]{32}-X''' 300 | keywords = ["FLWPUBK_TEST"] 301 | 302 | [[rules]] 303 | description = "Finicity Secret Key" 304 | id = "flutterwave-public-key" 305 | regex = '''FLWSECK_TEST-(?i)[a-h0-9]{32}-X''' 306 | keywords = ["FLWSECK_TEST"] 307 | 308 | [[rules]] 309 | description = "Finicity Secret Key" 310 | id = "flutterwave-public-key" 311 | regex = '''FLWSECK_TEST-(?i)[a-h0-9]{32}-X''' 312 | keywords = ["FLWSECK_TEST"] 313 | 314 | [[rules]] 315 | description = "Frame.io API token" 316 | id = "frameio-api-token" 317 | regex = '''fio-u-(?i)[a-z0-9\-_=]{64}''' 318 | keywords = ["fio-u-"] 319 | 320 | [[rules]] 321 | description = "GoCardless API token" 322 | id = "gocardless-api-token" 323 | regex = '''(?i)(?:gocardless)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(live_(?i)[a-z0-9\-_=]{40})['|\"|\n|\r|\s|\x60]''' 324 | keywords = ["live_", "gocardless"] 325 | 326 | [[rules]] 327 | description = "GitHub Personal Access Token" 328 | id = "github-pat" 329 | regex = '''ghp_[0-9a-zA-Z]{36}''' 330 | keywords = ["ghp_"] 331 | 332 | [[rules]] 333 | description = "GitHub OAuth Access Token" 334 | id = "github-oauth" 335 | regex = '''gho_[0-9a-zA-Z]{36}''' 336 | keywords = ["gho_"] 337 | 338 | [[rules]] 339 | description = "GitHub App Token" 340 | id = "github-app-token" 341 | regex = '''(ghu|ghs)_[0-9a-zA-Z]{36}''' 342 | keywords = ["ghu_", "ghs_"] 343 | 344 | [[rules]] 345 | description = "GitHub Refresh Token" 346 | id = "github-refresh-token" 347 | regex = '''ghr_[0-9a-zA-Z]{36}''' 348 | keywords = ["ghr_"] 349 | 350 | [[rules]] 351 | description = "Gitlab Personal Access Token" 352 | id = "gitlab-pat" 353 | regex = '''glpat-[0-9a-zA-Z\-\_]{20}''' 354 | keywords = ["glpat-"] 355 | 356 | [[rules]] 357 | description = "HashiCorp Terraform user/org API token" 358 | id = "hashicorp-tf-api-token" 359 | regex = '''(?i)[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}''' 360 | keywords = ["atlasv1"] 361 | 362 | [[rules]] 363 | description = "Heroku API Key" 364 | id = "heroku-api-key" 365 | regex = '''(?i)(?:heroku)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})['|\"|\n|\r|\s|\x60]''' 366 | secretGroup = 1 367 | keywords = ["heroku"] 368 | 369 | [[rules]] 370 | description = "HubSpot API Token" 371 | id = "hubspot-api-key" 372 | regex = '''(?i)(?:hubspot)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})['|\"|\n|\r|\s|\x60]''' 373 | secretGroup = 1 374 | keywords = ["hubspot"] 375 | 376 | [[rules]] 377 | description = "Intercom API Token" 378 | id = "intercom-api-key" 379 | regex = '''(?i)(?:intercom)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_\-]{60})['|\"|\n|\r|\s|\x60]''' 380 | secretGroup = 1 381 | keywords = ["intercom"] 382 | 383 | [[rules]] 384 | description = "Linear API Token" 385 | id = "linear-api-key" 386 | regex = '''lin_api_(?i)[a-z0-9]{40}''' 387 | keywords = ["lin_api_"] 388 | 389 | [[rules]] 390 | description = "Linear Client Secret" 391 | id = "linear-client-secret" 392 | regex = '''(?i)(?:linear)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})['|\"|\n|\r|\s|\x60]''' 393 | keywords = ["linear"] 394 | 395 | [[rules]] 396 | description = "LinkedIn Client ID" 397 | id = "linkedin-client-id" 398 | regex = '''(?i)(?:linkedin|linked-in)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{14})['|\"|\n|\r|\s|\x60]''' 399 | secretGroup = 1 400 | keywords = ["linkedin", "linked-in"] 401 | 402 | [[rules]] 403 | description = "LinkedIn Client secret" 404 | id = "linkedin-client-secret" 405 | regex = '''(?i)(?:linkedin|linked-in)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{16})['|\"|\n|\r|\s|\x60]''' 406 | secretGroup = 1 407 | keywords = ["linkedin", "linked-in"] 408 | 409 | [[rules]] 410 | description = "Lob API Key" 411 | id = "lob-api-key" 412 | regex = '''(?i)(?:lob)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}((live|test)_[a-f0-9]{35})['|\"|\n|\r|\s|\x60]''' 413 | keywords = ["test_", "live_"] 414 | 415 | [[rules]] 416 | description = "Lob Publishable API Key" 417 | id = "lob-pub-api-key" 418 | regex = '''(?i)(?:lob)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}((test|live)_pub_[a-f0-9]{31})['|\"|\n|\r|\s|\x60]''' 419 | keywords = ["test_pub", "live_pub", "_pub"] 420 | 421 | [[rules]] 422 | description = "Mailchimp API key" 423 | id = "mailchimp-api-key" 424 | regex = '''(?i)(?:mailchimp)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32}-us20)['|\"|\n|\r|\s|\x60]''' 425 | secretGroup = 1 426 | keywords = ["mailchimp"] 427 | 428 | [[rules]] 429 | description = "Mailgun public validation key" 430 | id = "mailgun-pub-key" 431 | regex = '''(?i)(?:mailgun)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(pubkey-[a-f0-9]{32})['|\"|\n|\r|\s|\x60]''' 432 | secretGroup = 1 433 | keywords = ["mailgun"] 434 | 435 | [[rules]] 436 | description = "Mailgun private API token" 437 | id = "mailgun-private-api-token" 438 | regex = '''(?i)(?:mailgun)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(key-[a-f0-9]{32})['|\"|\n|\r|\s|\x60]''' 439 | secretGroup = 1 440 | keywords = ["mailgun"] 441 | 442 | [[rules]] 443 | description = "Mailgun webhook signing key" 444 | id = "mailgun-signing-key" 445 | regex = '''(?i)(?:mailgun)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})['|\"|\n|\r|\s|\x60]''' 446 | secretGroup = 1 447 | keywords = ["mailgun"] 448 | 449 | [[rules]] 450 | description = "MapBox API token" 451 | id = "mapbox-api-token" 452 | regex = '''(?i)(?:mapbox)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(pk\.[a-z0-9]{60}\.[a-z0-9]{22})['|\"|\n|\r|\s|\x60]''' 453 | secretGroup = 1 454 | keywords = ["mapbox"] 455 | 456 | [[rules]] 457 | description = "MessageBird API token" 458 | id = "messagebird-api-token" 459 | regex = '''(?i)(?:messagebird|message-bird|message_bird)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{25})['|\"|\n|\r|\s|\x60]''' 460 | secretGroup = 1 461 | keywords = ["messagebird", "message-bird", "message_bird"] 462 | 463 | [[rules]] 464 | description = "MessageBird client ID" 465 | id = "messagebird-client-id" 466 | regex = '''(?i)(?:messagebird|message-bird|message_bird)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-h0-9]{8}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{12})['|\"|\n|\r|\s|\x60]''' 467 | secretGroup = 1 468 | keywords = ["messagebird", "message-bird", "message_bird"] 469 | 470 | [[rules]] 471 | description = "New Relic user API Key" 472 | id = "new-relic-user-api-key" 473 | regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(NRAK-[a-z0-9]{27})['|\"|\n|\r|\s|\x60]''' 474 | secretGroup = 1 475 | keywords = ["NRAK"] 476 | 477 | [[rules]] 478 | description = "New Relic user API ID" 479 | id = "new-relic-user-api-id" 480 | regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})['|\"|\n|\r|\s|\x60]''' 481 | secretGroup = 1 482 | keywords = ["new-relic", "newrelic", "new_relic"] 483 | 484 | [[rules]] 485 | description = "New Relic ingest browser API token" 486 | id = "new-relic-browser-api-token" 487 | regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(NRJS-[a-f0-9]{19})['|\"|\n|\r|\s|\x60]''' 488 | secretGroup = 1 489 | keywords = ["NRJS-"] 490 | 491 | [[rules]] 492 | description = "npm access token" 493 | id = "npm-access-token" 494 | regex = '''(?i)\b(npm_[a-z0-9]{36})['|\"|\n|\r|\s|\x60]''' 495 | secretGroup = 1 496 | keywords = ["npm_"] 497 | 498 | [[rules]] 499 | description = "PlanetScale password" 500 | id = "planetscale-password" 501 | regex = '''(?i)\b(pscale_pw_(?i)[a-z0-9=\-_\.]{43})['|\"|\n|\r|\s|\x60]''' 502 | secretGroup = 1 503 | keywords = ["pscale_pw_"] 504 | 505 | [[rules]] 506 | description = "PlanetScale API token" 507 | id = "planetscale-api-token" 508 | regex = '''(?i)\b(pscale_tkn_(?i)[a-z0-9=\-_\.]{43})['|\"|\n|\r|\s|\x60]''' 509 | secretGroup = 1 510 | keywords = ["pscale_tkn_"] 511 | 512 | [[rules]] 513 | description = "Postman API token" 514 | id = "postman-api-token" 515 | regex = '''(?i)\b(PMAK-(?i)[a-f0-9]{24}\-[a-f0-9]{34})['|\"|\n|\r|\s|\x60]''' 516 | secretGroup = 1 517 | keywords = ["PMAK-"] 518 | 519 | [[rules]] 520 | description = "Private Key" 521 | id = "private-key" 522 | regex = '''(?i)-----\s*?BEGIN[ A-Z0-9_-]*?PRIVATE KEY\s*?-----[\s\S]*?----\s*?END[ A-Z0-9_-]*? PRIVATE KEY\s*?-----''' 523 | keywords = ["-----BEGIN PRIVATE"] 524 | 525 | [[rules]] 526 | description = "Pulumi API token" 527 | id = "pulumi-api-token" 528 | regex = '''(?i)\b(pul-[a-f0-9]{40})['|\"|\n|\r|\s|\x60]''' 529 | secretGroup = 1 530 | keywords = ["pul-"] 531 | 532 | [[rules]] 533 | description = "PyPI upload token" 534 | id = "pypi-upload-token" 535 | regex = '''pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}''' 536 | keywords = ["pypi-AgEIcHlwaS5vcmc"] 537 | 538 | [[rules]] 539 | description = "Rubygem API token" 540 | id = "rubygems-api-token" 541 | regex = '''(?i)\b(rubygems_[a-f0-9]{48})['|\"|\n|\r|\s|\x60]''' 542 | secretGroup = 1 543 | keywords = ["rubygems_"] 544 | 545 | [[rules]] 546 | description = "SendGrid API token" 547 | id = "sendgrid-api-token" 548 | regex = '''(?i)\b(SG\.(?i)[a-z0-9=_\-\.]{66})['|\"|\n|\r|\s|\x60]''' 549 | secretGroup = 1 550 | keywords = ["SG."] 551 | 552 | [[rules]] 553 | description = "Sendinblue API token" 554 | id = "sendinblue-api-token" 555 | regex = '''(?i)\b(xkeysib-[a-f0-9]{64}\-(?i)[a-z0-9]{16})['|\"|\n|\r|\s|\x60]''' 556 | secretGroup = 1 557 | keywords = ["xkeysib-"] 558 | 559 | [[rules]] 560 | description = "Shippo API token" 561 | id = "shippo-api-token" 562 | regex = '''(?i)\b(shippo_(live|test)_[a-f0-9]{40})['|\"|\n|\r|\s|\x60]''' 563 | secretGroup = 1 564 | keywords = ["shippo_"] 565 | 566 | [[rules]] 567 | description = "Shopify access token" 568 | id = "shopify-access-token" 569 | regex = '''shpat_[a-fA-F0-9]{32}''' 570 | keywords = ["shpat_"] 571 | 572 | [[rules]] 573 | description = "Shopify custom access token" 574 | id = "shopify-custom-access-token" 575 | regex = '''shpca_[a-fA-F0-9]{32}''' 576 | keywords = ["shpca_"] 577 | 578 | [[rules]] 579 | description = "Shopify private app access token" 580 | id = "shopify-private-app-access-token" 581 | regex = '''shppa_[a-fA-F0-9]{32}''' 582 | keywords = ["shppa_"] 583 | 584 | [[rules]] 585 | description = "Shopify shared secret" 586 | id = "shopify-shared-secret" 587 | regex = '''shpss_[a-fA-F0-9]{32}''' 588 | keywords = ["shpss_"] 589 | 590 | [[rules]] 591 | description = "Slack token" 592 | id = "slack-access-token" 593 | regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})''' 594 | keywords = ["xoxb", "xoxa", "xoxp", "xoxr", "xoxs"] 595 | 596 | [[rules]] 597 | description = "Slack Webhook" 598 | id = "slack-web-hook" 599 | regex = '''https:\/\/hooks.slack.com\/services\/[A-Za-z0-9+\/]{44,46}''' 600 | keywords = ["hooks.slack.com"] 601 | 602 | [[rules]] 603 | description = "Stripe Live keys" 604 | id = "stripe-access-token" 605 | regex = '''(?i)(sk|pk)_live_[0-9a-z]{10,32}''' 606 | keywords = ["sk_test", "pk_test", "sk_live", "pk_live"] 607 | 608 | [[rules]] 609 | description = "Twilio API Key" 610 | id = "twilio-api-key" 611 | regex = '''SK[0-9a-fA-F]{32}''' 612 | keywords = ["twilio"] 613 | 614 | [[rules]] 615 | description = "Twitch API token" 616 | id = "twitch-api-token" 617 | regex = '''(?i)(?:twitch)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})['|\"|\n|\r|\s|\x60]''' 618 | secretGroup = 1 619 | keywords = ["twitch"] 620 | 621 | [[rules]] 622 | description = "twitter" 623 | id = "twitter" 624 | regex = '''(?i)(?:twitter)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{35,44})['|\"|\n|\r|\s|\x60]''' 625 | secretGroup = 1 626 | keywords = ["twitter"] 627 | 628 | [[rules]] 629 | description = "Typeform API token" 630 | id = "typeform-api-token" 631 | regex = '''(?i)(?:typeform)(?:[0-9a-z\-_\s.]{0,20})(?:'|"){0,1}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(tfp_[a-z0-9\-_\.=]{59})['|\"|\n|\r|\s|\x60]''' 632 | secretGroup = 1 633 | keywords = ["tfp_"] 634 | --------------------------------------------------------------------------------