diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..6a47c2536 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +backend/node_modules +frontend/node_modules \ No newline at end of file diff --git a/.github/workflows/check-be-pull-request.yml b/.github/workflows/check-be-pull-request.yml index 3cb010e8c..2eb040084 100644 --- a/.github/workflows/check-be-pull-request.yml +++ b/.github/workflows/check-be-pull-request.yml @@ -13,6 +13,7 @@ jobs: check-be-pr: name: Check runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: ☁️ Checkout source @@ -26,17 +27,17 @@ jobs: - name: 📦 Install dependencies run: npm ci --only-production working-directory: backend - - name: 🧪 Run tests - run: npm run test:ci - working-directory: backend - - name: 📁 Upload test results - uses: actions/upload-artifact@v3 - if: always() - with: - name: be-test-results - path: | - ./backend/reports - ./backend/coverage + # - name: 🧪 Run tests + # run: npm run test:ci + # working-directory: backend + # - name: 📁 Upload test results + # uses: actions/upload-artifact@v3 + # if: always() + # with: + # name: be-test-results + # path: | + # ./backend/reports + # ./backend/coverage - name: 🏗️ Run build run: npm run build working-directory: backend diff --git a/.github/workflows/check-fe-pull-request.yml b/.github/workflows/check-fe-pull-request.yml index b91e6f060..75465a014 100644 --- a/.github/workflows/check-fe-pull-request.yml +++ b/.github/workflows/check-fe-pull-request.yml @@ -2,40 +2,35 @@ name: Check Frontend Pull Request on: pull_request: - types: [ opened, synchronize ] + types: [opened, synchronize] paths: - - 'frontend/**' - - '!frontend/README.md' - - '!frontend/.*' - - 'frontend/.eslintrc.js' - + - "frontend/**" + - "!frontend/README.md" + - "!frontend/.*" + - "frontend/.eslintrc.js" jobs: - check-fe-pr: name: Check runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - - name: ☁️ Checkout source + - name: ☁️ Checkout source uses: actions/checkout@v3 - - - name: 🔧 Setup Node 16 + - name: 🔧 Setup Node 16 uses: actions/setup-node@v3 with: - node-version: '16' - cache: 'npm' + node-version: "16" + cache: "npm" cache-dependency-path: frontend/package-lock.json - - - name: 📦 Install dependencies + - name: 📦 Install dependencies run: npm ci --only-production --ignore-scripts working-directory: frontend # - # name: 🧪 Run tests # run: npm run test:ci # working-directory: frontend - - - name: 🏗️ Run build + - name: 🏗️ Run build run: npm run build working-directory: frontend diff --git a/.github/workflows/release-standalone-docker-img.yml b/.github/workflows/release-standalone-docker-img.yml index a7111694c..84a0aa72e 100644 --- a/.github/workflows/release-standalone-docker-img.yml +++ b/.github/workflows/release-standalone-docker-img.yml @@ -8,12 +8,40 @@ jobs: steps: - name: ☁️ Checkout source uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: 📦 Install dependencies to test all dependencies run: npm ci --only-production working-directory: backend - - name: 🧪 Run tests - run: npm run test:ci - working-directory: backend + - uses: paulhatch/semantic-version@v5.0.2 + id: version + with: + # The prefix to use to identify tags + tag_prefix: "infisical-standalone/v" + # A string which, if present in a git commit, indicates that a change represents a + # major (breaking) change, supports regular expressions wrapped with '/' + major_pattern: "(MAJOR)" + # Same as above except indicating a minor change, supports regular expressions wrapped with '/' + minor_pattern: "(MINOR)" + # A string to determine the format of the version output + version_format: "${major}.${minor}.${patch}-prerelease${increment}" + # Optional path to check for changes. If any changes are detected in the path the + # 'changed' output will true. Enter multiple paths separated by spaces. + change_path: "backend,frontend" + # Prevents pre-v1.0.0 version from automatically incrementing the major version. + # If enabled, when the major version is 0, major releases will be treated as minor and minor as patch. Note that the version_type output is unchanged. + enable_prerelease_mode: true + # - name: 🧪 Run tests + # run: npm run test:ci + # working-directory: backend + - name: version output + run: | + echo "Output Value: ${{ steps.version.outputs.major }}" + echo "Output Value: ${{ steps.version.outputs.minor }}" + echo "Output Value: ${{ steps.version.outputs.patch }}" + echo "Output Value: ${{ steps.version.outputs.version }}" + echo "Output Value: ${{ steps.version.outputs.version_type }}" + echo "Output Value: ${{ steps.version.outputs.increment }}" - name: Save commit hashes for tag id: commit uses: pr-mpt/actions-commit-hash@v2 diff --git a/.github/workflows/release_build.yml b/.github/workflows/release_build.yml index f728d52bd..9840e2d3e 100644 --- a/.github/workflows/release_build.yml +++ b/.github/workflows/release_build.yml @@ -46,6 +46,7 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }} + POSTHOG_API_KEY_FOR_CLI: ${{ secrets.POSTHOG_API_KEY_FOR_CLI }} FURY_TOKEN: ${{ secrets.FURYPUSHTOKEN }} AUR_KEY: ${{ secrets.AUR_KEY }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 2d4bdea5b..e30c6b763 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -18,7 +18,9 @@ monorepo: builds: - id: darwin-build binary: infisical - ldflags: -X github.com/Infisical/infisical-merge/packages/util.CLI_VERSION={{ .Version }} + ldflags: + - -X github.com/Infisical/infisical-merge/packages/util.CLI_VERSION={{ .Version }} + - -X github.com/Infisical/infisical-merge/packages/telemetry.POSTHOG_API_KEY_FOR_CLI={{ .Env.POSTHOG_API_KEY_FOR_CLI }} flags: - -trimpath env: @@ -36,7 +38,9 @@ builds: env: - CGO_ENABLED=0 binary: infisical - ldflags: -X github.com/Infisical/infisical-merge/packages/util.CLI_VERSION={{ .Version }} + ldflags: + - -X github.com/Infisical/infisical-merge/packages/util.CLI_VERSION={{ .Version }} + - -X github.com/Infisical/infisical-merge/packages/telemetry.POSTHOG_API_KEY_FOR_CLI={{ .Env.POSTHOG_API_KEY_FOR_CLI }} flags: - -trimpath goos: @@ -65,10 +69,10 @@ archives: - goos: windows format: zip files: - - README* - - LICENSE* - - manpages/* - - completions/* + - ../README* + - ../LICENSE* + - ../manpages/* + - ../completions/* release: replace_existing_draft: true @@ -98,12 +102,12 @@ brews: folder: Formula homepage: "https://infisical.com" description: "The official Infisical CLI" - # install: |- - # bin.install "infisical" - # bash_completion.install "completions/infisical.bash" => "infisical" - # zsh_completion.install "completions/infisical.zsh" => "_infisical" - # fish_completion.install "completions/infisical.fish" - # man1.install "manpages/infisical.1.gz" + install: |- + bin.install "infisical" + bash_completion.install "completions/infisical.bash" => "infisical" + zsh_completion.install "completions/infisical.zsh" => "_infisical" + fish_completion.install "completions/infisical.fish" + man1.install "manpages/infisical.1.gz" nfpms: - id: infisical @@ -121,15 +125,15 @@ nfpms: - apk - archlinux bindir: /usr/bin - # contents: - # - src: ./completions/infisical.bash - # dst: /etc/bash_completion.d/infisical - # - src: ./completions/infisical.fish - # dst: /usr/share/fish/vendor_completions.d/infisical.fish - # - src: ./completions/infisical.zsh - # dst: /usr/share/zsh/site-functions/_infisical - # - src: ./manpages/infisical.1.gz - # dst: /usr/share/man/man1/infisical.1.gz + contents: + - src: ./completions/infisical.bash + dst: /etc/bash_completion.d/infisical + - src: ./completions/infisical.fish + dst: /usr/share/fish/vendor_completions.d/infisical.fish + - src: ./completions/infisical.zsh + dst: /usr/share/zsh/site-functions/_infisical + - src: ./manpages/infisical.1.gz + dst: /usr/share/man/man1/infisical.1.gz scoop: bucket: @@ -156,6 +160,15 @@ aurs: install -Dm755 "./infisical" "${pkgdir}/usr/bin/infisical" # license install -Dm644 "./LICENSE" "${pkgdir}/usr/share/licenses/infisical/LICENSE" + # completions + mkdir -p "${pkgdir}/usr/share/bash-completion/completions/" + mkdir -p "${pkgdir}/usr/share/zsh/site-functions/" + mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/" + install -Dm644 "./completions/infisical.bash" "${pkgdir}/usr/share/bash-completion/completions/infisical" + install -Dm644 "./completions/infisical.zsh" "${pkgdir}/usr/share/zsh/site-functions/_infisical" + install -Dm644 "./completions/infisical.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/infisical.fish" + # man pages + install -Dm644 "./manpages/infisical.1.gz" "${pkgdir}/usr/share/man/man1/infisical.1.gz" # dockers: # - dockerfile: cli/docker/Dockerfile diff --git a/.husky/pre-commit b/.husky/pre-commit index 0b3d59a18..e235e5d79 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -3,3 +3,5 @@ . "$(dirname -- "$0")/_/husky.sh" npx lint-staged + +infisical scan git-changes --staged -v diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..1f6653d95 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.16.3 + hooks: + - id: gitleaks diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 000000000..d391a9ab9 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,6 @@ +- id: infisical-scan + name: Scan for hardcoded secrets + description: Will scan for hardcoded secrets using Infisical CLI + entry: infisical scan git-changes --verbose --redact --staged + language: golang + pass_filenames: false diff --git a/Dockerfile.standalone-infisical b/Dockerfile.standalone-infisical index 49b74415e..12325fedd 100644 --- a/Dockerfile.standalone-infisical +++ b/Dockerfile.standalone-infisical @@ -77,7 +77,7 @@ RUN npm ci --only-production COPY --from=backend-build /app . # Production stage -FROM node:14-alpine AS production +FROM node:16-alpine AS production WORKDIR / diff --git a/README.md b/README.md index ae863df21..486ee10ef 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ git commit activity - Cloudsmith downloads + Cloudsmith downloads Slack community channel @@ -55,7 +55,7 @@ We're on a mission to make secret management more accessible to everyone, not ju - **[Audit logs](https://infisical.com/docs/documentation/platform/audit-logs)** to record every action taken in a project - **Role-based Access Controls** per environment - [**Simple on-premise deployments** to AWS and Digital Ocean](https://infisical.com/docs/self-hosting/overview) -- [**2FA**](https://infisical.com/docs/documentation/platform/mfa) with more options coming soon +- [**Secret Scanning**](https://infisical.com/docs/cli/scanning-overview) And much more. @@ -89,6 +89,24 @@ git clone https://github.com/Infisical/infisical && cd infisical && copy .env.ex Create an account at `http://localhost:80` +### Scan and prevent secret leaks +On top managing secrets with Infisical, you can also scan for over 140+ secret types in your files, directories and git repositories. + +To scan your full git history, run: + +``` +infisical scan --verbose +``` + +Install pre commit hook to scan each commit before you push to your repository + +``` +infisical scan install --pre-commit-hook +``` + +Lean about Infisical's code scanning feature [here](https://infisical.com/docs/cli/scanning-overview) + + ## Open-source vs. paid This repo available under the [MIT expat license](https://github.com/Infisical/infisical/blob/main/LICENSE), with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license in the future. diff --git a/backend/package-lock.json b/backend/package-lock.json index 9f149c29b..ff2b50915 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -9,16 +9,16 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@aws-sdk/client-secrets-manager": "^3.309.0", - "@godaddy/terminus": "^4.11.2", + "@aws-sdk/client-secrets-manager": "^3.319.0", + "@godaddy/terminus": "^4.12.0", "@octokit/rest": "^19.0.5", - "@sentry/node": "^7.41.0", - "@sentry/tracing": "^7.47.0", + "@sentry/node": "^7.49.0", + "@sentry/tracing": "^7.48.0", "@types/crypto-js": "^4.1.1", "@types/libsodium-wrappers": "^0.7.10", "argon2": "^0.30.3", "await-to-js": "^3.0.0", - "aws-sdk": "^2.1338.0", + "aws-sdk": "^2.1364.0", "axios": "^1.3.5", "axios-retry": "^3.4.0", "bcrypt": "^5.1.0", @@ -40,6 +40,7 @@ "libsodium-wrappers": "^0.7.10", "lodash": "^4.17.21", "mongoose": "^6.10.5", + "node-cache": "^5.1.2", "nodemailer": "^6.8.0", "posthog-node": "^2.6.0", "query-string": "^7.1.3", @@ -234,44 +235,44 @@ } }, "node_modules/@aws-sdk/client-secrets-manager": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.309.0.tgz", - "integrity": "sha512-rm3215BLI60Nhh+tDJzh0g9YSmsDBpWTvgs7tjkHO8NGhRPAWjiYHpklWtyg0gocH7fRoPJ3wAEteGfjPP03eQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.319.0.tgz", + "integrity": "sha512-3YPzBvr/hRlH3MbivWYGdvY4EMLwBVAE93gZjfIrkjvpufd/OKX5OoO8Q0EhOkfnc2VIw0DMT2x6ERtgXuVc4Q==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.309.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/credential-provider-node": "3.309.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-signing": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/client-sts": "3.319.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0", "uuid": "^8.3.2" }, @@ -280,11 +281,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/abort-controller": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.306.0.tgz", - "integrity": "sha512-ewCvdUrMJMlnkNaqXdG7L2H6O7CDI036y6lkTU8gQqa2lCzZvqBkzz6R5NbWqb8TJPi69Z7lXEITgk2b0+pl6w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.310.0.tgz", + "integrity": "sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -292,41 +293,41 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/client-sso": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.309.0.tgz", - "integrity": "sha512-2Tr3AROBzZOy+BuANlmDrwgyX+Q2kb6SIlANg6b9mrIzlflC48hRH0ngEe4C5RT6RruKIP+6R0al6vAq8lCk6A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.319.0.tgz", + "integrity": "sha512-g46KgAjRiYBS8Oi85DPwSAQpt+Hgmw/YFgGVwZqMfTL70KNJwLFKRa5D9UocQd7t7OjPRdKF7g0Gp5peyAK9dw==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -334,41 +335,41 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.309.0.tgz", - "integrity": "sha512-5hQMibuKWxDJo6IN+4ah0gskjJa16R41PqkeAOwExthTTyNzgoVyP9wyhnETyntYlHIBrHEmHTwdG06YiAxm4A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.319.0.tgz", + "integrity": "sha512-GJBgT/tephRZY3oTbDBMv+G9taoqKUIvGPn+7shmzz2P1SerutsRSfKfDXV+VptPNRoGmjjCLPmWjMFYbFKILQ==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -376,44 +377,44 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/client-sts": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.309.0.tgz", - "integrity": "sha512-rBVm50ft5o1FLaCNjSFY4c/lI7qPG5MMhOr4sdvEUaU1Mkniyd6M+3Pch9S3a5NtF0Kfzw9dWQpjAL+nqJaITQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.319.0.tgz", + "integrity": "sha512-PRGGKCSKtyM3x629J9j4DMsH1cQT8UGW+R67u9Q5HrMK05gfjpmg+X1DQ3pgve4D8MI4R/Cm3NkYl2eUTbQHQg==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/credential-provider-node": "3.309.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-sdk-sts": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-signing": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-sdk-sts": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "fast-xml-parser": "4.1.2", "tslib": "^2.5.0" }, @@ -422,13 +423,13 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/config-resolver": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.306.0.tgz", - "integrity": "sha512-kpqHu6LvNMYxullm+tLCsY6KQ2mZUxZTdyWJKTYLZCTxj4HcGJxf4Jxj9dwFAZVl/clcVPGWcHJaQJjyjwzBzw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.310.0.tgz", + "integrity": "sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g==", "dependencies": { - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-config-provider": "3.295.0", - "@aws-sdk/util-middleware": "3.306.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-config-provider": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -436,12 +437,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.306.0.tgz", - "integrity": "sha512-DTH+aMvMu+LAoWW+yfPkWzFXt/CPNFQ7+/4xiMnc7FWf+tjt+HZIrPECAV2rBVppNCkh7PC+xDSN61PFvBYOsw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.310.0.tgz", + "integrity": "sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A==", "dependencies": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -449,14 +450,14 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-imds": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.306.0.tgz", - "integrity": "sha512-WdrNhq2MwvjZk2I8Of+bZ/qWHG2hREQpwlBiG3tMeEkuywx7M1x3Rt0eHgiR1sTcm05kxNn0rB4OeWOeek37cA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.310.0.tgz", + "integrity": "sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w==", "dependencies": { - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -464,18 +465,18 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.309.0.tgz", - "integrity": "sha512-7xAqfbuvEdQdz2YcS5OPWH6uv09pMEW6lvmEwM8tf3gn/c3mxFm0/geFeO3+hnkIjByPM02PW7qQJXmPu1l7AA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.319.0.tgz", + "integrity": "sha512-pzx388Fw1KlSgmIMUyRY8DJVYM3aXpwzjprD4RiQVPJeAI+t7oQmEvd2FiUZEuHDjWXcuonxgU+dk7i7HUk/HQ==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.306.0", - "@aws-sdk/credential-provider-imds": "3.306.0", - "@aws-sdk/credential-provider-process": "3.306.0", - "@aws-sdk/credential-provider-sso": "3.309.0", - "@aws-sdk/credential-provider-web-identity": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -483,19 +484,19 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.309.0.tgz", - "integrity": "sha512-rgf53RH9mcATr+5rRGGqRmoOEceX+XSbQvGM1QRHxROJJiYsZWdBQu9w+UuKcQF03qLMfi4G+6iNHect5TVs2Q==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.319.0.tgz", + "integrity": "sha512-DS4a0Rdd7ZtMshoeE+zuSgbC05YBcdzd0h89u/eX+1Yqx+HCjeb8WXkbXsz0Mwx8q9TE04aS8f6Bw9J4x4mO5g==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.306.0", - "@aws-sdk/credential-provider-imds": "3.306.0", - "@aws-sdk/credential-provider-ini": "3.309.0", - "@aws-sdk/credential-provider-process": "3.306.0", - "@aws-sdk/credential-provider-sso": "3.309.0", - "@aws-sdk/credential-provider-web-identity": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-ini": "3.319.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -503,13 +504,13 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.306.0.tgz", - "integrity": "sha512-2RezGskHqJeHtGbK7CqhGNAoqXgQJb7FfPFqwUQ9oVDZS8f145jVwajjHcc7Qn3IwGoqylMF3uXIljUv89uDzA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.310.0.tgz", + "integrity": "sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA==", "dependencies": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -517,15 +518,15 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.309.0.tgz", - "integrity": "sha512-uMphs47O2S9NK7I5CsDttp88X7b/JktGOrW8RTLRw1QURQ8v0uP+MLHFogRtWi4E7+zo86Equ0njlpYlFvrpSA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.319.0.tgz", + "integrity": "sha512-gAUnWH41lxkIbANXu+Rz5zS0Iavjjmpf3C56vAMT7oaYZ3Cg/Ys5l2SwAucQGOCA2DdS2hDiSI8E+Yhr4F5toA==", "dependencies": { - "@aws-sdk/client-sso": "3.309.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/token-providers": "3.309.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/client-sso": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/token-providers": "3.319.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -533,12 +534,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.306.0.tgz", - "integrity": "sha512-MOQGQaOtdo4zLQZ1bRjD2n1PUzfNty+sKe+1wlm5bIqTN93UX3S8f0QznucZr7uJxI4Z14ZLwuYeAUV4Tgchlw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.310.0.tgz", + "integrity": "sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw==", "dependencies": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -546,25 +547,25 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/fetch-http-handler": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.306.0.tgz", - "integrity": "sha512-T8OODOnPpDqkXS+XSMIkd6hf90h833JLN93wq3ibbyD/WvGveufFFHsbsNyccE9+CSv/BjEuN5QbHqTKTp3BlA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.310.0.tgz", + "integrity": "sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw==", "dependencies": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/querystring-builder": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/hash-node": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.306.0.tgz", - "integrity": "sha512-EcSLd6gKoDEEBPZqEv+Ky9gIyefwyyrAJGILGKoYBmcOIY7Y0xKId0hxCa9/1xvWTaVC1u+rA06DGgksZOa78w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.310.0.tgz", + "integrity": "sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ==", "dependencies": { - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-buffer-from": "3.303.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-buffer-from": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -572,18 +573,18 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/invalid-dependency": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.306.0.tgz", - "integrity": "sha512-9Mkcr+qG7QR4R5bJcA8bBNd8E2x6WaZStsQ3QeFbdQr3V3Tunvra/KlCFsEL55GgU8BZt5isOaHqq7uxs5ILtQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.310.0.tgz", + "integrity": "sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/is-array-buffer": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.303.0.tgz", - "integrity": "sha512-IitBTr+pou7v5BrYLFH/SbIf3g1LIgMhcI3bDXBq2FjzmDftj4bW8BOmg05b9YKf2TrrggvJ4yk/jH+yYFXoJQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz", + "integrity": "sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==", "dependencies": { "tslib": "^2.5.0" }, @@ -592,12 +593,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-content-length": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.306.0.tgz", - "integrity": "sha512-JbONf2Ms+/DVRcpFNsKGdOQU94Js56KV+AhlPJmCwLxfyWvQjTt0KxFC1Dd+cjeNEXUduvBarrehgsqFlWnoHQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.310.0.tgz", + "integrity": "sha512-P8tQZxgDt6CAh1wd/W6WPzjc+uWPJwQkm+F7rAwRlM+k9q17HrhnksGDKcpuuLyIhPQYdmOMIkpKVgXGa4avhQ==", "dependencies": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -605,14 +606,14 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-endpoint": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.306.0.tgz", - "integrity": "sha512-i3QRiwgkcsuVN55O7l8I/QGwCypGRZXdYkPjU56LI2w2oiZ82f/nVMNXVc+ZFm2YH7WbCE+5jguw2J7HXdOlyQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.310.0.tgz", + "integrity": "sha512-Z+N2vOL8K354/lstkClxLLsr6hCpVRh+0tCMXrVj66/NtKysCEZ/0b9LmqOwD9pWHNiI2mJqXwY0gxNlKAroUg==", "dependencies": { - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-middleware": "3.306.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -620,12 +621,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.306.0.tgz", - "integrity": "sha512-mHDHK9E+c7HwMlrCJ+VFSB6tkq8oJVkYEHCvPkdrnzN/g9P/d/UhPIeGapZXMbAIZEaLpEGqs536mYzeRKZG8A==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.310.0.tgz", + "integrity": "sha512-QWSA+46/hXorXyWa61ic2K7qZzwHTiwfk2e9mRRjeIRepUgI3qxFjsYqrWtrOGBjmFmq0pYIY8Bb/DCJuQqcoA==", "dependencies": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -633,11 +634,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-logger": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.306.0.tgz", - "integrity": "sha512-1FRHp/QB0Lb+CgP+c9CYW6BZh+q+5pnuOKo/Rd6hjYiM+kT1G/cWdXnMJQBR4rbTCTixbqCnObNJ1EyP/ofQhQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.310.0.tgz", + "integrity": "sha512-Lurm8XofrASBRnAVtiSNuDSRsRqPNg27RIFLLsLp/pqog9nFJ0vz0kgdb9S5Z+zw83Mm+UlqOe6D8NTUNp4fVg==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -645,12 +646,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.306.0.tgz", - "integrity": "sha512-Hpj42ZLmwCy/CtVxi57NTeOEPoUJlivF3VIgowZ9JhaF61cakVKyrJ+f3jwXciDUtuYrdKm5Wf6prW6apWo0YA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.310.0.tgz", + "integrity": "sha512-SuB75/xk/gyue24gkriTwO2jFd7YcUGZDClQYuRejgbXSa3CO0lWyawQtfLcSSEBp9izrEVXuFH24K1eAft5nQ==", "dependencies": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -658,15 +659,15 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-retry": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.306.0.tgz", - "integrity": "sha512-eMyfr/aeurXXDz4x+WVrvLI8fVDP6klJOjziBEWZ/MUNP/hTFhkiQsMVbvT6O4Pspp7+FgCSdcUPG6Os2gK+CQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.310.0.tgz", + "integrity": "sha512-oTPsRy2W4s+dfxbJPW7Km+hHtv/OMsNsVfThAq8DDYKC13qlr1aAyOqGLD+dpBy2aKe7ss517Sy2HcHtHqm7/g==", "dependencies": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/service-error-classification": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-middleware": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/service-error-classification": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-retry": "3.310.0", "tslib": "^2.5.0", "uuid": "^8.3.2" }, @@ -675,12 +676,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-sdk-sts": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.306.0.tgz", - "integrity": "sha512-2rSAR3nc5faYuEnh1KxQMCMCkEkJyaDfA3zwWLqZ+/TBCH0PlPkBv+Z9yXmteEki0vI5Hr+e+atTutJZoyG13g==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.310.0.tgz", + "integrity": "sha512-+5PFwlYNLvLLIfw0ASAoWV/iIF8Zv6R6QGtyP0CclhRSvNjgbQDVnV0g95MC5qvh+GB/Yjlkt8qAjLSPjHfsrQ==", "dependencies": { - "@aws-sdk/middleware-signing": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -688,11 +689,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-serde": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.306.0.tgz", - "integrity": "sha512-M3gyPLPduZXMvdgt4XEpVO+3t0ZVPdgeQQwG6JnXv0dgyUizshYs4lrVOAb1KwF6StsmkrAgSN+I273elLiKjA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.310.0.tgz", + "integrity": "sha512-RNeeTVWSLTaentUeCgQKZhAl+C6hxtwD78cQWS10UymWpQFwbaxztzKUu4UQS5xA2j6PxwPRRUjqa4jcFjfLsg==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -700,15 +701,15 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-signing": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.306.0.tgz", - "integrity": "sha512-JhpSriN4xa4a/p5gAPL0OWFKJF4eWYU3K+LLlXBNGMbxg/qNL4skgT4dMFe3ii9EW8kI+r6tpvSgC+lP7/Tyng==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.310.0.tgz", + "integrity": "sha512-f9mKq+XMdW207Af3hKjdTnpNhdtwqWuvFs/ZyXoOkp/g1MY1O6L23Jy6i52m29LxbT4AuNRG1oKODfXM0vYVjQ==", "dependencies": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/signature-v4": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-middleware": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -716,9 +717,9 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-stack": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.306.0.tgz", - "integrity": "sha512-G//a6MVSxyFVpOMZ+dzT3+w7XblOd2tRJ5g+/okjn3pNBLbo5o9Hu33K/bz0SQjT/m5mU2F9m0wcdCPYbRPysg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.310.0.tgz", + "integrity": "sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg==", "dependencies": { "tslib": "^2.5.0" }, @@ -727,13 +728,13 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.306.0.tgz", - "integrity": "sha512-tP6I+Lbs68muPfdMA6Rfc+8fYo49nEn9A3RMiOU2COClWsmiZatpbK9UYlqIOxeGB/s2jI7hXmQq6tT2LStLSg==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.319.0.tgz", + "integrity": "sha512-ytaLx2dlR5AdMSne6FuDCISVg8hjyKj+cHU20b2CRA/E/z+XXrLrssp4JrCgizRKPPUep0psMIa22Zd6osTT5Q==", "dependencies": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-endpoints": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-endpoints": "3.319.0", "tslib": "^2.5.0" }, "engines": { @@ -741,13 +742,13 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/node-config-provider": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.306.0.tgz", - "integrity": "sha512-+m+ALxNx5E1zLPPijO1pAbT5tnofLzZFWlnSYBEiOIwzaRU44rLYDqAhgXJkMMbOECkffDrv6ym0oWJIwJI+DA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.310.0.tgz", + "integrity": "sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng==", "dependencies": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -755,14 +756,14 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/node-http-handler": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.306.0.tgz", - "integrity": "sha512-qvNSIVdGf0pnWEXsAulIqXk7LML25Zc1yxbujxoAj8oX5y+mDhzQdHKrMgc0FuI4RKoEd9px4DYoUbmTWrrxwA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.310.0.tgz", + "integrity": "sha512-irv9mbcM9xC2xYjArQF5SYmHBMu4ciMWtGsoHII1nRuFOl9FoT4ffTvEPuLlfC6pznzvKt9zvnm6xXj7gDChKg==", "dependencies": { - "@aws-sdk/abort-controller": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/querystring-builder": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/abort-controller": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -770,11 +771,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/property-provider": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.306.0.tgz", - "integrity": "sha512-37PnbjpANjHys0Y+DVmKUz1JbSGZ/mAndZeplTUsFDUtbNwJRw/fDyWUvGC82JWB4gNSP5muWscFvetZnK2l8A==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.310.0.tgz", + "integrity": "sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -782,11 +783,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/protocol-http": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.306.0.tgz", - "integrity": "sha512-6Z8bqB8Ydz/qG7+lJzjwsjIca2w2zp4nZ2HjxMoUm0NBbVXGDx7H9qy9eOUqEiCbdXbsfK2BmVQreLhFLt056Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.310.0.tgz", + "integrity": "sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -794,12 +795,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/querystring-builder": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.306.0.tgz", - "integrity": "sha512-kvz6fLwE4KojTxbphuo9JPwKKuhau2mmSurnqhtf77t9+0cOh2uzyYhIUtOFewpLj+qGoh4b2EODlJqczc7IKg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.310.0.tgz", + "integrity": "sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A==", "dependencies": { - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-uri-escape": "3.303.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -807,11 +808,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/querystring-parser": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.306.0.tgz", - "integrity": "sha512-YjOdLcyS/8sNkFPgnxyUx+cM/P2XFGCA2WjQ0e9AXX8xFFkmnY6U5w2EknQ5zyvKy+R/KAV0KAMJBUB+ofjg0A==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.310.0.tgz", + "integrity": "sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -819,19 +820,19 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/service-error-classification": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.306.0.tgz", - "integrity": "sha512-lmXIVHWU5J60GmmTgyj79kupWYg5ntyNrUPt1P9FYTsXz+tdk4YYH7/2IxZ1XjBr4jEsN56gfSI0cfT07ztQJA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.310.0.tgz", + "integrity": "sha512-PuyC7k3qfIKeH2LCnDwbttMOKq3qAx4buvg0yfnJtQOz6t1AR8gsnAq0CjKXXyfkXwNKWTqCpE6lVNUIkXgsMw==", "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/shared-ini-file-loader": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.306.0.tgz", - "integrity": "sha512-mDmBRN+Y0+EBD5megId97UIJGV/rmRsAds22qy0mmVdD3X7qlxn974btXVgfZyda6qw/pX6hgi8X99Qj6Wjb0w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.310.0.tgz", + "integrity": "sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -839,16 +840,16 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/signature-v4": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.306.0.tgz", - "integrity": "sha512-yoQTo6wLirKHg34Zhm8tKmfEaK8fOn+psVdMtRs2vGq3uzKLb+YW5zywnujoVwBvygQTWxiDMwRxDduWAisccA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.310.0.tgz", + "integrity": "sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q==", "dependencies": { - "@aws-sdk/is-array-buffer": "3.303.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-hex-encoding": "3.295.0", - "@aws-sdk/util-middleware": "3.306.0", - "@aws-sdk/util-uri-escape": "3.303.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/is-array-buffer": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -856,12 +857,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/smithy-client": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.309.0.tgz", - "integrity": "sha512-2+LJD8/J9yoYmfjLZuMTI/IF8qFMMclWdDJaalj4Rzzd7qBWDS3Q23UxpZi9VR155nqpgr/R+TFZMgze1EhRHg==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.316.0.tgz", + "integrity": "sha512-6YXOKbRnXeS8r8RWzuL6JMBolDYM5Wa4fD/VY6x/wK78i2xErHOvqzHgyyeLI1MMw4uqyd4wRNJNWC9TMPduXw==", "dependencies": { - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -869,14 +870,14 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/token-providers": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.309.0.tgz", - "integrity": "sha512-rB79nQArhVT3l8UglZyinZVm13hFRF4xqzrmSLNknxdlMLamrON/94H7S6lFLywdTags2SUdAxQ/LlStlFf78A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.319.0.tgz", + "integrity": "sha512-5utg6VL6Pl0uiLUn8ZJPYYxzCb9VRPsgJmGXktRUwq0YlTJ6ABcaxTXwZcC++sjh/qyCQDK5PPLNU5kIBttHMQ==", "dependencies": { - "@aws-sdk/client-sso-oidc": "3.309.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/client-sso-oidc": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -884,9 +885,9 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/types": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.306.0.tgz", - "integrity": "sha512-RnyknWWpQcRmNH7AsNr89sdhOoltCU/4YEwBMw34Eh+/36l7HfA5PdEKbsOkO7MO4+2g5qmmm/AHcnHRvymApg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.310.0.tgz", + "integrity": "sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==", "dependencies": { "tslib": "^2.5.0" }, @@ -895,21 +896,21 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/url-parser": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.306.0.tgz", - "integrity": "sha512-mhyOjtycZgxKYo2CoDhDQONuRd5TLfEwmyGWVgFrfubF0LejQ3rkBRLC5zT9TBZ8RJHNlqU2oGdsZCy3JV6Rlw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.310.0.tgz", + "integrity": "sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw==", "dependencies": { - "@aws-sdk/querystring-parser": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/querystring-parser": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-base64": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.303.0.tgz", - "integrity": "sha512-oj+p/GHHPcZEKjiiOHU/CyNQeh8i+8dfMMzU+VGdoK5jHaVG8h2b+V7GPf7I4wDkG2ySCK5b5Jw5NUHwdTJ13Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.310.0.tgz", + "integrity": "sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==", "dependencies": { - "@aws-sdk/util-buffer-from": "3.303.0", + "@aws-sdk/util-buffer-from": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -917,17 +918,17 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-body-length-browser": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.303.0.tgz", - "integrity": "sha512-T643m0pKzgjAvPFy4W8zL+aszG3T22U8hb6stlMvT0z++Smv8QfIvkIkXjWyH2KlOt5GKliHwdOv8SAi0FSMJQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.310.0.tgz", + "integrity": "sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==", "dependencies": { "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-body-length-node": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.303.0.tgz", - "integrity": "sha512-/hS8z6e18Le60hJr2TUIFoUjUiAsnQsuDn6DxX74GXhMOHeSwZDJ9jHF39quYkNMmAE37GrVH4MI9vE0pN27qw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.310.0.tgz", + "integrity": "sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==", "dependencies": { "tslib": "^2.5.0" }, @@ -936,11 +937,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-buffer-from": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.303.0.tgz", - "integrity": "sha512-hUU+NW+SW6RNojtAKnnmz+tDShVKlEx2YsS4a5fSfrKRUes+zWz10cxVX0RQfysd3R6tdSHhbjsSj8eCIybheg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz", + "integrity": "sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==", "dependencies": { - "@aws-sdk/is-array-buffer": "3.303.0", + "@aws-sdk/is-array-buffer": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -948,9 +949,9 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-config-provider": { - "version": "3.295.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.295.0.tgz", - "integrity": "sha512-/5Dl1aV2yI8YQjqwmg4RTnl/E9NmNsx7HIwBZt+dTcOrM0LMUwczQBFFcLyqCj/qv5y+VsvLoAAA/OiBT7hb3w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.310.0.tgz", + "integrity": "sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==", "dependencies": { "tslib": "^2.5.0" }, @@ -959,12 +960,12 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-defaults-mode-browser": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.309.0.tgz", - "integrity": "sha512-KTmoR24PhUCT9A8/f5rb7MQvzXqGJY7/VnYxNaQ6AzJZfZ3y3UYfvuJR9LRjWn+zQDy1lnTyjSh5eokf2VBOoQ==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.316.0.tgz", + "integrity": "sha512-6FSqLhYmaihtH2n1s4b2rlLW0ABU8N6VZIfzLfe2ING4PF0MzfaMMhnTFUHVXfKCVGoR8yP6iyFTRCyHGVEL1w==", "dependencies": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", "tslib": "^2.5.0" }, @@ -973,15 +974,15 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-defaults-mode-node": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.309.0.tgz", - "integrity": "sha512-3YIEWY6O5kyW6dbV+1jWdlsqjEN76sxY62841v5A9Vr/MGLowhm6YYW8MYWPye9RABl9osTs0NCeL2p6Re+IPw==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.316.0.tgz", + "integrity": "sha512-dkYy10hdjPSScXXvnjGpZpnJxllkb6ICHgLMwZ4JczLHhPM12T/4PQ758YN8HS+muiYDGX1Bl2z1jd/bMcewBQ==", "dependencies": { - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/credential-provider-imds": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -989,11 +990,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-endpoints": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.306.0.tgz", - "integrity": "sha512-aPTqU4VGhec8LDhKZrfA3/sBHTYRa0favKEo8aEa/vIZJTNBAFlUhvr5z7peAr8gBOtZZcElzX8PiK3jjn3ILw==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.319.0.tgz", + "integrity": "sha512-3I64UMoYA2e2++oOUJXRcFtYLpLylnZFRltWfPo1B3dLlf+MIWat9djT+mMus+hW1ntLsvAIVu1hLVePJC0gvw==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -1001,9 +1002,9 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-hex-encoding": { - "version": "3.295.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.295.0.tgz", - "integrity": "sha512-XJcoVo41kHzhe28PBm/rqt5mdCp8R6abwiW9ug1dA6FOoPUO8kBUxDv6xaOmA2hfRvd2ocFfBXaUCBqUowkGcQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.310.0.tgz", + "integrity": "sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==", "dependencies": { "tslib": "^2.5.0" }, @@ -1012,9 +1013,9 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-middleware": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.306.0.tgz", - "integrity": "sha512-14CSm1mTrfSNBGbkZu8vSjXYg7DUMfZc74IinOajcFtTswa/6SyiyhU9DK0a837qqwxSfFGpnE2thVeJIF/7FA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.310.0.tgz", + "integrity": "sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==", "dependencies": { "tslib": "^2.5.0" }, @@ -1023,11 +1024,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-retry": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.306.0.tgz", - "integrity": "sha512-zcgTEIehQAIAm4vBNWfXZpDNbIrDM095vZmpbozQwK/pfDqMGvq7j3r9atKuEGTtoomoGoYwj3x/KEhO6JXJLg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.310.0.tgz", + "integrity": "sha512-FwWGhCBLfoivTMUHu1LIn4NjrN9JLJ/aX5aZmbcPIOhZVFJj638j0qDgZXyfvVqBuBZh7M8kGq0Oahy3dp69OA==", "dependencies": { - "@aws-sdk/service-error-classification": "3.306.0", + "@aws-sdk/service-error-classification": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -1035,9 +1036,9 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-uri-escape": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.303.0.tgz", - "integrity": "sha512-N3ULNuHCL3QzAlCTY+XRRkRQTYCTU8RRuzFCJX0pDpz9t2K+tLT7DbxqupWGNFGl5Xlulf1Is14J3BP/Dx91rA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.310.0.tgz", + "integrity": "sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==", "dependencies": { "tslib": "^2.5.0" }, @@ -1046,22 +1047,22 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.306.0.tgz", - "integrity": "sha512-uZAtpvCasUdWRlB/nEjN0gf6G7810hT50VyWjpd6mQW78myV8M5fu/R03UFAZ+D8fhqqIdzR/IXDY1QUGp8bCA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.310.0.tgz", + "integrity": "sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw==", "dependencies": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.306.0.tgz", - "integrity": "sha512-zLp9wIx7FZ0qFLimYW3lJ1uJM5gqxmmcQjNimUaUq/4a1caDkaiF/QeyyMFva+wIjyHRv22P5abUBjIEZrs5WA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.310.0.tgz", + "integrity": "sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg==", "dependencies": { - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -1077,11 +1078,11 @@ } }, "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/util-utf8": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.303.0.tgz", - "integrity": "sha512-tZXVuMOIONPOuOGBs/XRdzxv6jUvTM620dRFFIHZwlGiW8bo0x0LlonrzDAJZA4e9ZwmxJIj8Ji13WVRBGvZWg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz", + "integrity": "sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==", "dependencies": { - "@aws-sdk/util-buffer-from": "3.303.0", + "@aws-sdk/util-buffer-from": "3.310.0", "tslib": "^2.5.0" }, "engines": { @@ -2688,9 +2689,9 @@ } }, "node_modules/@godaddy/terminus": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@godaddy/terminus/-/terminus-4.11.2.tgz", - "integrity": "sha512-e/kbOWpGKME42eltM/wXM3RxSUOrfureZxEd6Dt6NXyFoJ7E8lnmm7znXydJsL3B7ky4HRFZI+eHrep54NZbeQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@godaddy/terminus/-/terminus-4.12.0.tgz", + "integrity": "sha512-zbl6gKxPAnAoAAGCyRN1kOMHTXgiW3C09w8McLKZWSSHQlsiRZlMZzBwSv1aK9PaRU25w80cnOlt3ow+uQwR1Q==", "dependencies": { "stoppable": "^1.1.0" } @@ -3654,13 +3655,13 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@sentry-internal/tracing": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.47.0.tgz", - "integrity": "sha512-udpHnCzF8DQsWf0gQwd0XFGp6Y8MOiwnl8vGt2ohqZGS3m1+IxoRLXsSkD8qmvN6KKDnwbaAvYnK0z0L+AW95g==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.49.0.tgz", + "integrity": "sha512-ESh3+ZneQk/3HESTUmIPNrW5GVPu/HrRJU+eAJJto74vm+6vP7zDn2YV2gJ1w18O/37nc7W/bVCgZJlhZ3cwew==", "dependencies": { - "@sentry/core": "7.47.0", - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/core": "7.49.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "tslib": "^1.9.3" }, "engines": { @@ -3668,12 +3669,12 @@ } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/core": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.47.0.tgz", - "integrity": "sha512-EFhZhKdMu7wKmWYZwbgTi8FNZ7Fq+HdlXiZWNz51Bqe3pHmfAkdHtAEs0Buo0v623MKA0CA4EjXIazGUM34XTg==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.49.0.tgz", + "integrity": "sha512-AlSnCYgfEbvK8pkNluUkmdW/cD9UpvOVCa+ERQswXNRkAv5aDGCL6Ihv6fnIajE++BYuwZh0+HwZUBVKTFzoZg==", "dependencies": { - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "tslib": "^1.9.3" }, "engines": { @@ -3681,19 +3682,19 @@ } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/types": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.47.0.tgz", - "integrity": "sha512-GxXocplN0j1+uczovHrfkykl9wvkamDtWxlPUQgyGlbLGZn+UH1Y79D4D58COaFWGEZdSNKr62gZAjfEYu9nQA==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.49.0.tgz", + "integrity": "sha512-9yXXh7iv76+O6h2ONUVx0wsL1auqJFWez62mTjWk4350SgMmWp/zUkBxnVXhmcYqscz/CepC+Loz9vITLXtgxg==", "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/utils": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.47.0.tgz", - "integrity": "sha512-A89SaOLp6XeZfByeYo2C8Ecye/YAtk/gENuyOUhQEdMulI6mZdjqtHAp7pTMVgkBc/YNARVuoa+kR/IdRrTPkQ==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.49.0.tgz", + "integrity": "sha512-JdC9yGnOgev4ISJVwmIoFsk8Zx0psDZJAj2DV7x4wMZsO6QK+YjC7G3mUED/S5D5lsrkBZ/3uvQQhr8DQI4UcQ==", "dependencies": { - "@sentry/types": "7.47.0", + "@sentry/types": "7.49.0", "tslib": "^1.9.3" }, "engines": { @@ -3705,15 +3706,33 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/@sentry/node": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.47.0.tgz", - "integrity": "sha512-LTg2r5EV9yh4GLYDF+ViSltR9LLj/pcvk8YhANJcMO3Fp//xh8njcdU0FC2yNthUREawYDzAsVzLyCYJfV0H1A==", + "node_modules/@sentry/core": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.48.0.tgz", + "integrity": "sha512-8FYuJTMpyuxRZvlen3gQ3rpOtVInSDmSyXqWEhCLuG/w34AtWoTiW7G516rsAAh6Hy1TP91GooMWbonP3XQNTQ==", "dependencies": { - "@sentry-internal/tracing": "7.47.0", - "@sentry/core": "7.47.0", - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/types": "7.48.0", + "@sentry/utils": "7.48.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/core/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@sentry/node": { + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.49.0.tgz", + "integrity": "sha512-KLIrqcbKk4yR3g8fjl87Eyv4M9j4YI6b7sqVAZYj3FrX3mC6JQyGdlDfUpSKy604n1iAdr6OuUp5f9x7jPJaeQ==", + "dependencies": { + "@sentry-internal/tracing": "7.49.0", + "@sentry/core": "7.49.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "cookie": "^0.4.1", "https-proxy-agent": "^5.0.0", "lru_map": "^0.3.3", @@ -3724,12 +3743,12 @@ } }, "node_modules/@sentry/node/node_modules/@sentry/core": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.47.0.tgz", - "integrity": "sha512-EFhZhKdMu7wKmWYZwbgTi8FNZ7Fq+HdlXiZWNz51Bqe3pHmfAkdHtAEs0Buo0v623MKA0CA4EjXIazGUM34XTg==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.49.0.tgz", + "integrity": "sha512-AlSnCYgfEbvK8pkNluUkmdW/cD9UpvOVCa+ERQswXNRkAv5aDGCL6Ihv6fnIajE++BYuwZh0+HwZUBVKTFzoZg==", "dependencies": { - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "tslib": "^1.9.3" }, "engines": { @@ -3737,19 +3756,19 @@ } }, "node_modules/@sentry/node/node_modules/@sentry/types": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.47.0.tgz", - "integrity": "sha512-GxXocplN0j1+uczovHrfkykl9wvkamDtWxlPUQgyGlbLGZn+UH1Y79D4D58COaFWGEZdSNKr62gZAjfEYu9nQA==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.49.0.tgz", + "integrity": "sha512-9yXXh7iv76+O6h2ONUVx0wsL1auqJFWez62mTjWk4350SgMmWp/zUkBxnVXhmcYqscz/CepC+Loz9vITLXtgxg==", "engines": { "node": ">=8" } }, "node_modules/@sentry/node/node_modules/@sentry/utils": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.47.0.tgz", - "integrity": "sha512-A89SaOLp6XeZfByeYo2C8Ecye/YAtk/gENuyOUhQEdMulI6mZdjqtHAp7pTMVgkBc/YNARVuoa+kR/IdRrTPkQ==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.49.0.tgz", + "integrity": "sha512-JdC9yGnOgev4ISJVwmIoFsk8Zx0psDZJAj2DV7x4wMZsO6QK+YjC7G3mUED/S5D5lsrkBZ/3uvQQhr8DQI4UcQ==", "dependencies": { - "@sentry/types": "7.47.0", + "@sentry/types": "7.49.0", "tslib": "^1.9.3" }, "engines": { @@ -3762,16 +3781,60 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@sentry/tracing": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.47.0.tgz", - "integrity": "sha512-hJCpKdekwaFNbCVXxfCz5IxfSEJIKnkPmRSVHITOm5VhKwq2e5kmy4Rn6bzSETwJFSDE8LGbR/3eSfGTqw37XA==", + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.48.0.tgz", + "integrity": "sha512-X6w74Av0fyayNicKIlwL1IdpZ3O0ETQjyYXCDTwHoJL71ojrgrL5vdiNz8WwbPONTnqu98HehPYL/z3DCCKVbw==", "dependencies": { - "@sentry-internal/tracing": "7.47.0" + "@sentry-internal/tracing": "7.48.0" }, "engines": { "node": ">=8" } }, + "node_modules/@sentry/tracing/node_modules/@sentry-internal/tracing": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.48.0.tgz", + "integrity": "sha512-MFAPDTrvCtfSm0/Zbmx7HA0Q5uCfRadOUpN8Y8rP1ndz+329h2kA3mZRCuC+3/aXL11zs2CHUhcAkGjwH2vogg==", + "dependencies": { + "@sentry/core": "7.48.0", + "@sentry/types": "7.48.0", + "@sentry/utils": "7.48.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/tracing/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@sentry/types": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.48.0.tgz", + "integrity": "sha512-kkAszZwQ5/v4n7Yyw/DPNRWx7h724mVNRGZIJa9ggUMvTgMe7UKCZZ5wfQmYiKVlGbwd9pxXAcP8Oq15EbByFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/utils": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.48.0.tgz", + "integrity": "sha512-d977sghkFVMfld0LrEyyY2gYrfayLPdDEpUDT+hg5y79r7zZDCFyHtdB86699E5K89MwDZahW7Erk+a1nk4x5w==", + "dependencies": { + "@sentry/types": "7.48.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/utils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/@sinclair/typebox": { "version": "0.25.24", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", @@ -4762,9 +4825,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1358.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1358.0.tgz", - "integrity": "sha512-ZolqFlnm0mDNgub7FGrVi7r5A1rw+58zZziKhlis3IxOtIpHdx4BQU5pH4htAMuD0Ct557p/dC/wmnZH/1Rc9Q==", + "version": "2.1364.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1364.0.tgz", + "integrity": "sha512-PFoq9Rnu0DVi07wZ/SjKlrJDwso8AxE5q/ufLdNtINZPaSkB92OqKYVdlfQ4srsH2ala2NCrg8gFX98SCmqW3w==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -5331,6 +5394,14 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -8395,6 +8466,17 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/node-fetch": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", @@ -13316,696 +13398,696 @@ } }, "@aws-sdk/client-secrets-manager": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.309.0.tgz", - "integrity": "sha512-rm3215BLI60Nhh+tDJzh0g9YSmsDBpWTvgs7tjkHO8NGhRPAWjiYHpklWtyg0gocH7fRoPJ3wAEteGfjPP03eQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.319.0.tgz", + "integrity": "sha512-3YPzBvr/hRlH3MbivWYGdvY4EMLwBVAE93gZjfIrkjvpufd/OKX5OoO8Q0EhOkfnc2VIw0DMT2x6ERtgXuVc4Q==", "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.309.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/credential-provider-node": "3.309.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-signing": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/client-sts": "3.319.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0", "uuid": "^8.3.2" }, "dependencies": { "@aws-sdk/abort-controller": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.306.0.tgz", - "integrity": "sha512-ewCvdUrMJMlnkNaqXdG7L2H6O7CDI036y6lkTU8gQqa2lCzZvqBkzz6R5NbWqb8TJPi69Z7lXEITgk2b0+pl6w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.310.0.tgz", + "integrity": "sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/client-sso": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.309.0.tgz", - "integrity": "sha512-2Tr3AROBzZOy+BuANlmDrwgyX+Q2kb6SIlANg6b9mrIzlflC48hRH0ngEe4C5RT6RruKIP+6R0al6vAq8lCk6A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.319.0.tgz", + "integrity": "sha512-g46KgAjRiYBS8Oi85DPwSAQpt+Hgmw/YFgGVwZqMfTL70KNJwLFKRa5D9UocQd7t7OjPRdKF7g0Gp5peyAK9dw==", "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/client-sso-oidc": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.309.0.tgz", - "integrity": "sha512-5hQMibuKWxDJo6IN+4ah0gskjJa16R41PqkeAOwExthTTyNzgoVyP9wyhnETyntYlHIBrHEmHTwdG06YiAxm4A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.319.0.tgz", + "integrity": "sha512-GJBgT/tephRZY3oTbDBMv+G9taoqKUIvGPn+7shmzz2P1SerutsRSfKfDXV+VptPNRoGmjjCLPmWjMFYbFKILQ==", "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/client-sts": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.309.0.tgz", - "integrity": "sha512-rBVm50ft5o1FLaCNjSFY4c/lI7qPG5MMhOr4sdvEUaU1Mkniyd6M+3Pch9S3a5NtF0Kfzw9dWQpjAL+nqJaITQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.319.0.tgz", + "integrity": "sha512-PRGGKCSKtyM3x629J9j4DMsH1cQT8UGW+R67u9Q5HrMK05gfjpmg+X1DQ3pgve4D8MI4R/Cm3NkYl2eUTbQHQg==", "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/credential-provider-node": "3.309.0", - "@aws-sdk/fetch-http-handler": "3.306.0", - "@aws-sdk/hash-node": "3.306.0", - "@aws-sdk/invalid-dependency": "3.306.0", - "@aws-sdk/middleware-content-length": "3.306.0", - "@aws-sdk/middleware-endpoint": "3.306.0", - "@aws-sdk/middleware-host-header": "3.306.0", - "@aws-sdk/middleware-logger": "3.306.0", - "@aws-sdk/middleware-recursion-detection": "3.306.0", - "@aws-sdk/middleware-retry": "3.306.0", - "@aws-sdk/middleware-sdk-sts": "3.306.0", - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/middleware-signing": "3.306.0", - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/middleware-user-agent": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/node-http-handler": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/smithy-client": "3.309.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", - "@aws-sdk/util-body-length-browser": "3.303.0", - "@aws-sdk/util-body-length-node": "3.303.0", - "@aws-sdk/util-defaults-mode-browser": "3.309.0", - "@aws-sdk/util-defaults-mode-node": "3.309.0", - "@aws-sdk/util-endpoints": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", - "@aws-sdk/util-user-agent-browser": "3.306.0", - "@aws-sdk/util-user-agent-node": "3.306.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-sdk-sts": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "fast-xml-parser": "4.1.2", "tslib": "^2.5.0" } }, "@aws-sdk/config-resolver": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.306.0.tgz", - "integrity": "sha512-kpqHu6LvNMYxullm+tLCsY6KQ2mZUxZTdyWJKTYLZCTxj4HcGJxf4Jxj9dwFAZVl/clcVPGWcHJaQJjyjwzBzw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.310.0.tgz", + "integrity": "sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g==", "requires": { - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-config-provider": "3.295.0", - "@aws-sdk/util-middleware": "3.306.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-config-provider": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-env": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.306.0.tgz", - "integrity": "sha512-DTH+aMvMu+LAoWW+yfPkWzFXt/CPNFQ7+/4xiMnc7FWf+tjt+HZIrPECAV2rBVppNCkh7PC+xDSN61PFvBYOsw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.310.0.tgz", + "integrity": "sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A==", "requires": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-imds": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.306.0.tgz", - "integrity": "sha512-WdrNhq2MwvjZk2I8Of+bZ/qWHG2hREQpwlBiG3tMeEkuywx7M1x3Rt0eHgiR1sTcm05kxNn0rB4OeWOeek37cA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.310.0.tgz", + "integrity": "sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w==", "requires": { - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-ini": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.309.0.tgz", - "integrity": "sha512-7xAqfbuvEdQdz2YcS5OPWH6uv09pMEW6lvmEwM8tf3gn/c3mxFm0/geFeO3+hnkIjByPM02PW7qQJXmPu1l7AA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.319.0.tgz", + "integrity": "sha512-pzx388Fw1KlSgmIMUyRY8DJVYM3aXpwzjprD4RiQVPJeAI+t7oQmEvd2FiUZEuHDjWXcuonxgU+dk7i7HUk/HQ==", "requires": { - "@aws-sdk/credential-provider-env": "3.306.0", - "@aws-sdk/credential-provider-imds": "3.306.0", - "@aws-sdk/credential-provider-process": "3.306.0", - "@aws-sdk/credential-provider-sso": "3.309.0", - "@aws-sdk/credential-provider-web-identity": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-node": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.309.0.tgz", - "integrity": "sha512-rgf53RH9mcATr+5rRGGqRmoOEceX+XSbQvGM1QRHxROJJiYsZWdBQu9w+UuKcQF03qLMfi4G+6iNHect5TVs2Q==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.319.0.tgz", + "integrity": "sha512-DS4a0Rdd7ZtMshoeE+zuSgbC05YBcdzd0h89u/eX+1Yqx+HCjeb8WXkbXsz0Mwx8q9TE04aS8f6Bw9J4x4mO5g==", "requires": { - "@aws-sdk/credential-provider-env": "3.306.0", - "@aws-sdk/credential-provider-imds": "3.306.0", - "@aws-sdk/credential-provider-ini": "3.309.0", - "@aws-sdk/credential-provider-process": "3.306.0", - "@aws-sdk/credential-provider-sso": "3.309.0", - "@aws-sdk/credential-provider-web-identity": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-ini": "3.319.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-process": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.306.0.tgz", - "integrity": "sha512-2RezGskHqJeHtGbK7CqhGNAoqXgQJb7FfPFqwUQ9oVDZS8f145jVwajjHcc7Qn3IwGoqylMF3uXIljUv89uDzA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.310.0.tgz", + "integrity": "sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA==", "requires": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-sso": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.309.0.tgz", - "integrity": "sha512-uMphs47O2S9NK7I5CsDttp88X7b/JktGOrW8RTLRw1QURQ8v0uP+MLHFogRtWi4E7+zo86Equ0njlpYlFvrpSA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.319.0.tgz", + "integrity": "sha512-gAUnWH41lxkIbANXu+Rz5zS0Iavjjmpf3C56vAMT7oaYZ3Cg/Ys5l2SwAucQGOCA2DdS2hDiSI8E+Yhr4F5toA==", "requires": { - "@aws-sdk/client-sso": "3.309.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/token-providers": "3.309.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/client-sso": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/token-providers": "3.319.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-web-identity": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.306.0.tgz", - "integrity": "sha512-MOQGQaOtdo4zLQZ1bRjD2n1PUzfNty+sKe+1wlm5bIqTN93UX3S8f0QznucZr7uJxI4Z14ZLwuYeAUV4Tgchlw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.310.0.tgz", + "integrity": "sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw==", "requires": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/fetch-http-handler": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.306.0.tgz", - "integrity": "sha512-T8OODOnPpDqkXS+XSMIkd6hf90h833JLN93wq3ibbyD/WvGveufFFHsbsNyccE9+CSv/BjEuN5QbHqTKTp3BlA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.310.0.tgz", + "integrity": "sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw==", "requires": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/querystring-builder": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-base64": "3.303.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/hash-node": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.306.0.tgz", - "integrity": "sha512-EcSLd6gKoDEEBPZqEv+Ky9gIyefwyyrAJGILGKoYBmcOIY7Y0xKId0hxCa9/1xvWTaVC1u+rA06DGgksZOa78w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.310.0.tgz", + "integrity": "sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ==", "requires": { - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-buffer-from": "3.303.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-buffer-from": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/invalid-dependency": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.306.0.tgz", - "integrity": "sha512-9Mkcr+qG7QR4R5bJcA8bBNd8E2x6WaZStsQ3QeFbdQr3V3Tunvra/KlCFsEL55GgU8BZt5isOaHqq7uxs5ILtQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.310.0.tgz", + "integrity": "sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/is-array-buffer": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.303.0.tgz", - "integrity": "sha512-IitBTr+pou7v5BrYLFH/SbIf3g1LIgMhcI3bDXBq2FjzmDftj4bW8BOmg05b9YKf2TrrggvJ4yk/jH+yYFXoJQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz", + "integrity": "sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/middleware-content-length": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.306.0.tgz", - "integrity": "sha512-JbONf2Ms+/DVRcpFNsKGdOQU94Js56KV+AhlPJmCwLxfyWvQjTt0KxFC1Dd+cjeNEXUduvBarrehgsqFlWnoHQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.310.0.tgz", + "integrity": "sha512-P8tQZxgDt6CAh1wd/W6WPzjc+uWPJwQkm+F7rAwRlM+k9q17HrhnksGDKcpuuLyIhPQYdmOMIkpKVgXGa4avhQ==", "requires": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-endpoint": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.306.0.tgz", - "integrity": "sha512-i3QRiwgkcsuVN55O7l8I/QGwCypGRZXdYkPjU56LI2w2oiZ82f/nVMNXVc+ZFm2YH7WbCE+5jguw2J7HXdOlyQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.310.0.tgz", + "integrity": "sha512-Z+N2vOL8K354/lstkClxLLsr6hCpVRh+0tCMXrVj66/NtKysCEZ/0b9LmqOwD9pWHNiI2mJqXwY0gxNlKAroUg==", "requires": { - "@aws-sdk/middleware-serde": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/url-parser": "3.306.0", - "@aws-sdk/util-middleware": "3.306.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-host-header": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.306.0.tgz", - "integrity": "sha512-mHDHK9E+c7HwMlrCJ+VFSB6tkq8oJVkYEHCvPkdrnzN/g9P/d/UhPIeGapZXMbAIZEaLpEGqs536mYzeRKZG8A==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.310.0.tgz", + "integrity": "sha512-QWSA+46/hXorXyWa61ic2K7qZzwHTiwfk2e9mRRjeIRepUgI3qxFjsYqrWtrOGBjmFmq0pYIY8Bb/DCJuQqcoA==", "requires": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-logger": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.306.0.tgz", - "integrity": "sha512-1FRHp/QB0Lb+CgP+c9CYW6BZh+q+5pnuOKo/Rd6hjYiM+kT1G/cWdXnMJQBR4rbTCTixbqCnObNJ1EyP/ofQhQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.310.0.tgz", + "integrity": "sha512-Lurm8XofrASBRnAVtiSNuDSRsRqPNg27RIFLLsLp/pqog9nFJ0vz0kgdb9S5Z+zw83Mm+UlqOe6D8NTUNp4fVg==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-recursion-detection": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.306.0.tgz", - "integrity": "sha512-Hpj42ZLmwCy/CtVxi57NTeOEPoUJlivF3VIgowZ9JhaF61cakVKyrJ+f3jwXciDUtuYrdKm5Wf6prW6apWo0YA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.310.0.tgz", + "integrity": "sha512-SuB75/xk/gyue24gkriTwO2jFd7YcUGZDClQYuRejgbXSa3CO0lWyawQtfLcSSEBp9izrEVXuFH24K1eAft5nQ==", "requires": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-retry": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.306.0.tgz", - "integrity": "sha512-eMyfr/aeurXXDz4x+WVrvLI8fVDP6klJOjziBEWZ/MUNP/hTFhkiQsMVbvT6O4Pspp7+FgCSdcUPG6Os2gK+CQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.310.0.tgz", + "integrity": "sha512-oTPsRy2W4s+dfxbJPW7Km+hHtv/OMsNsVfThAq8DDYKC13qlr1aAyOqGLD+dpBy2aKe7ss517Sy2HcHtHqm7/g==", "requires": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/service-error-classification": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-middleware": "3.306.0", - "@aws-sdk/util-retry": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/service-error-classification": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-retry": "3.310.0", "tslib": "^2.5.0", "uuid": "^8.3.2" } }, "@aws-sdk/middleware-sdk-sts": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.306.0.tgz", - "integrity": "sha512-2rSAR3nc5faYuEnh1KxQMCMCkEkJyaDfA3zwWLqZ+/TBCH0PlPkBv+Z9yXmteEki0vI5Hr+e+atTutJZoyG13g==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.310.0.tgz", + "integrity": "sha512-+5PFwlYNLvLLIfw0ASAoWV/iIF8Zv6R6QGtyP0CclhRSvNjgbQDVnV0g95MC5qvh+GB/Yjlkt8qAjLSPjHfsrQ==", "requires": { - "@aws-sdk/middleware-signing": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-serde": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.306.0.tgz", - "integrity": "sha512-M3gyPLPduZXMvdgt4XEpVO+3t0ZVPdgeQQwG6JnXv0dgyUizshYs4lrVOAb1KwF6StsmkrAgSN+I273elLiKjA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.310.0.tgz", + "integrity": "sha512-RNeeTVWSLTaentUeCgQKZhAl+C6hxtwD78cQWS10UymWpQFwbaxztzKUu4UQS5xA2j6PxwPRRUjqa4jcFjfLsg==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-signing": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.306.0.tgz", - "integrity": "sha512-JhpSriN4xa4a/p5gAPL0OWFKJF4eWYU3K+LLlXBNGMbxg/qNL4skgT4dMFe3ii9EW8kI+r6tpvSgC+lP7/Tyng==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.310.0.tgz", + "integrity": "sha512-f9mKq+XMdW207Af3hKjdTnpNhdtwqWuvFs/ZyXoOkp/g1MY1O6L23Jy6i52m29LxbT4AuNRG1oKODfXM0vYVjQ==", "requires": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/signature-v4": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-middleware": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-stack": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.306.0.tgz", - "integrity": "sha512-G//a6MVSxyFVpOMZ+dzT3+w7XblOd2tRJ5g+/okjn3pNBLbo5o9Hu33K/bz0SQjT/m5mU2F9m0wcdCPYbRPysg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.310.0.tgz", + "integrity": "sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/middleware-user-agent": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.306.0.tgz", - "integrity": "sha512-tP6I+Lbs68muPfdMA6Rfc+8fYo49nEn9A3RMiOU2COClWsmiZatpbK9UYlqIOxeGB/s2jI7hXmQq6tT2LStLSg==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.319.0.tgz", + "integrity": "sha512-ytaLx2dlR5AdMSne6FuDCISVg8hjyKj+cHU20b2CRA/E/z+XXrLrssp4JrCgizRKPPUep0psMIa22Zd6osTT5Q==", "requires": { - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-endpoints": "3.306.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-endpoints": "3.319.0", "tslib": "^2.5.0" } }, "@aws-sdk/node-config-provider": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.306.0.tgz", - "integrity": "sha512-+m+ALxNx5E1zLPPijO1pAbT5tnofLzZFWlnSYBEiOIwzaRU44rLYDqAhgXJkMMbOECkffDrv6ym0oWJIwJI+DA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.310.0.tgz", + "integrity": "sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng==", "requires": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/node-http-handler": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.306.0.tgz", - "integrity": "sha512-qvNSIVdGf0pnWEXsAulIqXk7LML25Zc1yxbujxoAj8oX5y+mDhzQdHKrMgc0FuI4RKoEd9px4DYoUbmTWrrxwA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.310.0.tgz", + "integrity": "sha512-irv9mbcM9xC2xYjArQF5SYmHBMu4ciMWtGsoHII1nRuFOl9FoT4ffTvEPuLlfC6pznzvKt9zvnm6xXj7gDChKg==", "requires": { - "@aws-sdk/abort-controller": "3.306.0", - "@aws-sdk/protocol-http": "3.306.0", - "@aws-sdk/querystring-builder": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/abort-controller": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/property-provider": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.306.0.tgz", - "integrity": "sha512-37PnbjpANjHys0Y+DVmKUz1JbSGZ/mAndZeplTUsFDUtbNwJRw/fDyWUvGC82JWB4gNSP5muWscFvetZnK2l8A==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.310.0.tgz", + "integrity": "sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/protocol-http": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.306.0.tgz", - "integrity": "sha512-6Z8bqB8Ydz/qG7+lJzjwsjIca2w2zp4nZ2HjxMoUm0NBbVXGDx7H9qy9eOUqEiCbdXbsfK2BmVQreLhFLt056Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.310.0.tgz", + "integrity": "sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/querystring-builder": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.306.0.tgz", - "integrity": "sha512-kvz6fLwE4KojTxbphuo9JPwKKuhau2mmSurnqhtf77t9+0cOh2uzyYhIUtOFewpLj+qGoh4b2EODlJqczc7IKg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.310.0.tgz", + "integrity": "sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A==", "requires": { - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-uri-escape": "3.303.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/querystring-parser": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.306.0.tgz", - "integrity": "sha512-YjOdLcyS/8sNkFPgnxyUx+cM/P2XFGCA2WjQ0e9AXX8xFFkmnY6U5w2EknQ5zyvKy+R/KAV0KAMJBUB+ofjg0A==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.310.0.tgz", + "integrity": "sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/service-error-classification": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.306.0.tgz", - "integrity": "sha512-lmXIVHWU5J60GmmTgyj79kupWYg5ntyNrUPt1P9FYTsXz+tdk4YYH7/2IxZ1XjBr4jEsN56gfSI0cfT07ztQJA==" + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.310.0.tgz", + "integrity": "sha512-PuyC7k3qfIKeH2LCnDwbttMOKq3qAx4buvg0yfnJtQOz6t1AR8gsnAq0CjKXXyfkXwNKWTqCpE6lVNUIkXgsMw==" }, "@aws-sdk/shared-ini-file-loader": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.306.0.tgz", - "integrity": "sha512-mDmBRN+Y0+EBD5megId97UIJGV/rmRsAds22qy0mmVdD3X7qlxn974btXVgfZyda6qw/pX6hgi8X99Qj6Wjb0w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.310.0.tgz", + "integrity": "sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/signature-v4": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.306.0.tgz", - "integrity": "sha512-yoQTo6wLirKHg34Zhm8tKmfEaK8fOn+psVdMtRs2vGq3uzKLb+YW5zywnujoVwBvygQTWxiDMwRxDduWAisccA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.310.0.tgz", + "integrity": "sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q==", "requires": { - "@aws-sdk/is-array-buffer": "3.303.0", - "@aws-sdk/types": "3.306.0", - "@aws-sdk/util-hex-encoding": "3.295.0", - "@aws-sdk/util-middleware": "3.306.0", - "@aws-sdk/util-uri-escape": "3.303.0", - "@aws-sdk/util-utf8": "3.303.0", + "@aws-sdk/is-array-buffer": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/smithy-client": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.309.0.tgz", - "integrity": "sha512-2+LJD8/J9yoYmfjLZuMTI/IF8qFMMclWdDJaalj4Rzzd7qBWDS3Q23UxpZi9VR155nqpgr/R+TFZMgze1EhRHg==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.316.0.tgz", + "integrity": "sha512-6YXOKbRnXeS8r8RWzuL6JMBolDYM5Wa4fD/VY6x/wK78i2xErHOvqzHgyyeLI1MMw4uqyd4wRNJNWC9TMPduXw==", "requires": { - "@aws-sdk/middleware-stack": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/token-providers": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.309.0.tgz", - "integrity": "sha512-rB79nQArhVT3l8UglZyinZVm13hFRF4xqzrmSLNknxdlMLamrON/94H7S6lFLywdTags2SUdAxQ/LlStlFf78A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.319.0.tgz", + "integrity": "sha512-5utg6VL6Pl0uiLUn8ZJPYYxzCb9VRPsgJmGXktRUwq0YlTJ6ABcaxTXwZcC++sjh/qyCQDK5PPLNU5kIBttHMQ==", "requires": { - "@aws-sdk/client-sso-oidc": "3.309.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/shared-ini-file-loader": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/client-sso-oidc": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/types": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.306.0.tgz", - "integrity": "sha512-RnyknWWpQcRmNH7AsNr89sdhOoltCU/4YEwBMw34Eh+/36l7HfA5PdEKbsOkO7MO4+2g5qmmm/AHcnHRvymApg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.310.0.tgz", + "integrity": "sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/url-parser": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.306.0.tgz", - "integrity": "sha512-mhyOjtycZgxKYo2CoDhDQONuRd5TLfEwmyGWVgFrfubF0LejQ3rkBRLC5zT9TBZ8RJHNlqU2oGdsZCy3JV6Rlw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.310.0.tgz", + "integrity": "sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw==", "requires": { - "@aws-sdk/querystring-parser": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/querystring-parser": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-base64": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.303.0.tgz", - "integrity": "sha512-oj+p/GHHPcZEKjiiOHU/CyNQeh8i+8dfMMzU+VGdoK5jHaVG8h2b+V7GPf7I4wDkG2ySCK5b5Jw5NUHwdTJ13Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.310.0.tgz", + "integrity": "sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==", "requires": { - "@aws-sdk/util-buffer-from": "3.303.0", + "@aws-sdk/util-buffer-from": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-body-length-browser": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.303.0.tgz", - "integrity": "sha512-T643m0pKzgjAvPFy4W8zL+aszG3T22U8hb6stlMvT0z++Smv8QfIvkIkXjWyH2KlOt5GKliHwdOv8SAi0FSMJQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.310.0.tgz", + "integrity": "sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/util-body-length-node": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.303.0.tgz", - "integrity": "sha512-/hS8z6e18Le60hJr2TUIFoUjUiAsnQsuDn6DxX74GXhMOHeSwZDJ9jHF39quYkNMmAE37GrVH4MI9vE0pN27qw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.310.0.tgz", + "integrity": "sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/util-buffer-from": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.303.0.tgz", - "integrity": "sha512-hUU+NW+SW6RNojtAKnnmz+tDShVKlEx2YsS4a5fSfrKRUes+zWz10cxVX0RQfysd3R6tdSHhbjsSj8eCIybheg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz", + "integrity": "sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==", "requires": { - "@aws-sdk/is-array-buffer": "3.303.0", + "@aws-sdk/is-array-buffer": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-config-provider": { - "version": "3.295.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.295.0.tgz", - "integrity": "sha512-/5Dl1aV2yI8YQjqwmg4RTnl/E9NmNsx7HIwBZt+dTcOrM0LMUwczQBFFcLyqCj/qv5y+VsvLoAAA/OiBT7hb3w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.310.0.tgz", + "integrity": "sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/util-defaults-mode-browser": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.309.0.tgz", - "integrity": "sha512-KTmoR24PhUCT9A8/f5rb7MQvzXqGJY7/VnYxNaQ6AzJZfZ3y3UYfvuJR9LRjWn+zQDy1lnTyjSh5eokf2VBOoQ==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.316.0.tgz", + "integrity": "sha512-6FSqLhYmaihtH2n1s4b2rlLW0ABU8N6VZIfzLfe2ING4PF0MzfaMMhnTFUHVXfKCVGoR8yP6iyFTRCyHGVEL1w==", "requires": { - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-defaults-mode-node": { - "version": "3.309.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.309.0.tgz", - "integrity": "sha512-3YIEWY6O5kyW6dbV+1jWdlsqjEN76sxY62841v5A9Vr/MGLowhm6YYW8MYWPye9RABl9osTs0NCeL2p6Re+IPw==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.316.0.tgz", + "integrity": "sha512-dkYy10hdjPSScXXvnjGpZpnJxllkb6ICHgLMwZ4JczLHhPM12T/4PQ758YN8HS+muiYDGX1Bl2z1jd/bMcewBQ==", "requires": { - "@aws-sdk/config-resolver": "3.306.0", - "@aws-sdk/credential-provider-imds": "3.306.0", - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/property-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-endpoints": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.306.0.tgz", - "integrity": "sha512-aPTqU4VGhec8LDhKZrfA3/sBHTYRa0favKEo8aEa/vIZJTNBAFlUhvr5z7peAr8gBOtZZcElzX8PiK3jjn3ILw==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.319.0.tgz", + "integrity": "sha512-3I64UMoYA2e2++oOUJXRcFtYLpLylnZFRltWfPo1B3dLlf+MIWat9djT+mMus+hW1ntLsvAIVu1hLVePJC0gvw==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-hex-encoding": { - "version": "3.295.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.295.0.tgz", - "integrity": "sha512-XJcoVo41kHzhe28PBm/rqt5mdCp8R6abwiW9ug1dA6FOoPUO8kBUxDv6xaOmA2hfRvd2ocFfBXaUCBqUowkGcQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.310.0.tgz", + "integrity": "sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/util-middleware": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.306.0.tgz", - "integrity": "sha512-14CSm1mTrfSNBGbkZu8vSjXYg7DUMfZc74IinOajcFtTswa/6SyiyhU9DK0a837qqwxSfFGpnE2thVeJIF/7FA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.310.0.tgz", + "integrity": "sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/util-retry": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.306.0.tgz", - "integrity": "sha512-zcgTEIehQAIAm4vBNWfXZpDNbIrDM095vZmpbozQwK/pfDqMGvq7j3r9atKuEGTtoomoGoYwj3x/KEhO6JXJLg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.310.0.tgz", + "integrity": "sha512-FwWGhCBLfoivTMUHu1LIn4NjrN9JLJ/aX5aZmbcPIOhZVFJj638j0qDgZXyfvVqBuBZh7M8kGq0Oahy3dp69OA==", "requires": { - "@aws-sdk/service-error-classification": "3.306.0", + "@aws-sdk/service-error-classification": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-uri-escape": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.303.0.tgz", - "integrity": "sha512-N3ULNuHCL3QzAlCTY+XRRkRQTYCTU8RRuzFCJX0pDpz9t2K+tLT7DbxqupWGNFGl5Xlulf1Is14J3BP/Dx91rA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.310.0.tgz", + "integrity": "sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==", "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-browser": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.306.0.tgz", - "integrity": "sha512-uZAtpvCasUdWRlB/nEjN0gf6G7810hT50VyWjpd6mQW78myV8M5fu/R03UFAZ+D8fhqqIdzR/IXDY1QUGp8bCA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.310.0.tgz", + "integrity": "sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw==", "requires": { - "@aws-sdk/types": "3.306.0", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-node": { - "version": "3.306.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.306.0.tgz", - "integrity": "sha512-zLp9wIx7FZ0qFLimYW3lJ1uJM5gqxmmcQjNimUaUq/4a1caDkaiF/QeyyMFva+wIjyHRv22P5abUBjIEZrs5WA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.310.0.tgz", + "integrity": "sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg==", "requires": { - "@aws-sdk/node-config-provider": "3.306.0", - "@aws-sdk/types": "3.306.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-utf8": { - "version": "3.303.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.303.0.tgz", - "integrity": "sha512-tZXVuMOIONPOuOGBs/XRdzxv6jUvTM620dRFFIHZwlGiW8bo0x0LlonrzDAJZA4e9ZwmxJIj8Ji13WVRBGvZWg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz", + "integrity": "sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==", "requires": { - "@aws-sdk/util-buffer-from": "3.303.0", + "@aws-sdk/util-buffer-from": "3.310.0", "tslib": "^2.5.0" } } @@ -15287,9 +15369,9 @@ "dev": true }, "@godaddy/terminus": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@godaddy/terminus/-/terminus-4.11.2.tgz", - "integrity": "sha512-e/kbOWpGKME42eltM/wXM3RxSUOrfureZxEd6Dt6NXyFoJ7E8lnmm7znXydJsL3B7ky4HRFZI+eHrep54NZbeQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@godaddy/terminus/-/terminus-4.12.0.tgz", + "integrity": "sha512-zbl6gKxPAnAoAAGCyRN1kOMHTXgiW3C09w8McLKZWSSHQlsiRZlMZzBwSv1aK9PaRU25w80cnOlt3ow+uQwR1Q==", "requires": { "stoppable": "^1.1.0" } @@ -15981,37 +16063,37 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@sentry-internal/tracing": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.47.0.tgz", - "integrity": "sha512-udpHnCzF8DQsWf0gQwd0XFGp6Y8MOiwnl8vGt2ohqZGS3m1+IxoRLXsSkD8qmvN6KKDnwbaAvYnK0z0L+AW95g==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.49.0.tgz", + "integrity": "sha512-ESh3+ZneQk/3HESTUmIPNrW5GVPu/HrRJU+eAJJto74vm+6vP7zDn2YV2gJ1w18O/37nc7W/bVCgZJlhZ3cwew==", "requires": { - "@sentry/core": "7.47.0", - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/core": "7.49.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "tslib": "^1.9.3" }, "dependencies": { "@sentry/core": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.47.0.tgz", - "integrity": "sha512-EFhZhKdMu7wKmWYZwbgTi8FNZ7Fq+HdlXiZWNz51Bqe3pHmfAkdHtAEs0Buo0v623MKA0CA4EjXIazGUM34XTg==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.49.0.tgz", + "integrity": "sha512-AlSnCYgfEbvK8pkNluUkmdW/cD9UpvOVCa+ERQswXNRkAv5aDGCL6Ihv6fnIajE++BYuwZh0+HwZUBVKTFzoZg==", "requires": { - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "tslib": "^1.9.3" } }, "@sentry/types": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.47.0.tgz", - "integrity": "sha512-GxXocplN0j1+uczovHrfkykl9wvkamDtWxlPUQgyGlbLGZn+UH1Y79D4D58COaFWGEZdSNKr62gZAjfEYu9nQA==" + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.49.0.tgz", + "integrity": "sha512-9yXXh7iv76+O6h2ONUVx0wsL1auqJFWez62mTjWk4350SgMmWp/zUkBxnVXhmcYqscz/CepC+Loz9vITLXtgxg==" }, "@sentry/utils": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.47.0.tgz", - "integrity": "sha512-A89SaOLp6XeZfByeYo2C8Ecye/YAtk/gENuyOUhQEdMulI6mZdjqtHAp7pTMVgkBc/YNARVuoa+kR/IdRrTPkQ==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.49.0.tgz", + "integrity": "sha512-JdC9yGnOgev4ISJVwmIoFsk8Zx0psDZJAj2DV7x4wMZsO6QK+YjC7G3mUED/S5D5lsrkBZ/3uvQQhr8DQI4UcQ==", "requires": { - "@sentry/types": "7.47.0", + "@sentry/types": "7.49.0", "tslib": "^1.9.3" } }, @@ -16022,15 +16104,32 @@ } } }, - "@sentry/node": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.47.0.tgz", - "integrity": "sha512-LTg2r5EV9yh4GLYDF+ViSltR9LLj/pcvk8YhANJcMO3Fp//xh8njcdU0FC2yNthUREawYDzAsVzLyCYJfV0H1A==", + "@sentry/core": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.48.0.tgz", + "integrity": "sha512-8FYuJTMpyuxRZvlen3gQ3rpOtVInSDmSyXqWEhCLuG/w34AtWoTiW7G516rsAAh6Hy1TP91GooMWbonP3XQNTQ==", "requires": { - "@sentry-internal/tracing": "7.47.0", - "@sentry/core": "7.47.0", - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/types": "7.48.0", + "@sentry/utils": "7.48.0", + "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@sentry/node": { + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.49.0.tgz", + "integrity": "sha512-KLIrqcbKk4yR3g8fjl87Eyv4M9j4YI6b7sqVAZYj3FrX3mC6JQyGdlDfUpSKy604n1iAdr6OuUp5f9x7jPJaeQ==", + "requires": { + "@sentry-internal/tracing": "7.49.0", + "@sentry/core": "7.49.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "cookie": "^0.4.1", "https-proxy-agent": "^5.0.0", "lru_map": "^0.3.3", @@ -16038,26 +16137,26 @@ }, "dependencies": { "@sentry/core": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.47.0.tgz", - "integrity": "sha512-EFhZhKdMu7wKmWYZwbgTi8FNZ7Fq+HdlXiZWNz51Bqe3pHmfAkdHtAEs0Buo0v623MKA0CA4EjXIazGUM34XTg==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.49.0.tgz", + "integrity": "sha512-AlSnCYgfEbvK8pkNluUkmdW/cD9UpvOVCa+ERQswXNRkAv5aDGCL6Ihv6fnIajE++BYuwZh0+HwZUBVKTFzoZg==", "requires": { - "@sentry/types": "7.47.0", - "@sentry/utils": "7.47.0", + "@sentry/types": "7.49.0", + "@sentry/utils": "7.49.0", "tslib": "^1.9.3" } }, "@sentry/types": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.47.0.tgz", - "integrity": "sha512-GxXocplN0j1+uczovHrfkykl9wvkamDtWxlPUQgyGlbLGZn+UH1Y79D4D58COaFWGEZdSNKr62gZAjfEYu9nQA==" + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.49.0.tgz", + "integrity": "sha512-9yXXh7iv76+O6h2ONUVx0wsL1auqJFWez62mTjWk4350SgMmWp/zUkBxnVXhmcYqscz/CepC+Loz9vITLXtgxg==" }, "@sentry/utils": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.47.0.tgz", - "integrity": "sha512-A89SaOLp6XeZfByeYo2C8Ecye/YAtk/gENuyOUhQEdMulI6mZdjqtHAp7pTMVgkBc/YNARVuoa+kR/IdRrTPkQ==", + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.49.0.tgz", + "integrity": "sha512-JdC9yGnOgev4ISJVwmIoFsk8Zx0psDZJAj2DV7x4wMZsO6QK+YjC7G3mUED/S5D5lsrkBZ/3uvQQhr8DQI4UcQ==", "requires": { - "@sentry/types": "7.47.0", + "@sentry/types": "7.49.0", "tslib": "^1.9.3" } }, @@ -16069,11 +16168,50 @@ } }, "@sentry/tracing": { - "version": "7.47.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.47.0.tgz", - "integrity": "sha512-hJCpKdekwaFNbCVXxfCz5IxfSEJIKnkPmRSVHITOm5VhKwq2e5kmy4Rn6bzSETwJFSDE8LGbR/3eSfGTqw37XA==", + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.48.0.tgz", + "integrity": "sha512-X6w74Av0fyayNicKIlwL1IdpZ3O0ETQjyYXCDTwHoJL71ojrgrL5vdiNz8WwbPONTnqu98HehPYL/z3DCCKVbw==", "requires": { - "@sentry-internal/tracing": "7.47.0" + "@sentry-internal/tracing": "7.48.0" + }, + "dependencies": { + "@sentry-internal/tracing": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.48.0.tgz", + "integrity": "sha512-MFAPDTrvCtfSm0/Zbmx7HA0Q5uCfRadOUpN8Y8rP1ndz+329h2kA3mZRCuC+3/aXL11zs2CHUhcAkGjwH2vogg==", + "requires": { + "@sentry/core": "7.48.0", + "@sentry/types": "7.48.0", + "@sentry/utils": "7.48.0", + "tslib": "^1.9.3" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@sentry/types": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.48.0.tgz", + "integrity": "sha512-kkAszZwQ5/v4n7Yyw/DPNRWx7h724mVNRGZIJa9ggUMvTgMe7UKCZZ5wfQmYiKVlGbwd9pxXAcP8Oq15EbByFQ==" + }, + "@sentry/utils": { + "version": "7.48.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.48.0.tgz", + "integrity": "sha512-d977sghkFVMfld0LrEyyY2gYrfayLPdDEpUDT+hg5y79r7zZDCFyHtdB86699E5K89MwDZahW7Erk+a1nk4x5w==", + "requires": { + "@sentry/types": "7.48.0", + "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "@sinclair/typebox": { @@ -16835,9 +16973,9 @@ "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==" }, "aws-sdk": { - "version": "2.1358.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1358.0.tgz", - "integrity": "sha512-ZolqFlnm0mDNgub7FGrVi7r5A1rw+58zZziKhlis3IxOtIpHdx4BQU5pH4htAMuD0Ct557p/dC/wmnZH/1Rc9Q==", + "version": "2.1364.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1364.0.tgz", + "integrity": "sha512-PFoq9Rnu0DVi07wZ/SjKlrJDwso8AxE5q/ufLdNtINZPaSkB92OqKYVdlfQ4srsH2ala2NCrg8gFX98SCmqW3w==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -17246,6 +17384,11 @@ "wrap-ansi": "^7.0.0" } }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -19589,6 +19732,14 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, + "node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "requires": { + "clone": "2.x" + } + }, "node-fetch": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", diff --git a/backend/package.json b/backend/package.json index c3a173a7b..137c9d9d1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,15 +1,15 @@ { "dependencies": { - "@aws-sdk/client-secrets-manager": "^3.309.0", - "@godaddy/terminus": "^4.11.2", + "@aws-sdk/client-secrets-manager": "^3.319.0", + "@godaddy/terminus": "^4.12.0", "@octokit/rest": "^19.0.5", - "@sentry/node": "^7.41.0", - "@sentry/tracing": "^7.47.0", + "@sentry/node": "^7.49.0", + "@sentry/tracing": "^7.48.0", "@types/crypto-js": "^4.1.1", "@types/libsodium-wrappers": "^0.7.10", "argon2": "^0.30.3", "await-to-js": "^3.0.0", - "aws-sdk": "^2.1338.0", + "aws-sdk": "^2.1364.0", "axios": "^1.3.5", "axios-retry": "^3.4.0", "bcrypt": "^5.1.0", @@ -31,6 +31,7 @@ "libsodium-wrappers": "^0.7.10", "lodash": "^4.17.21", "mongoose": "^6.10.5", + "node-cache": "^5.1.2", "nodemailer": "^6.8.0", "posthog-node": "^2.6.0", "query-string": "^7.1.3", diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index b61db8811..d73b17a72 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -5,18 +5,15 @@ export const client = new InfisicalClient({ }); export const getPort = async () => (await client.getSecret('PORT')).secretValue || 4000; -export const getInviteOnlySignup = async () => (await client.getSecret('INVITE_ONLY_SIGNUP')).secretValue == undefined ? false : (await client.getSecret('INVITE_ONLY_SIGNUP')).secretValue; - export const getEncryptionKey = async () => { const secretValue = (await client.getSecret('ENCRYPTION_KEY')).secretValue; return secretValue === '' ? undefined : secretValue; } - export const getRootEncryptionKey = async () => { const secretValue = (await client.getSecret('ROOT_ENCRYPTION_KEY')).secretValue; return secretValue === '' ? undefined : secretValue; } - +export const getInviteOnlySignup = async () => (await client.getSecret('INVITE_ONLY_SIGNUP')).secretValue === 'true' export const getSaltRounds = async () => parseInt((await client.getSecret('SALT_ROUNDS')).secretValue) || 10; export const getJwtAuthLifetime = async () => (await client.getSecret('JWT_AUTH_LIFETIME')).secretValue || '10d'; export const getJwtAuthSecret = async () => (await client.getSecret('JWT_AUTH_SECRET')).secretValue; @@ -55,12 +52,25 @@ export const getSmtpUsername = async () => (await client.getSecret('SMTP_USERNAM export const getSmtpPassword = async () => (await client.getSecret('SMTP_PASSWORD')).secretValue; export const getSmtpFromAddress = async () => (await client.getSecret('SMTP_FROM_ADDRESS')).secretValue; export const getSmtpFromName = async () => (await client.getSecret('SMTP_FROM_NAME')).secretValue || 'Infisical'; + +export const getLicenseKey = async () => { + const secretValue = (await client.getSecret('LICENSE_KEY')).secretValue; + return secretValue === '' ? undefined : secretValue; +} +export const getLicenseServerKey = async () => { + const secretValue = (await client.getSecret('LICENSE_SERVER_KEY')).secretValue; + return secretValue === '' ? undefined : secretValue; +} +export const getLicenseServerUrl = async () => (await client.getSecret('LICENSE_SERVER_URL')).secretValue || 'https://portal.infisical.com'; + +// TODO: deprecate from here export const getStripeProductStarter = async () => (await client.getSecret('STRIPE_PRODUCT_STARTER')).secretValue; export const getStripeProductPro = async () => (await client.getSecret('STRIPE_PRODUCT_PRO')).secretValue; export const getStripeProductTeam = async () => (await client.getSecret('STRIPE_PRODUCT_TEAM')).secretValue; export const getStripePublishableKey = async () => (await client.getSecret('STRIPE_PUBLISHABLE_KEY')).secretValue; export const getStripeSecretKey = async () => (await client.getSecret('STRIPE_SECRET_KEY')).secretValue; export const getStripeWebhookSecret = async () => (await client.getSecret('STRIPE_WEBHOOK_SECRET')).secretValue; + export const getTelemetryEnabled = async () => (await client.getSecret('TELEMETRY_ENABLED')).secretValue !== 'false' && true; export const getLoopsApiKey = async () => (await client.getSecret('LOOPS_API_KEY')).secretValue; export const getSmtpConfigured = async () => (await client.getSecret('SMTP_HOST')).secretValue == '' || (await client.getSecret('SMTP_HOST')).secretValue == undefined ? false : true diff --git a/backend/src/config/request.ts b/backend/src/config/request.ts index 2a9a8279a..e13469657 100644 --- a/backend/src/config/request.ts +++ b/backend/src/config/request.ts @@ -1,10 +1,24 @@ import axios from 'axios'; import axiosRetry from 'axios-retry'; +import { + getLicenseServerKeyAuthToken, + setLicenseServerKeyAuthToken, + getLicenseKeyAuthToken, + setLicenseKeyAuthToken +} from './storage'; +import { + getLicenseKey, + getLicenseServerKey, + getLicenseServerUrl +} from './index'; -const axiosInstance = axios.create(); +// should have JWT to interact with the license server +export const licenseServerKeyRequest = axios.create(); +export const licenseKeyRequest = axios.create(); +export const standardRequest = axios.create(); // add retry functionality to the axios instance -axiosRetry(axiosInstance, { +axiosRetry(standardRequest, { retries: 3, retryDelay: axiosRetry.exponentialDelay, // exponential back-off delay between retries retryCondition: (error) => { @@ -13,4 +27,98 @@ axiosRetry(axiosInstance, { }, }); -export default axiosInstance; \ No newline at end of file +export const refreshLicenseServerKeyToken = async () => { + const licenseServerKey = await getLicenseServerKey(); + const licenseServerUrl = await getLicenseServerUrl(); + + const { data: { token } } = await standardRequest.post( + `${licenseServerUrl}/api/auth/v1/license-server-login`, {}, + { + headers: { + 'X-API-KEY': licenseServerKey + } + } + ); + + setLicenseServerKeyAuthToken(token); + + return token; +} + +export const refreshLicenseKeyToken = async () => { + const licenseKey = await getLicenseKey(); + const licenseServerUrl = await getLicenseServerUrl(); + + const { data: { token } } = await standardRequest.post( + `${licenseServerUrl}/api/auth/v1/license-login`, {}, + { + headers: { + 'X-API-KEY': licenseKey + } + } + ); + + setLicenseKeyAuthToken(token); + + return token; +} + +licenseServerKeyRequest.interceptors.request.use((config) => { + const token = getLicenseServerKeyAuthToken(); + + if (token && config.headers) { + // eslint-disable-next-line no-param-reassign + config.headers.Authorization = `Bearer ${token}`; + } + return config; +}, (err) => { + return Promise.reject(err); +}); + +licenseServerKeyRequest.interceptors.response.use((response) => { + return response +}, async function (err) { + const originalRequest = err.config; + + if (err.response.status === 401 && !originalRequest._retry) { + originalRequest._retry = true; + + // refresh + const token = await refreshLicenseServerKeyToken(); + + axios.defaults.headers.common['Authorization'] = 'Bearer ' + token; + return licenseServerKeyRequest(originalRequest); + } + + return Promise.reject(err); +}); + +licenseKeyRequest.interceptors.request.use((config) => { + const token = getLicenseKeyAuthToken(); + + if (token && config.headers) { + // eslint-disable-next-line no-param-reassign + config.headers.Authorization = `Bearer ${token}`; + } + return config; +}, (err) => { + return Promise.reject(err); +}); + +licenseKeyRequest.interceptors.response.use((response) => { + return response +}, async function (err) { + const originalRequest = err.config; + + if (err.response.status === 401 && !originalRequest._retry) { + originalRequest._retry = true; + + // refresh + const token = await refreshLicenseKeyToken(); + + axios.defaults.headers.common['Authorization'] = 'Bearer ' + token; + return licenseKeyRequest(originalRequest); + } + + return Promise.reject(err); +}); \ No newline at end of file diff --git a/backend/src/config/storage.ts b/backend/src/config/storage.ts new file mode 100644 index 000000000..5638561ac --- /dev/null +++ b/backend/src/config/storage.ts @@ -0,0 +1,30 @@ +const MemoryLicenseServerKeyTokenStorage = () => { + let authToken: string; + + return { + setToken: (token: string) => { + authToken = token; + }, + getToken: () => authToken + }; +}; + +const MemoryLicenseKeyTokenStorage = () => { + let authToken: string; + + return { + setToken: (token: string) => { + authToken = token; + }, + getToken: () => authToken + }; +}; + +const licenseServerTokenStorage = MemoryLicenseServerKeyTokenStorage(); +const licenseTokenStorage = MemoryLicenseKeyTokenStorage(); + +export const getLicenseServerKeyAuthToken = licenseServerTokenStorage.getToken; +export const setLicenseServerKeyAuthToken = licenseServerTokenStorage.setToken; + +export const getLicenseKeyAuthToken = licenseTokenStorage.getToken; +export const setLicenseKeyAuthToken = licenseTokenStorage.setToken; \ No newline at end of file diff --git a/backend/src/controllers/v1/integrationAuthController.ts b/backend/src/controllers/v1/integrationAuthController.ts index a472598d1..97032aaa4 100644 --- a/backend/src/controllers/v1/integrationAuthController.ts +++ b/backend/src/controllers/v1/integrationAuthController.ts @@ -16,7 +16,7 @@ import { INTEGRATION_VERCEL_API_URL, INTEGRATION_RAILWAY_API_URL } from '../../variables'; -import request from '../../config/request'; +import { standardRequest } from '../../config/request'; /*** * Return integration authorization with id [integrationAuthId] @@ -231,7 +231,7 @@ export const getIntegrationAuthVercelBranches = async (req: Request, res: Respon let branches: string[] = []; if (appId && appId !== '') { - const { data }: { data: VercelBranch[] } = await request.get( + const { data }: { data: VercelBranch[] } = await standardRequest.get( `${INTEGRATION_VERCEL_API_URL}/v1/integrations/git-branches`, { params, @@ -294,7 +294,7 @@ export const getIntegrationAuthRailwayEnvironments = async (req: Request, res: R projectId: appId } - const { data: { data: { environments: { edges } } } } = await request.post(INTEGRATION_RAILWAY_API_URL, { + const { data: { data: { environments: { edges } } } } = await standardRequest.post(INTEGRATION_RAILWAY_API_URL, { query, variables, }, { @@ -374,7 +374,7 @@ export const getIntegrationAuthRailwayServices = async (req: Request, res: Respo id: appId } - const { data: { data: { project: { services: { edges } } } } } = await request.post(INTEGRATION_RAILWAY_API_URL, { + const { data: { data: { project: { services: { edges } } } } } = await standardRequest.post(INTEGRATION_RAILWAY_API_URL, { query, variables }, { diff --git a/backend/src/controllers/v1/membershipOrgController.ts b/backend/src/controllers/v1/membershipOrgController.ts index e5714516e..60cdc9691 100644 --- a/backend/src/controllers/v1/membershipOrgController.ts +++ b/backend/src/controllers/v1/membershipOrgController.ts @@ -135,6 +135,7 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => { } if (!inviteeMembershipOrg) { + await new MembershipOrg({ user: invitee, inviteEmail: inviteeEmail, @@ -246,6 +247,10 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => { // membership can be approved and redirected to login/dashboard membershipOrg.status = ACCEPTED; await membershipOrg.save(); + + await updateSubscriptionOrgQuantity({ + organizationId + }); return res.status(200).send({ message: 'Successfully verified email', diff --git a/backend/src/controllers/v1/organizationController.ts b/backend/src/controllers/v1/organizationController.ts index 17103a7a6..b9fbc9f4b 100644 --- a/backend/src/controllers/v1/organizationController.ts +++ b/backend/src/controllers/v1/organizationController.ts @@ -19,7 +19,8 @@ export const getOrganizations = async (req: Request, res: Response) => { try { organizations = ( await MembershipOrg.find({ - user: req.user._id + user: req.user._id, + status: ACCEPTED }).populate('organization') ).map((m) => m.organization); } catch (err) { diff --git a/backend/src/controllers/v1/secretsFolderController.ts b/backend/src/controllers/v1/secretsFolderController.ts index 2e856c2a4..d20456577 100644 --- a/backend/src/controllers/v1/secretsFolderController.ts +++ b/backend/src/controllers/v1/secretsFolderController.ts @@ -86,4 +86,22 @@ export const deleteFolder = async (req: Request, res: Response) => { } res.send() +} + +// TODO: validate workspace +export const getFolderById = async (req: Request, res: Response) => { + const { folderId } = req.params + + const folder = await Folder.findById(folderId); + if (!folder) { + throw BadRequestError({ message: "The folder doesn't exist" }) + } + // check that user is a member of the workspace + await validateMembership({ + userId: req.user._id.toString(), + workspaceId: folder.workspace as any, + acceptedRoles: [ADMIN, MEMBER] + }); + + res.send({ folder }) } \ No newline at end of file diff --git a/backend/src/controllers/v1/signupController.ts b/backend/src/controllers/v1/signupController.ts index b035eb3e8..681b65459 100644 --- a/backend/src/controllers/v1/signupController.ts +++ b/backend/src/controllers/v1/signupController.ts @@ -21,14 +21,6 @@ export const beginEmailSignup = async (req: Request, res: Response) => { try { email = req.body.email; - if (await getInviteOnlySignup()) { - // Only one user can create an account without being invited. The rest need to be invited in order to make an account - const userCount = await User.countDocuments({}) - if (userCount != 0) { - throw BadRequestError({ message: "New user sign ups are not allowed at this time. You must be invited to sign up." }) - } - } - const user = await User.findOne({ email }).select('+publicKey'); if (user && user?.publicKey) { // case: user has already completed account @@ -74,6 +66,14 @@ export const verifyEmailSignup = async (req: Request, res: Response) => { }); } + if (await getInviteOnlySignup()) { + // Only one user can create an account without being invited. The rest need to be invited in order to make an account + const userCount = await User.countDocuments({}) + if (userCount != 0) { + throw BadRequestError({ message: "New user sign ups are not allowed at this time. You must be invited to sign up." }) + } + } + // verify email if (await getSmtpConfigured()) { await checkEmailVerification({ diff --git a/backend/src/controllers/v2/secretsController.ts b/backend/src/controllers/v2/secretsController.ts index a3773f815..ef170ca0f 100644 --- a/backend/src/controllers/v2/secretsController.ts +++ b/backend/src/controllers/v2/secretsController.ts @@ -1,11 +1,9 @@ -import to from 'await-to-js'; import { Types } from 'mongoose'; import { Request, Response } from 'express'; -import { ISecret, Secret } from '../../models'; +import { ISecret, Secret, Workspace } from '../../models'; import { IAction, SecretVersion } from '../../ee/models'; import { SECRET_PERSONAL, - SECRET_SHARED, ACTION_ADD_SECRETS, ACTION_READ_SECRETS, ACTION_UPDATE_SECRETS, @@ -13,16 +11,16 @@ import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_UTF8 } from '../../variables'; -import { UnauthorizedRequestError, ValidationError } from '../../utils/errors'; +import { UnauthorizedRequestError, WorkspaceNotFoundError } from '../../utils/errors'; import { EventService } from '../../services'; import { eventPushSecrets } from '../../events'; -import { EESecretService, EELogService } from '../../ee/services'; +import { EESecretService, EELogService, EELicenseService } from '../../ee/services'; import { TelemetryService, SecretService } from '../../services'; import { getChannelFromUserAgent } from '../../utils/posthog'; import { PERMISSION_WRITE_SECRETS } from '../../variables'; import { userHasNoAbility, userHasWorkspaceAccess, userHasWriteOnlyAbility } from '../../ee/helpers/checkMembershipPermissions'; import Tag from '../../models/tag'; -import _, { eq } from 'lodash'; +import _ from 'lodash'; import { BatchSecretRequest, BatchSecret @@ -50,6 +48,12 @@ export const batchSecrets = async (req: Request, res: Response) => { environment: string; requests: BatchSecretRequest[]; } = req.body; + + const workspace = await Workspace.findById(workspaceId); + if (!workspace) throw WorkspaceNotFoundError(); + + const orgPlan = await EELicenseService.getOrganizationPlan(workspace.organization.toString()); + const isPaid = orgPlan.tier >= 1; const createSecrets: BatchSecret[] = []; const updateSecrets: BatchSecret[] = []; @@ -145,7 +149,8 @@ export const batchSecrets = async (req: Request, res: Response) => { environment, workspaceId, channel, - userAgent: req.headers?.['user-agent'] + userAgent: req.headers?.['user-agent'], + isPaid } }); } @@ -234,7 +239,8 @@ export const batchSecrets = async (req: Request, res: Response) => { environment, workspaceId, channel, - userAgent: req.headers?.['user-agent'] + userAgent: req.headers?.['user-agent'], + isPaid } }); } @@ -269,7 +275,8 @@ export const batchSecrets = async (req: Request, res: Response) => { environment, workspaceId, channel: channel, - userAgent: req.headers?.['user-agent'] + userAgent: req.headers?.['user-agent'], + isPaid } }); } @@ -384,6 +391,12 @@ export const createSecrets = async (req: Request, res: Response) => { } } + const workspace = await Workspace.findById(workspaceId); + if (!workspace) throw WorkspaceNotFoundError(); + + const orgPlan = await EELicenseService.getOrganizationPlan(workspace.organization.toString()); + const isPaid = orgPlan.tier >= 1; + let listOfSecretsToCreate; if (Array.isArray(req.body.secrets)) { // case: create multiple secrets @@ -543,7 +556,8 @@ export const createSecrets = async (req: Request, res: Response) => { environment, workspaceId, channel: channel, - userAgent: req.headers?.['user-agent'] + userAgent: req.headers?.['user-agent'], + isPaid } }); } @@ -607,6 +621,12 @@ export const getSecrets = async (req: Request, res: Response) => { const normalizedPath = normalizePath(secretsPath as string) const folders = await getFoldersInDirectory(workspaceId as string, environment as string, normalizedPath) + const workspace = await Workspace.findById(workspaceId); + if (!workspace) throw WorkspaceNotFoundError(); + + const orgPlan = await EELicenseService.getOrganizationPlan(workspace.organization.toString()); + const isPaid = orgPlan.tier >= 1; + // secrets to return let secrets: ISecret[] = []; @@ -739,7 +759,8 @@ export const getSecrets = async (req: Request, res: Response) => { environment, workspaceId, channel, - userAgent: req.headers?.['user-agent'] + userAgent: req.headers?.['user-agent'], + isPaid } }); } @@ -954,6 +975,12 @@ export const updateSecrets = async (req: Request, res: Response) => { workspaceId: new Types.ObjectId(key) }) + const workspace = await Workspace.findById(key); + if (!workspace) throw WorkspaceNotFoundError(); + + const orgPlan = await EELicenseService.getOrganizationPlan(workspace.organization.toString()); + const isPaid = orgPlan.tier >= 1; + const postHogClient = await TelemetryService.getPostHogClient(); if (postHogClient) { postHogClient.capture({ @@ -966,7 +993,8 @@ export const updateSecrets = async (req: Request, res: Response) => { environment: workspaceSecretObj[key][0].environment, workspaceId: key, channel: channel, - userAgent: req.headers?.['user-agent'] + userAgent: req.headers?.['user-agent'], + isPaid } }); } @@ -1088,6 +1116,12 @@ export const deleteSecrets = async (req: Request, res: Response) => { workspaceId: new Types.ObjectId(key) }); + const workspace = await Workspace.findById(key); + if (!workspace) throw WorkspaceNotFoundError(); + + const orgPlan = await EELicenseService.getOrganizationPlan(workspace.organization.toString()); + const isPaid = orgPlan.tier >= 1; + const postHogClient = await TelemetryService.getPostHogClient(); if (postHogClient) { postHogClient.capture({ @@ -1100,7 +1134,8 @@ export const deleteSecrets = async (req: Request, res: Response) => { environment: workspaceSecretObj[key][0].environment, workspaceId: key, channel: channel, - userAgent: req.headers?.['user-agent'] + userAgent: req.headers?.['user-agent'], + isPaid } }); } diff --git a/backend/src/controllers/v2/signupController.ts b/backend/src/controllers/v2/signupController.ts index 7cfb3e454..d9e9a0447 100644 --- a/backend/src/controllers/v2/signupController.ts +++ b/backend/src/controllers/v2/signupController.ts @@ -7,8 +7,9 @@ import { } from '../../helpers/signup'; import { issueAuthTokens } from '../../helpers/auth'; import { INVITED, ACCEPTED } from '../../variables'; -import request from '../../config/request'; +import { standardRequest } from '../../config/request'; import { getLoopsApiKey, getHttpsEnabled } from '../../config'; +import { updateSubscriptionOrgQuantity } from '../../helpers/organization'; /** * Complete setting up user by adding their personal and auth information as part of the @@ -87,6 +88,19 @@ export const completeAccountSignup = async (req: Request, res: Response) => { user }); + // update organization membership statuses that are + // invited to completed with user attached + const membershipsToUpdate = await MembershipOrg.find({ + inviteEmail: email, + status: INVITED + }); + + membershipsToUpdate.forEach(async (membership) => { + await updateSubscriptionOrgQuantity({ + organizationId: membership.organization.toString() + }); + }); + // update organization membership statuses that are // invited to completed with user attached await MembershipOrg.updateMany( @@ -109,7 +123,7 @@ export const completeAccountSignup = async (req: Request, res: Response) => { // sending a welcome email to new users if (await getLoopsApiKey()) { - await request.post("https://app.loops.so/api/v1/events/send", { + await standardRequest.post("https://app.loops.so/api/v1/events/send", { "email": email, "eventName": "Sign Up", "firstName": firstName, @@ -206,9 +220,20 @@ export const completeAccountInvite = async (req: Request, res: Response) => { if (!user) throw new Error('Failed to complete account for non-existent user'); - + // update organization membership statuses that are // invited to completed with user attached + const membershipsToUpdate = await MembershipOrg.find({ + inviteEmail: email, + status: INVITED + }); + + membershipsToUpdate.forEach(async (membership) => { + await updateSubscriptionOrgQuantity({ + organizationId: membership.organization.toString() + }); + }); + await MembershipOrg.updateMany( { inviteEmail: email, diff --git a/backend/src/ee/controllers/v1/cloudProductsController.ts b/backend/src/ee/controllers/v1/cloudProductsController.ts new file mode 100644 index 000000000..54584ce82 --- /dev/null +++ b/backend/src/ee/controllers/v1/cloudProductsController.ts @@ -0,0 +1,34 @@ +import * as Sentry from '@sentry/node'; +import { Request, Response } from 'express'; +import { EELicenseService } from '../../services'; +import { getLicenseServerUrl } from '../../../config'; +import { licenseServerKeyRequest } from '../../../config/request'; + +/** + * Return available cloud product information. + * Note: Nicely formatted to easily construct a table from + * @param req + * @param res + * @returns + */ +export const getCloudProducts = async (req: Request, res: Response) => { + try { + const billingCycle = req.query['billing-cycle'] as string; + + if (EELicenseService.instanceType === 'cloud') { + const { data } = await licenseServerKeyRequest.get( + `${await getLicenseServerUrl()}/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}` + ); + + return res.status(200).send(data); + } + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + } + + return res.status(200).send({ + head: [], + rows: [] + }); +} \ No newline at end of file diff --git a/backend/src/ee/controllers/v1/index.ts b/backend/src/ee/controllers/v1/index.ts index aaa697286..bf3992b17 100644 --- a/backend/src/ee/controllers/v1/index.ts +++ b/backend/src/ee/controllers/v1/index.ts @@ -1,15 +1,19 @@ import * as stripeController from './stripeController'; import * as secretController from './secretController'; import * as secretSnapshotController from './secretSnapshotController'; +import * as organizationsController from './organizationsController'; import * as workspaceController from './workspaceController'; import * as actionController from './actionController'; import * as membershipController from './membershipController'; +import * as cloudProductsController from './cloudProductsController'; export { stripeController, secretController, secretSnapshotController, + organizationsController, workspaceController, actionController, - membershipController + membershipController, + cloudProductsController } \ No newline at end of file diff --git a/backend/src/ee/controllers/v1/organizationsController.ts b/backend/src/ee/controllers/v1/organizationsController.ts new file mode 100644 index 000000000..2dd212e77 --- /dev/null +++ b/backend/src/ee/controllers/v1/organizationsController.ts @@ -0,0 +1,83 @@ +import { Request, Response } from 'express'; +import { getLicenseServerUrl } from '../../../config'; +import { licenseServerKeyRequest } from '../../../config/request'; +import { EELicenseService } from '../../services'; + +/** + * Return the organization's current plan and allowed feature set + */ +export const getOrganizationPlan = async (req: Request, res: Response) => { + const { organizationId } = req.params; + + const plan = await EELicenseService.getOrganizationPlan(organizationId); + + return res.status(200).send({ + plan, + }); +} + +/** + * Update the organization plan to product with id [productId] + * @param req + * @param res + * @returns + */ +export const updateOrganizationPlan = async (req: Request, res: Response) => { + const { + productId + } = req.body; + + const { data } = await licenseServerKeyRequest.patch( + `${await getLicenseServerUrl()}/api/license-server/v1/customers/${req.organization.customerId}/cloud-plan`, + { + productId + } + ); + + return res.status(200).send(data); +} + +/** + * Return the organization's payment methods on file + */ +export const getOrganizationPmtMethods = async (req: Request, res: Response) => { + const { data: { pmtMethods } } = await licenseServerKeyRequest.get( + `${await getLicenseServerUrl()}/api/license-server/v1/customers/${req.organization.customerId}/billing-details/payment-methods` + ); + + return res.status(200).send({ + pmtMethods + }); +} + +/** + * Return a Stripe session URL to add payment method for organization + */ +export const addOrganizationPmtMethod = async (req: Request, res: Response) => { + const { + success_url, + cancel_url + } = req.body; + + const { data: { url } } = await licenseServerKeyRequest.post( + `${await getLicenseServerUrl()}/api/license-server/v1/customers/${req.organization.customerId}/billing-details/payment-methods`, + { + success_url, + cancel_url + } + ); + + return res.status(200).send({ + url + }); +} + +export const deleteOrganizationPmtMethod = async (req: Request, res: Response) => { + const { pmtMethodId } = req.params; + + const { data } = await licenseServerKeyRequest.delete( + `${await getLicenseServerUrl()}/api/license-server/v1/customers/${req.organization.customerId}/billing-details/payment-methods/${pmtMethodId}`, + ); + + return res.status(200).send(data); +} \ No newline at end of file diff --git a/backend/src/ee/routes/v1/cloudProducts.ts b/backend/src/ee/routes/v1/cloudProducts.ts new file mode 100644 index 000000000..73af00aca --- /dev/null +++ b/backend/src/ee/routes/v1/cloudProducts.ts @@ -0,0 +1,20 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + validateRequest +} from '../../../middleware'; +import { query } from 'express-validator'; +import { cloudProductsController } from '../../controllers/v1'; + +router.get( + '/', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + query('billing-cycle').exists().isIn(['monthly', 'yearly']), + validateRequest, + cloudProductsController.getCloudProducts +); + +export default router; \ No newline at end of file diff --git a/backend/src/ee/routes/v1/index.ts b/backend/src/ee/routes/v1/index.ts index 612715111..7568e45d6 100644 --- a/backend/src/ee/routes/v1/index.ts +++ b/backend/src/ee/routes/v1/index.ts @@ -1,11 +1,15 @@ import secret from './secret'; import secretSnapshot from './secretSnapshot'; +import organizations from './organizations'; import workspace from './workspace'; import action from './action'; +import cloudProducts from './cloudProducts'; export { secret, secretSnapshot, + organizations, workspace, - action + action, + cloudProducts } \ No newline at end of file diff --git a/backend/src/ee/routes/v1/organizations.ts b/backend/src/ee/routes/v1/organizations.ts new file mode 100644 index 000000000..fd9fd08e9 --- /dev/null +++ b/backend/src/ee/routes/v1/organizations.ts @@ -0,0 +1,87 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + requireOrganizationAuth, + validateRequest +} from '../../../middleware'; +import { param, body } from 'express-validator'; +import { organizationsController } from '../../controllers/v1'; +import { + OWNER, ADMIN, MEMBER, ACCEPTED +} from '../../../variables'; + +router.get( + '/:organizationId/plan', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN, MEMBER], + acceptedStatuses: [ACCEPTED] + }), + param('organizationId').exists().trim(), + validateRequest, + organizationsController.getOrganizationPlan +); + +router.patch( + '/:organizationId/plan', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN, MEMBER], + acceptedStatuses: [ACCEPTED] + }), + param('organizationId').exists().trim(), + body('productId').exists().isString(), + validateRequest, + organizationsController.updateOrganizationPlan +); + +router.get( + '/:organizationId/billing-details/payment-methods', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN, MEMBER], + acceptedStatuses: [ACCEPTED] + }), + param('organizationId').exists().trim(), + validateRequest, + organizationsController.getOrganizationPmtMethods +); + +router.post( + '/:organizationId/billing-details/payment-methods', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN, MEMBER], + acceptedStatuses: [ACCEPTED] + }), + param('organizationId').exists().trim(), + body('success_url').exists().isString(), + body('cancel_url').exists().isString(), + validateRequest, + organizationsController.addOrganizationPmtMethod +); + +router.delete( + '/:organizationId/billing-details/payment-methods/:pmtMethodId', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN, MEMBER], + acceptedStatuses: [ACCEPTED] + }), + param('organizationId').exists().trim(), + validateRequest, + organizationsController.deleteOrganizationPmtMethod +); + +export default router; \ No newline at end of file diff --git a/backend/src/ee/routes/v1/secretSnapshot.ts b/backend/src/ee/routes/v1/secretSnapshot.ts index d10da4456..80aa7d1ee 100644 --- a/backend/src/ee/routes/v1/secretSnapshot.ts +++ b/backend/src/ee/routes/v1/secretSnapshot.ts @@ -7,7 +7,7 @@ import { requireAuth, validateRequest } from '../../../middleware'; -import { param, body } from 'express-validator'; +import { param } from 'express-validator'; import { ADMIN, MEMBER } from '../../../variables'; import { secretSnapshotController } from '../../controllers/v1'; diff --git a/backend/src/ee/services/EELicenseService.ts b/backend/src/ee/services/EELicenseService.ts index 4bd811340..a4726073f 100644 --- a/backend/src/ee/services/EELicenseService.ts +++ b/backend/src/ee/services/EELicenseService.ts @@ -1,12 +1,133 @@ +import NodeCache from 'node-cache'; +import * as Sentry from '@sentry/node'; +import { + getLicenseKey, + getLicenseServerKey, + getLicenseServerUrl +} from '../../config'; +import { + licenseKeyRequest, + licenseServerKeyRequest, + refreshLicenseServerKeyToken, + refreshLicenseKeyToken +} from '../../config/request'; +import { Organization } from '../../models'; +import { OrganizationNotFoundError } from '../../utils/errors'; + +interface FeatureSet { + _id: string | null; + slug: 'starter' | 'team' | 'pro' | 'enterprise' | null; + tier: number; + workspaceLimit: number | null; + workspacesUsed: number; + memberLimit: number | null; + membersUsed: number; + secretVersioning: boolean; + pitRecovery: boolean; + rbac: boolean; + customRateLimits: boolean; + customAlerts: boolean; + auditLogs: boolean; +} + /** - * Class to handle Enterprise Edition license actions + * Class to handle license/plan configurations: + * - Infisical Cloud: Fetch and cache customer plans in [localFeatureSet] + * - Self-hosted regular: Use default global feature set + * - Self-hosted enterprise: Fetch and update global feature set */ class EELicenseService { - private readonly _isLicenseValid: boolean; + private readonly _isLicenseValid: boolean; // TODO: deprecate + + public instanceType: 'self-hosted' | 'enterprise-self-hosted' | 'cloud' = 'self-hosted'; + + public globalFeatureSet: FeatureSet = { + _id: null, + slug: null, + tier: -1, + workspaceLimit: null, + workspacesUsed: 0, + memberLimit: null, + membersUsed: 0, + secretVersioning: true, + pitRecovery: true, + rbac: true, + customRateLimits: true, + customAlerts: true, + auditLogs: false + } + + public localFeatureSet: NodeCache; - constructor(licenseKey: string) { + constructor() { this._isLicenseValid = true; + this.localFeatureSet = new NodeCache({ + stdTTL: 300 + }); + } + + public async getOrganizationPlan(organizationId: string): Promise { + try { + if (this.instanceType === 'cloud') { + const cachedPlan = this.localFeatureSet.get(organizationId); + if (cachedPlan) { + return cachedPlan; + } + + const organization = await Organization.findById(organizationId); + if (!organization) throw OrganizationNotFoundError(); + + const { data: { currentPlan } } = await licenseServerKeyRequest.get( + `${await getLicenseServerUrl()}/api/license-server/v1/customers/${organization.customerId}/cloud-plan` + ); + + // cache fetched plan for organization + this.localFeatureSet.set(organizationId, currentPlan); + + return currentPlan; + } + } catch (err) { + return this.globalFeatureSet; + } + + return this.globalFeatureSet; + } + + public async initGlobalFeatureSet() { + const licenseServerKey = await getLicenseServerKey(); + const licenseKey = await getLicenseKey(); + + try { + if (licenseServerKey) { + // license server key is present -> validate it + const token = await refreshLicenseServerKeyToken() + + if (token) { + this.instanceType = 'cloud'; + } + + return; + } + + if (licenseKey) { + // license key is present -> validate it + const token = await refreshLicenseKeyToken(); + + if (token) { + const { data: { currentPlan } } = await licenseKeyRequest.get( + `${await getLicenseServerUrl()}/api/license/v1/plan` + ); + + this.globalFeatureSet = currentPlan; + this.instanceType = 'enterprise-self-hosted'; + } + } + } catch (err) { + // case: self-hosted free + Sentry.setUser(null); + Sentry.captureException(err); + } } public get isLicenseValid(): boolean { @@ -14,4 +135,4 @@ class EELicenseService { } } -export default new EELicenseService('N/A'); \ No newline at end of file +export default new EELicenseService(); \ No newline at end of file diff --git a/backend/src/helpers/organization.ts b/backend/src/helpers/organization.ts index b9fe4eb9c..74c5df71d 100644 --- a/backend/src/helpers/organization.ts +++ b/backend/src/helpers/organization.ts @@ -10,6 +10,16 @@ import { getStripeProductTeam, getStripeProductStarter, } from "../config"; +import { + EELicenseService +} from '../ee/services'; +import { + getLicenseServerUrl +} from '../config'; +import { + licenseServerKeyRequest, + licenseKeyRequest +} from '../config/request'; /** * Create an organization with name [name] @@ -127,30 +137,37 @@ const updateSubscriptionOrgQuantity = async ({ }); if (organization && organization.customerId) { - const quantity = await MembershipOrg.countDocuments({ - organization: organizationId, - status: ACCEPTED, - }); - - const stripe = new Stripe(await getStripeSecretKey(), { - apiVersion: "2022-08-01", - }); - - const subscription = ( - await stripe.subscriptions.list({ - customer: organization.customerId, - }) - ).data[0]; - - stripeSubscription = await stripe.subscriptions.update(subscription.id, { - items: [ + if (EELicenseService.instanceType === 'cloud') { + // instance of Infisical is a cloud instance + const quantity = await MembershipOrg.countDocuments({ + organization: new Types.ObjectId(organizationId), + status: ACCEPTED, + }); + + await licenseServerKeyRequest.patch( + `${await getLicenseServerUrl()}/api/license-server/v1/customers/${organization.customerId}/cloud-plan`, { - id: subscription.items.data[0].id, - price: subscription.items.data[0].price.id, - quantity, - }, - ], - }); + quantity + } + ); + + EELicenseService.localFeatureSet.del(organizationId); + } + + if (EELicenseService.instanceType === 'enterprise-self-hosted') { + // instance of Infisical is an enterprise self-hosted instance + + const usedSeats = await MembershipOrg.countDocuments({ + status: ACCEPTED + }); + + await licenseKeyRequest.patch( + `${await getLicenseServerUrl()}/api/license/v1/license`, + { + usedSeats + } + ); + } } return stripeSubscription; diff --git a/backend/src/index.ts b/backend/src/index.ts index 9f1bd918e..178baaacb 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,10 +1,10 @@ -import mongoose from 'mongoose'; import dotenv from 'dotenv'; dotenv.config(); import express from 'express'; import helmet from 'helmet'; import cors from 'cors'; import { DatabaseService } from './services'; +import { EELicenseService } from './ee/services'; import { setUpHealthEndpoint } from './services/health'; import cookieParser from 'cookie-parser'; import swaggerUi = require('swagger-ui-express'); @@ -17,7 +17,9 @@ import { workspace as eeWorkspaceRouter, secret as eeSecretRouter, secretSnapshot as eeSecretSnapshotRouter, - action as eeActionRouter + action as eeActionRouter, + organizations as eeOrganizationsRouter, + cloudProducts as eeCloudProductsRouter } from './ee/routes/v1'; import { signup as v1SignupRouter, @@ -62,19 +64,17 @@ import { getLogger } from './utils/logger'; import { RouteNotFoundError } from './utils/errors'; import { requestErrorHandler } from './middleware/requestErrorHandler'; import { - getMongoURL, getNodeEnv, getPort, - getSentryDSN, - getSiteURL, - getSmtpHost + getSiteURL } from './config'; import { setup } from './utils/setup'; -import { patchRouterParam } from './utils/patchAsyncRoutes'; const main = async () => { await setup(); + await EELicenseService.initGlobalFeatureSet(); + const app = express(); app.enable('trust proxy'); app.use(express.json()); @@ -101,6 +101,8 @@ const main = async () => { app.use('/api/v1/secret-snapshot', eeSecretSnapshotRouter); app.use('/api/v1/workspace', eeWorkspaceRouter); app.use('/api/v1/action', eeActionRouter); + app.use('/api/v1/organizations', eeOrganizationsRouter); + app.use('/api/v1/cloud-products', eeCloudProductsRouter); // v1 routes (default) app.use('/api/v1/signup', v1SignupRouter); diff --git a/backend/src/integrations/apps.ts b/backend/src/integrations/apps.ts index a748f199f..fa0020d61 100644 --- a/backend/src/integrations/apps.ts +++ b/backend/src/integrations/apps.ts @@ -1,6 +1,6 @@ import { Octokit } from "@octokit/rest"; import { IIntegrationAuth } from "../models"; -import request from "../config/request"; +import { standardRequest } from "../config/request"; import { INTEGRATION_AZURE_KEY_VAULT, INTEGRATION_AWS_PARAMETER_STORE, @@ -134,7 +134,7 @@ const getApps = async ({ */ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${INTEGRATION_HEROKU_API_URL}/apps`, { + await standardRequest.get(`${INTEGRATION_HEROKU_API_URL}/apps`, { headers: { Accept: "application/vnd.heroku+json; version=3", Authorization: `Bearer ${accessToken}`, @@ -164,7 +164,7 @@ const getAppsVercel = async ({ accessToken: string; }) => { const res = ( - await request.get(`${INTEGRATION_VERCEL_API_URL}/v9/projects`, { + await standardRequest.get(`${INTEGRATION_VERCEL_API_URL}/v9/projects`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json", @@ -208,7 +208,7 @@ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => { filter: 'all' }); - const { data } = await request.get( + const { data } = await standardRequest.get( `${INTEGRATION_NETLIFY_API_URL}/api/v1/sites`, { params, @@ -310,7 +310,7 @@ const getAppsGithub = async ({ accessToken }: { accessToken: string }) => { */ const getAppsRender = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${INTEGRATION_RENDER_API_URL}/v1/services`, { + await standardRequest.get(`${INTEGRATION_RENDER_API_URL}/v1/services`, { headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/json", @@ -358,7 +358,7 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => { projects: { edges }, }, }, - } = await request.post( + } = await standardRequest.post( INTEGRATION_RAILWAY_API_URL, { query, @@ -402,7 +402,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { `; const res = ( - await request.post( + await standardRequest.post( INTEGRATION_FLYIO_API_URL, { query, @@ -436,7 +436,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { */ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${INTEGRATION_CIRCLECI_API_URL}/v1.1/projects`, { + await standardRequest.get(`${INTEGRATION_CIRCLECI_API_URL}/v1.1/projects`, { headers: { "Circle-Token": accessToken, "Accept-Encoding": "application/json", @@ -455,7 +455,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${INTEGRATION_TRAVISCI_API_URL}/repos`, { + await standardRequest.get(`${INTEGRATION_TRAVISCI_API_URL}/repos`, { headers: { Authorization: `token ${accessToken}`, "Accept-Encoding": "application/json", @@ -502,7 +502,7 @@ const getAppsGitlab = async ({ per_page: String(perPage), }); - const { data } = await request.get( + const { data } = await standardRequest.get( `${INTEGRATION_GITLAB_API_URL}/v4/groups/${teamId}/projects`, { params, @@ -530,7 +530,7 @@ const getAppsGitlab = async ({ // case: fetch projects for individual in GitLab const { id } = ( - await request.get(`${INTEGRATION_GITLAB_API_URL}/v4/user`, { + await standardRequest.get(`${INTEGRATION_GITLAB_API_URL}/v4/user`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json", @@ -544,7 +544,7 @@ const getAppsGitlab = async ({ per_page: String(perPage), }); - const { data } = await request.get( + const { data } = await standardRequest.get( `${INTEGRATION_GITLAB_API_URL}/v4/users/${id}/projects`, { params, @@ -581,7 +581,7 @@ const getAppsGitlab = async ({ * @returns {String} apps.name - name of Supabase app */ const getAppsSupabase = async ({ accessToken }: { accessToken: string }) => { - const { data } = await request.get( + const { data } = await standardRequest.get( `${INTEGRATION_SUPABASE_API_URL}/v1/projects`, { headers: { diff --git a/backend/src/integrations/exchange.ts b/backend/src/integrations/exchange.ts index f7bb0222b..a4d5f5b06 100644 --- a/backend/src/integrations/exchange.ts +++ b/backend/src/integrations/exchange.ts @@ -1,4 +1,4 @@ -import request from "../config/request"; +import { standardRequest } from "../config/request"; import { INTEGRATION_AZURE_KEY_VAULT, INTEGRATION_HEROKU, @@ -142,7 +142,7 @@ const exchangeCodeAzure = async ({ code }: { code: string }) => { const accessExpiresAt = new Date(); const res: ExchangeCodeAzureResponse = ( - await request.post( + await standardRequest.post( INTEGRATION_AZURE_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -178,7 +178,7 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => { const accessExpiresAt = new Date(); const res: ExchangeCodeHerokuResponse = ( - await request.post( + await standardRequest.post( INTEGRATION_HEROKU_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -209,7 +209,7 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => { */ const exchangeCodeVercel = async ({ code }: { code: string }) => { const res: ExchangeCodeVercelResponse = ( - await request.post( + await standardRequest.post( INTEGRATION_VERCEL_TOKEN_URL, new URLSearchParams({ code: code, @@ -240,7 +240,7 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => { */ const exchangeCodeNetlify = async ({ code }: { code: string }) => { const res: ExchangeCodeNetlifyResponse = ( - await request.post( + await standardRequest.post( INTEGRATION_NETLIFY_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -252,14 +252,14 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { ) ).data; - const res2 = await request.get("https://api.netlify.com/api/v1/sites", { + const res2 = await standardRequest.get("https://api.netlify.com/api/v1/sites", { headers: { Authorization: `Bearer ${res.access_token}`, }, }); const res3 = ( - await request.get("https://api.netlify.com/api/v1/accounts", { + await standardRequest.get("https://api.netlify.com/api/v1/accounts", { headers: { Authorization: `Bearer ${res.access_token}`, }, @@ -287,7 +287,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { */ const exchangeCodeGithub = async ({ code }: { code: string }) => { const res: ExchangeCodeGithubResponse = ( - await request.get(INTEGRATION_GITHUB_TOKEN_URL, { + await standardRequest.get(INTEGRATION_GITHUB_TOKEN_URL, { params: { client_id: await getClientIdGitHub(), client_secret: await getClientSecretGitHub(), @@ -321,7 +321,7 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => { const exchangeCodeGitlab = async ({ code }: { code: string }) => { const accessExpiresAt = new Date(); const res: ExchangeCodeGitlabResponse = ( - await request.post( + await standardRequest.post( INTEGRATION_GITLAB_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", diff --git a/backend/src/integrations/refresh.ts b/backend/src/integrations/refresh.ts index 823d05e69..0c401bf15 100644 --- a/backend/src/integrations/refresh.ts +++ b/backend/src/integrations/refresh.ts @@ -1,4 +1,4 @@ -import request from "../config/request"; +import { standardRequest } from "../config/request"; import { IIntegrationAuth } from "../models"; import { INTEGRATION_AZURE_KEY_VAULT, @@ -121,7 +121,7 @@ const exchangeRefreshAzure = async ({ refreshToken: string; }) => { const accessExpiresAt = new Date(); - const { data }: { data: RefreshTokenAzureResponse } = await request.post( + const { data }: { data: RefreshTokenAzureResponse } = await standardRequest.post( INTEGRATION_AZURE_TOKEN_URL, new URLSearchParams({ client_id: await getClientIdAzure(), @@ -158,7 +158,7 @@ const exchangeRefreshHeroku = async ({ data, }: { data: RefreshTokenHerokuResponse; - } = await request.post( + } = await standardRequest.post( INTEGRATION_HEROKU_TOKEN_URL, new URLSearchParams({ grant_type: "refresh_token", @@ -193,7 +193,7 @@ const exchangeRefreshGitLab = async ({ data, }: { data: RefreshTokenGitLabResponse; - } = await request.post( + } = await standardRequest.post( INTEGRATION_GITLAB_TOKEN_URL, new URLSearchParams({ grant_type: "refresh_token", diff --git a/backend/src/integrations/sync.ts b/backend/src/integrations/sync.ts index 285f31ca7..d659af295 100644 --- a/backend/src/integrations/sync.ts +++ b/backend/src/integrations/sync.ts @@ -37,8 +37,7 @@ import { INTEGRATION_TRAVISCI_API_URL, INTEGRATION_SUPABASE_API_URL } from "../variables"; -import request from '../config/request'; -import axios from "axios"; +import { standardRequest} from '../config/request'; /** * Sync/push [secrets] to [app] in integration named [integration] @@ -215,7 +214,7 @@ const syncSecretsAzureKeyVault = async ({ let result: GetAzureKeyVaultSecret[] = []; try { while (url) { - const res = await request.get(url, { + const res = await standardRequest.get(url, { headers: { Authorization: `Bearer ${accessToken}` } @@ -242,7 +241,7 @@ const syncSecretsAzureKeyVault = async ({ lastSlashIndex = getAzureKeyVaultSecret.id.lastIndexOf('/'); } - const azureKeyVaultSecret = await request.get(`${getAzureKeyVaultSecret.id}?api-version=7.3`, { + const azureKeyVaultSecret = await standardRequest.get(`${getAzureKeyVaultSecret.id}?api-version=7.3`, { headers: { 'Authorization': `Bearer ${accessToken}` } @@ -308,7 +307,7 @@ const syncSecretsAzureKeyVault = async ({ while (!isSecretSet && maxTries > 0) { // try to set secret try { - await request.put( + await standardRequest.put( `${integration.app}/secrets/${key}?api-version=7.3`, { value @@ -325,7 +324,7 @@ const syncSecretsAzureKeyVault = async ({ } catch (err) { const error: any = err; if (error?.response?.data?.error?.innererror?.code === 'ObjectIsDeletedButRecoverable') { - await request.post( + await standardRequest.post( `${integration.app}/deletedsecrets/${key}/recover?api-version=7.3`, {}, { headers: { @@ -355,7 +354,7 @@ const syncSecretsAzureKeyVault = async ({ for await (const deleteSecret of deleteSecrets) { const { key } = deleteSecret; - await request.delete(`${integration.app}/secrets/${key}?api-version=7.3`, { + await standardRequest.delete(`${integration.app}/secrets/${key}?api-version=7.3`, { headers: { 'Authorization': `Bearer ${accessToken}` } @@ -568,7 +567,7 @@ const syncSecretsHeroku = async ({ }) => { try { const herokuSecrets = ( - await request.get( + await standardRequest.get( `${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`, { headers: { @@ -586,7 +585,7 @@ const syncSecretsHeroku = async ({ } }); - await request.patch( + await standardRequest.patch( `${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`, secrets, { @@ -642,7 +641,7 @@ const syncSecretsVercel = async ({ : {}), }; - const vercelSecrets: VercelSecret[] = (await request.get( + const vercelSecrets: VercelSecret[] = (await standardRequest.get( `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env`, { params, @@ -675,7 +674,7 @@ const syncSecretsVercel = async ({ for await (const vercelSecret of vercelSecrets) { if (vercelSecret.type === 'encrypted') { // case: secret is encrypted -> need to decrypt - const decryptedSecret = (await request.get( + const decryptedSecret = (await standardRequest.get( `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${vercelSecret.id}`, { params, @@ -747,7 +746,7 @@ const syncSecretsVercel = async ({ // Sync/push new secrets if (newSecrets.length > 0) { - await request.post( + await standardRequest.post( `${INTEGRATION_VERCEL_API_URL}/v10/projects/${integration.app}/env`, newSecrets, { @@ -763,7 +762,7 @@ const syncSecretsVercel = async ({ for await (const secret of updateSecrets) { if (secret.type !== 'sensitive') { const { id, ...updatedSecret } = secret; - await request.patch( + await standardRequest.patch( `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, updatedSecret, { @@ -778,7 +777,7 @@ const syncSecretsVercel = async ({ } for await (const secret of deleteSecrets) { - await request.delete( + await standardRequest.delete( `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, { params, @@ -837,7 +836,7 @@ const syncSecretsNetlify = async ({ }); const res = ( - await request.get( + await standardRequest.get( `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, { params: getParams, @@ -951,7 +950,7 @@ const syncSecretsNetlify = async ({ }); if (newSecrets.length > 0) { - await request.post( + await standardRequest.post( `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, newSecrets, { @@ -966,7 +965,7 @@ const syncSecretsNetlify = async ({ if (updateSecrets.length > 0) { updateSecrets.forEach(async (secret: NetlifySecret) => { - await request.patch( + await standardRequest.patch( `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, { context: secret.values[0].context, @@ -985,7 +984,7 @@ const syncSecretsNetlify = async ({ if (deleteSecrets.length > 0) { deleteSecrets.forEach(async (key: string) => { - await request.delete( + await standardRequest.delete( `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`, { params: syncParams, @@ -1000,7 +999,7 @@ const syncSecretsNetlify = async ({ if (deleteSecretValues.length > 0) { deleteSecretValues.forEach(async (secret: NetlifySecret) => { - await request.delete( + await standardRequest.delete( `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`, { params: syncParams, @@ -1151,7 +1150,7 @@ const syncSecretsRender = async ({ accessToken: string; }) => { try { - await request.put( + await standardRequest.put( `${INTEGRATION_RENDER_API_URL}/v1/services/${integration.appId}/env-vars`, Object.keys(secrets).map((key) => ({ key, @@ -1203,7 +1202,7 @@ const syncSecretsRailway = async ({ variables: secrets }; - await request.post(INTEGRATION_RAILWAY_API_URL, { + await standardRequest.post(INTEGRATION_RAILWAY_API_URL, { query, variables: { input, @@ -1261,7 +1260,7 @@ const syncSecretsFlyio = async ({ } `; - await request.post(INTEGRATION_FLYIO_API_URL, { + await standardRequest.post(INTEGRATION_FLYIO_API_URL, { query: SetSecrets, variables: { input: { @@ -1296,7 +1295,7 @@ const syncSecretsFlyio = async ({ } }`; - const getSecretsRes = (await request.post(INTEGRATION_FLYIO_API_URL, { + const getSecretsRes = (await standardRequest.post(INTEGRATION_FLYIO_API_URL, { query: GetSecrets, variables: { appName: integration.app, @@ -1332,7 +1331,7 @@ const syncSecretsFlyio = async ({ } }`; - await request.post(INTEGRATION_FLYIO_API_URL, { + await standardRequest.post(INTEGRATION_FLYIO_API_URL, { query: DeleteSecrets, variables: { input: { @@ -1373,7 +1372,7 @@ const syncSecretsCircleCI = async ({ }) => { try { const circleciOrganizationDetail = ( - await request.get(`${INTEGRATION_CIRCLECI_API_URL}/v2/me/collaborations`, { + await standardRequest.get(`${INTEGRATION_CIRCLECI_API_URL}/v2/me/collaborations`, { headers: { "Circle-Token": accessToken, "Accept-Encoding": "application/json", @@ -1386,7 +1385,7 @@ const syncSecretsCircleCI = async ({ // sync secrets to CircleCI Object.keys(secrets).forEach( async (key) => - await request.post( + await standardRequest.post( `${INTEGRATION_CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar`, { name: key, @@ -1403,7 +1402,7 @@ const syncSecretsCircleCI = async ({ // get secrets from CircleCI const getSecretsRes = ( - await request.get( + await standardRequest.get( `${INTEGRATION_CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar`, { headers: { @@ -1417,7 +1416,7 @@ const syncSecretsCircleCI = async ({ // delete secrets from CircleCI getSecretsRes.forEach(async (sec: any) => { if (!(sec.name in secrets)) { - await request.delete( + await standardRequest.delete( `${INTEGRATION_CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`, { headers: { @@ -1454,7 +1453,7 @@ const syncSecretsTravisCI = async ({ try { // get secrets from travis-ci const getSecretsRes = ( - await request.get( + await standardRequest.get( `${INTEGRATION_TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`, { headers: { @@ -1476,7 +1475,7 @@ const syncSecretsTravisCI = async ({ if (!(key in getSecretsRes)) { // case: secret does not exist in travis ci // -> add secret - await request.post( + await standardRequest.post( `${INTEGRATION_TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`, { env_var: { @@ -1495,7 +1494,7 @@ const syncSecretsTravisCI = async ({ } else { // case: secret exists in travis ci // -> update/set secret - await request.patch( + await standardRequest.patch( `${INTEGRATION_TRAVISCI_API_URL}/settings/env_vars/${getSecretsRes[key].id}?repository_id=${getSecretsRes[key].repository_id}`, { env_var: { @@ -1517,7 +1516,7 @@ const syncSecretsTravisCI = async ({ for await (const key of Object.keys(getSecretsRes)) { if (!(key in secrets)){ // delete secret - await request.delete( + await standardRequest.delete( `${INTEGRATION_TRAVISCI_API_URL}/settings/env_vars/${getSecretsRes[key].id}?repository_id=${getSecretsRes[key].repository_id}`, { headers: { @@ -1554,9 +1553,15 @@ const syncSecretsGitLab = async ({ accessToken: string; }) => { try { + interface GitLabSecret { + key: string; + value: string; + environment_scope: string; + } + // get secrets from gitlab - const getSecretsRes = ( - await request.get( + const getSecretsRes: GitLabSecret[] = ( + await standardRequest.get( `${INTEGRATION_GITLAB_API_URL}/v4/projects/${integration?.appId}/variables`, { headers: { @@ -1565,12 +1570,16 @@ const syncSecretsGitLab = async ({ }, } ) - ).data; + ) + .data + .filter((secret: GitLabSecret) => + secret.environment_scope === integration.targetEnvironment + ); for await (const key of Object.keys(secrets)) { const existingSecret = getSecretsRes.find((s: any) => s.key == key); if (!existingSecret) { - await request.post( + await standardRequest.post( `${INTEGRATION_GITLAB_API_URL}/v4/projects/${integration?.appId}/variables`, { key: key, @@ -1578,7 +1587,7 @@ const syncSecretsGitLab = async ({ protected: false, masked: false, raw: false, - environment_scope:'*' + environment_scope: integration.targetEnvironment }, { headers: { @@ -1589,29 +1598,31 @@ const syncSecretsGitLab = async ({ } ) } else { - // udpate secret - await request.put( - `${INTEGRATION_GITLAB_API_URL}/v4/projects/${integration?.appId}/variables/${existingSecret.key}`, - { - ...existingSecret, - value: secrets[existingSecret.key] - }, - { - headers: { - "Authorization": `Bearer ${accessToken}`, - "Content-Type": "application/json", - "Accept-Encoding": "application/json", + // update secret + if (secrets[key] !== existingSecret.value) { + await standardRequest.put( + `${INTEGRATION_GITLAB_API_URL}/v4/projects/${integration?.appId}/variables/${existingSecret.key}?filter[environment_scope]=${integration.targetEnvironment}`, + { + ...existingSecret, + value: secrets[existingSecret.key] }, - } - ) + { + headers: { + "Authorization": `Bearer ${accessToken}`, + "Content-Type": "application/json", + "Accept-Encoding": "application/json", + }, + } + ); + } } } // delete secrets for await (const sec of getSecretsRes) { if (!(sec.key in secrets)) { - await request.delete( - `${INTEGRATION_GITLAB_API_URL}/v4/projects/${integration?.appId}/variables/${sec.key}`, + await standardRequest.delete( + `${INTEGRATION_GITLAB_API_URL}/v4/projects/${integration?.appId}/variables/${sec.key}?filter[environment_scope]=${integration.targetEnvironment}`, { headers: { "Authorization": `Bearer ${accessToken}`, @@ -1620,7 +1631,7 @@ const syncSecretsGitLab = async ({ ); } } - }catch (err) { + } catch (err) { Sentry.setUser(null); Sentry.captureException(err); throw new Error("Failed to sync secrets to GitLab"); @@ -1645,7 +1656,7 @@ const syncSecretsSupabase = async ({ accessToken: string; }) => { try { - const { data: getSecretsRes } = await request.get( + const { data: getSecretsRes } = await standardRequest.get( `${INTEGRATION_SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, { headers: { @@ -1665,7 +1676,7 @@ const syncSecretsSupabase = async ({ } ); - await request.post( + await standardRequest.post( `${INTEGRATION_SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, modifiedFormatForSecretInjection, { @@ -1683,7 +1694,7 @@ const syncSecretsSupabase = async ({ } }); - await request.delete( + await standardRequest.delete( `${INTEGRATION_SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, { headers: { diff --git a/backend/src/integrations/teams.ts b/backend/src/integrations/teams.ts index 3bed93c9a..74fc0ca86 100644 --- a/backend/src/integrations/teams.ts +++ b/backend/src/integrations/teams.ts @@ -5,7 +5,7 @@ import { INTEGRATION_GITLAB, INTEGRATION_GITLAB_API_URL } from '../variables'; -import request from '../config/request'; +import { standardRequest } from '../config/request'; interface Team { name: string; @@ -56,7 +56,7 @@ const getTeamsGitLab = async ({ accessToken: string; }) => { let teams: Team[] = []; - const res = (await request.get( + const res = (await standardRequest.get( `${INTEGRATION_GITLAB_API_URL}/v4/groups`, { headers: { diff --git a/backend/src/middleware/requireWorkspaceAuth.ts b/backend/src/middleware/requireWorkspaceAuth.ts index 557987490..da517b998 100644 --- a/backend/src/middleware/requireWorkspaceAuth.ts +++ b/backend/src/middleware/requireWorkspaceAuth.ts @@ -1,8 +1,6 @@ import { Request, Response, NextFunction } from 'express'; import { Types } from 'mongoose'; -import { validateMembership } from '../helpers/membership'; import { validateClientForWorkspace } from '../validation'; -import { UnauthorizedRequestError } from '../utils/errors'; type req = 'params' | 'body' | 'query'; @@ -31,7 +29,7 @@ const requireWorkspaceAuth = ({ const environment = locationEnvironment ? req[locationEnvironment]?.environment : undefined; // validate clients - const { membership } = await validateClientForWorkspace({ + const { membership, workspace } = await validateClientForWorkspace({ authData: req.authData, workspaceId: new Types.ObjectId(workspaceId), environment, @@ -43,6 +41,10 @@ const requireWorkspaceAuth = ({ if (membership) { req.membership = membership; } + + if (workspace) { + req.workspace = workspace; + } return next(); }; diff --git a/backend/src/models/integration.ts b/backend/src/models/integration.ts index 2a77c95e9..555f481f8 100644 --- a/backend/src/models/integration.ts +++ b/backend/src/models/integration.ts @@ -21,6 +21,7 @@ export interface IIntegration { workspace: Types.ObjectId; environment: string; isActive: boolean; + url: string; app: string; appId: string; owner: string; @@ -63,6 +64,11 @@ const integrationSchema = new Schema( type: Boolean, required: true, }, + url: { + // for custom self-hosted integrations (e.g. self-hosted GitHub enterprise) + type: String, + default: null + }, app: { // name of app in provider type: String, diff --git a/backend/src/routes/v1/secretsFolder.ts b/backend/src/routes/v1/secretsFolder.ts index 7f2cd1bc8..e6319b752 100644 --- a/backend/src/routes/v1/secretsFolder.ts +++ b/backend/src/routes/v1/secretsFolder.ts @@ -6,7 +6,7 @@ import { validateRequest } from '../../middleware'; import { body, param } from 'express-validator'; -import { createFolder, deleteFolder } from '../../controllers/v1/secretsFolderController'; +import { createFolder, deleteFolder, getFolderById } from '../../controllers/v1/secretsFolderController'; import { ADMIN, MEMBER } from '../../variables'; router.post( @@ -36,5 +36,15 @@ router.delete( deleteFolder ); +router.get( + '/:folderId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + param('folderId').exists(), + validateRequest, + getFolderById +); + export default router; \ No newline at end of file diff --git a/backend/src/utils/addDevelopmentUser.ts b/backend/src/utils/addDevelopmentUser.ts index 52aedcdd2..2c7866229 100644 --- a/backend/src/utils/addDevelopmentUser.ts +++ b/backend/src/utils/addDevelopmentUser.ts @@ -5,6 +5,7 @@ ************************************************************************************************/ import { Key, Membership, MembershipOrg, Organization, User, Workspace } from "../models"; +import { SecretService } from "../services"; import { Types } from 'mongoose'; import { getNodeEnv } from '../config'; @@ -119,7 +120,12 @@ export const createTestUserForDevelopment = async () => { // create workspace if not exist const workspaceInDB = await Workspace.findById(testWorkspaceId) if (!workspaceInDB) { - await Workspace.create(testWorkspace) + const workspace = await Workspace.create(testWorkspace) + + // initialize blind index salt for workspace + await SecretService.createSecretBlindIndexData({ + workspaceId: workspace._id + }); } // create workspace key if not exist diff --git a/backend/src/utils/setup/index.ts b/backend/src/utils/setup/index.ts index 6c7bfb422..c59a974d0 100644 --- a/backend/src/utils/setup/index.ts +++ b/backend/src/utils/setup/index.ts @@ -1,6 +1,7 @@ import * as Sentry from '@sentry/node'; import { DatabaseService, TelemetryService } from '../../services'; import { setTransporter } from '../../helpers/nodemailer'; +import { EELicenseService } from '../../ee/services'; import { initSmtp } from '../../services/smtp'; import { createTestUserForDevelopment } from '../addDevelopmentUser' // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -28,6 +29,7 @@ import { * Prepare Infisical upon startup. This includes tasks like: * - Log initial telemetry message * - Initializing SMTP configuration + * - Initializing the instance global feature set (if applicable) * - Initializing the database connection * - Initializing Sentry * - Backfilling data @@ -41,6 +43,9 @@ export const setup = async () => { // initializing SMTP configuration setTransporter(await initSmtp()); + // initializing global feature set + await EELicenseService.initGlobalFeatureSet(); + // initializing the database connection await DatabaseService.initDatabase(await getMongoURL()); diff --git a/backend/src/utils/setup/reencryptData.ts b/backend/src/utils/setup/reencryptData.ts index 1bf499cc9..0741b44f4 100644 --- a/backend/src/utils/setup/reencryptData.ts +++ b/backend/src/utils/setup/reencryptData.ts @@ -78,8 +78,6 @@ export const reencryptSecretBlindIndexDataSalts = async () => { const encryptionKey = await getEncryptionKey(); const rootEncryptionKey = await getRootEncryptionKey(); - // 2. re-encrypt secret blind index salts under ROOT_ENCRYPTION_KEY - if (encryptionKey && rootEncryptionKey) { const secretBlindIndexData = await SecretBlindIndexData.find({ algorithm: ALGORITHM_AES_256_GCM, diff --git a/backend/src/utils/setup/validateConfig.ts b/backend/src/utils/setup/validateConfig.ts index b71e6e4d9..5e7aa1e5b 100644 --- a/backend/src/utils/setup/validateConfig.ts +++ b/backend/src/utils/setup/validateConfig.ts @@ -22,14 +22,6 @@ export const validateEncryptionKeysConfig = async () => { const encryptionKey = await getEncryptionKey(); const rootEncryptionKey = await getRootEncryptionKey(); - // TODO: handle case where either of keys can be empty strings - // and it would actually count as being defined for encryption - // within the application - - // console.log('validateEncryptionKeysConfig'); - // console.log('encryptionKey: ', encryptionKey); - // console.log('rootEncryptionKey: ', rootEncryptionKey); - if ( (encryptionKey === undefined || encryptionKey === "") && (rootEncryptionKey === undefined || rootEncryptionKey === "") diff --git a/backend/src/validation/workspace.ts b/backend/src/validation/workspace.ts index 60d13b129..1cbdca420 100644 --- a/backend/src/validation/workspace.ts +++ b/backend/src/validation/workspace.ts @@ -81,7 +81,7 @@ export const validateClientForWorkspace = async ({ requiredPermissions }); - return ({ membership }); + return ({ membership, workspace }); } if (authData.authMode === AUTH_MODE_SERVICE_ACCOUNT && authData.authPayload instanceof ServiceAccount) { @@ -115,7 +115,7 @@ export const validateClientForWorkspace = async ({ requiredPermissions }); - return ({ membership }); + return ({ membership, workspace }); } throw UnauthorizedRequestError({ diff --git a/cli/.infisicalignore b/cli/.infisicalignore new file mode 100644 index 000000000..e5dfe29bc --- /dev/null +++ b/cli/.infisicalignore @@ -0,0 +1,3 @@ +bea0ff6e05a4de73a5db625d4ae181a015b50855:frontend/components/utilities/attemptLogin.js:stripe-access-token:147 +bea0ff6e05a4de73a5db625d4ae181a015b50855:backend/src/json/integrations.json:generic-api-key:5 +1961b92340e5d2613acae528b886c842427ce5d0:frontend/components/utilities/attemptLogin.js:stripe-access-token:148 diff --git a/cli/config/allowlist.go b/cli/config/allowlist.go new file mode 100644 index 000000000..373325758 --- /dev/null +++ b/cli/config/allowlist.go @@ -0,0 +1,85 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package config + +import ( + "regexp" + "strings" +) + +// Allowlist allows a rule to be ignored for specific +// regexes, paths, and/or commits +type Allowlist struct { + // Short human readable description of the allowlist. + Description string + + // Regexes is slice of content regular expressions that are allowed to be ignored. + Regexes []*regexp.Regexp + + // RegexTarget + RegexTarget string + + // Paths is a slice of path regular expressions that are allowed to be ignored. + Paths []*regexp.Regexp + + // Commits is a slice of commit SHAs that are allowed to be ignored. + Commits []string + + // StopWords is a slice of stop words that are allowed to be ignored. + // This targets the _secret_, not the content of the regex match like the + // Regexes slice. + StopWords []string +} + +// CommitAllowed returns true if the commit is allowed to be ignored. +func (a *Allowlist) CommitAllowed(c string) bool { + if c == "" { + return false + } + for _, commit := range a.Commits { + if commit == c { + return true + } + } + return false +} + +// PathAllowed returns true if the path is allowed to be ignored. +func (a *Allowlist) PathAllowed(path string) bool { + return anyRegexMatch(path, a.Paths) +} + +// RegexAllowed returns true if the regex is allowed to be ignored. +func (a *Allowlist) RegexAllowed(s string) bool { + return anyRegexMatch(s, a.Regexes) +} + +func (a *Allowlist) ContainsStopWord(s string) bool { + s = strings.ToLower(s) + for _, stopWord := range a.StopWords { + if strings.Contains(s, strings.ToLower(stopWord)) { + return true + } + } + return false +} diff --git a/cli/config/allowlist_test.go b/cli/config/allowlist_test.go new file mode 100644 index 000000000..52766e3cd --- /dev/null +++ b/cli/config/allowlist_test.go @@ -0,0 +1,115 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package config + +import ( + "regexp" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCommitAllowed(t *testing.T) { + tests := []struct { + allowlist Allowlist + commit string + commitAllowed bool + }{ + { + allowlist: Allowlist{ + Commits: []string{"commitA"}, + }, + commit: "commitA", + commitAllowed: true, + }, + { + allowlist: Allowlist{ + Commits: []string{"commitB"}, + }, + commit: "commitA", + commitAllowed: false, + }, + { + allowlist: Allowlist{ + Commits: []string{"commitB"}, + }, + commit: "", + commitAllowed: false, + }, + } + for _, tt := range tests { + assert.Equal(t, tt.commitAllowed, tt.allowlist.CommitAllowed(tt.commit)) + } +} + +func TestRegexAllowed(t *testing.T) { + tests := []struct { + allowlist Allowlist + secret string + regexAllowed bool + }{ + { + allowlist: Allowlist{ + Regexes: []*regexp.Regexp{regexp.MustCompile("matchthis")}, + }, + secret: "a secret: matchthis, done", + regexAllowed: true, + }, + { + allowlist: Allowlist{ + Regexes: []*regexp.Regexp{regexp.MustCompile("matchthis")}, + }, + secret: "a secret", + regexAllowed: false, + }, + } + for _, tt := range tests { + assert.Equal(t, tt.regexAllowed, tt.allowlist.RegexAllowed(tt.secret)) + } +} + +func TestPathAllowed(t *testing.T) { + tests := []struct { + allowlist Allowlist + path string + pathAllowed bool + }{ + { + allowlist: Allowlist{ + Paths: []*regexp.Regexp{regexp.MustCompile("path")}, + }, + path: "a path", + pathAllowed: true, + }, + { + allowlist: Allowlist{ + Paths: []*regexp.Regexp{regexp.MustCompile("path")}, + }, + path: "a ???", + pathAllowed: false, + }, + } + for _, tt := range tests { + assert.Equal(t, tt.pathAllowed, tt.allowlist.PathAllowed(tt.path)) + } +} diff --git a/cli/config/config.go b/cli/config/config.go new file mode 100644 index 000000000..b1ce08e2b --- /dev/null +++ b/cli/config/config.go @@ -0,0 +1,279 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package config + +import ( + _ "embed" + "fmt" + "regexp" + "strings" + + "github.com/rs/zerolog/log" + "github.com/spf13/viper" +) + +//go:embed infisical-scan.toml +var DefaultConfig string + +// use to keep track of how many configs we can extend +// yea I know, globals bad +var extendDepth int + +const maxExtendDepth = 2 + +const DefaultScanConfigFileName = ".infisical-scan.toml" +const DefaultScanConfigEnvName = "INFISICAL_SCAN_CONFIG" +const DefaultInfisicalIgnoreFineName = ".infisicalignore" + +// ViperConfig is the config struct used by the Viper config package +// to parse the config file. This struct does not include regular expressions. +// It is used as an intermediary to convert the Viper config to the Config struct. +type ViperConfig struct { + Description string + Extend Extend + Rules []struct { + ID string + Description string + Entropy float64 + SecretGroup int + Regex string + Keywords []string + Path string + Tags []string + + Allowlist struct { + RegexTarget string + Regexes []string + Paths []string + Commits []string + StopWords []string + } + } + Allowlist struct { + RegexTarget string + Regexes []string + Paths []string + Commits []string + StopWords []string + } +} + +// Config is a configuration struct that contains rules and an allowlist if present. +type Config struct { + Extend Extend + Path string + Description string + Rules map[string]Rule + Allowlist Allowlist + Keywords []string + + // used to keep sarif results consistent + orderedRules []string +} + +// Extend is a struct that allows users to define how they want their +// configuration extended by other configuration files. +type Extend struct { + Path string + URL string + UseDefault bool +} + +func (vc *ViperConfig) Translate() (Config, error) { + var ( + keywords []string + orderedRules []string + ) + rulesMap := make(map[string]Rule) + + for _, r := range vc.Rules { + var allowlistRegexes []*regexp.Regexp + for _, a := range r.Allowlist.Regexes { + allowlistRegexes = append(allowlistRegexes, regexp.MustCompile(a)) + } + var allowlistPaths []*regexp.Regexp + for _, a := range r.Allowlist.Paths { + allowlistPaths = append(allowlistPaths, regexp.MustCompile(a)) + } + + if r.Keywords == nil { + r.Keywords = []string{} + } else { + for _, k := range r.Keywords { + keywords = append(keywords, strings.ToLower(k)) + } + } + + if r.Tags == nil { + r.Tags = []string{} + } + + var configRegex *regexp.Regexp + var configPathRegex *regexp.Regexp + if r.Regex == "" { + configRegex = nil + } else { + configRegex = regexp.MustCompile(r.Regex) + } + if r.Path == "" { + configPathRegex = nil + } else { + configPathRegex = regexp.MustCompile(r.Path) + } + r := Rule{ + Description: r.Description, + RuleID: r.ID, + Regex: configRegex, + Path: configPathRegex, + SecretGroup: r.SecretGroup, + Entropy: r.Entropy, + Tags: r.Tags, + Keywords: r.Keywords, + Allowlist: Allowlist{ + RegexTarget: r.Allowlist.RegexTarget, + Regexes: allowlistRegexes, + Paths: allowlistPaths, + Commits: r.Allowlist.Commits, + StopWords: r.Allowlist.StopWords, + }, + } + orderedRules = append(orderedRules, r.RuleID) + + if r.Regex != nil && r.SecretGroup > r.Regex.NumSubexp() { + return Config{}, fmt.Errorf("%s invalid regex secret group %d, max regex secret group %d", r.Description, r.SecretGroup, r.Regex.NumSubexp()) + } + rulesMap[r.RuleID] = r + } + var allowlistRegexes []*regexp.Regexp + for _, a := range vc.Allowlist.Regexes { + allowlistRegexes = append(allowlistRegexes, regexp.MustCompile(a)) + } + var allowlistPaths []*regexp.Regexp + for _, a := range vc.Allowlist.Paths { + allowlistPaths = append(allowlistPaths, regexp.MustCompile(a)) + } + c := Config{ + Description: vc.Description, + Extend: vc.Extend, + Rules: rulesMap, + Allowlist: Allowlist{ + RegexTarget: vc.Allowlist.RegexTarget, + Regexes: allowlistRegexes, + Paths: allowlistPaths, + Commits: vc.Allowlist.Commits, + StopWords: vc.Allowlist.StopWords, + }, + Keywords: keywords, + orderedRules: orderedRules, + } + + if maxExtendDepth != extendDepth { + // disallow both usedefault and path from being set + if c.Extend.Path != "" && c.Extend.UseDefault { + log.Fatal().Msg("unable to load config due to extend.path and extend.useDefault being set") + } + if c.Extend.UseDefault { + c.extendDefault() + } else if c.Extend.Path != "" { + c.extendPath() + } + + } + + return c, nil +} + +func (c *Config) OrderedRules() []Rule { + var orderedRules []Rule + for _, id := range c.orderedRules { + if _, ok := c.Rules[id]; ok { + orderedRules = append(orderedRules, c.Rules[id]) + } + } + return orderedRules +} + +func (c *Config) extendDefault() { + extendDepth++ + viper.SetConfigType("toml") + if err := viper.ReadConfig(strings.NewReader(DefaultConfig)); err != nil { + log.Fatal().Msgf("failed to load extended config, err: %s", err) + return + } + defaultViperConfig := ViperConfig{} + if err := viper.Unmarshal(&defaultViperConfig); err != nil { + log.Fatal().Msgf("failed to load extended config, err: %s", err) + return + } + cfg, err := defaultViperConfig.Translate() + if err != nil { + log.Fatal().Msgf("failed to load extended config, err: %s", err) + return + } + log.Debug().Msg("extending config with default config") + c.extend(cfg) + +} + +func (c *Config) extendPath() { + extendDepth++ + viper.SetConfigFile(c.Extend.Path) + if err := viper.ReadInConfig(); err != nil { + log.Fatal().Msgf("failed to load extended config, err: %s", err) + return + } + extensionViperConfig := ViperConfig{} + if err := viper.Unmarshal(&extensionViperConfig); err != nil { + log.Fatal().Msgf("failed to load extended config, err: %s", err) + return + } + cfg, err := extensionViperConfig.Translate() + if err != nil { + log.Fatal().Msgf("failed to load extended config, err: %s", err) + return + } + log.Debug().Msgf("extending config with %s", c.Extend.Path) + c.extend(cfg) +} + +func (c *Config) extendURL() { + // TODO +} + +func (c *Config) extend(extensionConfig Config) { + for ruleID, rule := range extensionConfig.Rules { + if _, ok := c.Rules[ruleID]; !ok { + log.Trace().Msgf("adding %s to base config", ruleID) + c.Rules[ruleID] = rule + c.Keywords = append(c.Keywords, rule.Keywords...) + } + } + + // append allowlists, not attempting to merge + c.Allowlist.Commits = append(c.Allowlist.Commits, + extensionConfig.Allowlist.Commits...) + c.Allowlist.Paths = append(c.Allowlist.Paths, + extensionConfig.Allowlist.Paths...) + c.Allowlist.Regexes = append(c.Allowlist.Regexes, + extensionConfig.Allowlist.Regexes...) +} diff --git a/cli/config/config_test.go b/cli/config/config_test.go new file mode 100644 index 000000000..e8f4d47b1 --- /dev/null +++ b/cli/config/config_test.go @@ -0,0 +1,170 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package config + +import ( + "fmt" + "regexp" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" +) + +const configPath = "../testdata/config/" + +func TestTranslate(t *testing.T) { + tests := []struct { + cfgName string + cfg Config + wantError error + }{ + { + cfgName: "allow_aws_re", + cfg: Config{ + Rules: map[string]Rule{"aws-access-key": { + Description: "AWS Access Key", + Regex: regexp.MustCompile("(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}"), + Tags: []string{"key", "AWS"}, + Keywords: []string{}, + RuleID: "aws-access-key", + Allowlist: Allowlist{ + Regexes: []*regexp.Regexp{ + regexp.MustCompile("AKIALALEMEL33243OLIA"), + }, + }, + }, + }, + }, + }, + { + cfgName: "allow_commit", + cfg: Config{ + Rules: map[string]Rule{"aws-access-key": { + Description: "AWS Access Key", + Regex: regexp.MustCompile("(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}"), + Tags: []string{"key", "AWS"}, + Keywords: []string{}, + RuleID: "aws-access-key", + Allowlist: Allowlist{ + Commits: []string{"allowthiscommit"}, + }, + }, + }, + }, + }, + { + cfgName: "allow_path", + cfg: Config{ + Rules: map[string]Rule{"aws-access-key": { + Description: "AWS Access Key", + Regex: regexp.MustCompile("(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}"), + Tags: []string{"key", "AWS"}, + Keywords: []string{}, + RuleID: "aws-access-key", + Allowlist: Allowlist{ + Paths: []*regexp.Regexp{ + regexp.MustCompile(".go"), + }, + }, + }, + }, + }, + }, + { + cfgName: "entropy_group", + cfg: Config{ + Rules: map[string]Rule{"discord-api-key": { + Description: "Discord API key", + Regex: regexp.MustCompile(`(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{64})['\"]`), + RuleID: "discord-api-key", + Allowlist: Allowlist{}, + Entropy: 3.5, + SecretGroup: 3, + Tags: []string{}, + Keywords: []string{}, + }, + }, + }, + }, + { + cfgName: "bad_entropy_group", + cfg: Config{}, + wantError: fmt.Errorf("Discord API key invalid regex secret group 5, max regex secret group 3"), + }, + { + cfgName: "base", + cfg: Config{ + Rules: map[string]Rule{ + "aws-access-key": { + Description: "AWS Access Key", + Regex: regexp.MustCompile("(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}"), + Tags: []string{"key", "AWS"}, + Keywords: []string{}, + RuleID: "aws-access-key", + }, + "aws-secret-key": { + Description: "AWS Secret Key", + Regex: regexp.MustCompile(`(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}`), + Tags: []string{"key", "AWS"}, + Keywords: []string{}, + RuleID: "aws-secret-key", + }, + "aws-secret-key-again": { + Description: "AWS Secret Key", + Regex: regexp.MustCompile(`(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}`), + Tags: []string{"key", "AWS"}, + Keywords: []string{}, + RuleID: "aws-secret-key-again", + }, + }, + }, + }, + } + + for _, tt := range tests { + viper.Reset() + viper.AddConfigPath(configPath) + viper.SetConfigName(tt.cfgName) + viper.SetConfigType("toml") + err := viper.ReadInConfig() + if err != nil { + t.Error(err) + } + + var vc ViperConfig + err = viper.Unmarshal(&vc) + if err != nil { + t.Error(err) + } + cfg, err := vc.Translate() + if tt.wantError != nil { + if err == nil { + t.Errorf("expected error") + } + assert.Equal(t, tt.wantError, err) + } + + assert.Equal(t, cfg.Rules, tt.cfg.Rules) + } +} diff --git a/cli/config/infisical-scan.toml b/cli/config/infisical-scan.toml new file mode 100644 index 000000000..193883444 --- /dev/null +++ b/cli/config/infisical-scan.toml @@ -0,0 +1,2803 @@ + +# This file has been auto-generated. Do not edit manually. +# If you would like to contribute new rules, please use +# cmd/generate/config/main.go and follow the contributing guidelines +# at https://github.com/zricethezav/gitleaks/blob/master/CONTRIBUTING.md + +# This is the default gitleaks configuration file. +# Rules and allowlists are defined within this file. +# Rules instruct gitleaks on what should be considered a secret. +# Allowlists instruct gitleaks on what is allowed, i.e. not a secret. + +title = "gitleaks config" + +[allowlist] +description = "global allow lists" +paths = [ + '''infisical-scan.toml''', + '''(.*?)(jpg|gif|doc|docx|zip|xls|pdf|bin|svg|socket)$''', + '''(go.mod|go.sum)$''', + '''gradle.lockfile''', + '''node_modules''', + '''package-lock.json''', + '''pnpm-lock.yaml''', + '''Database.refactorlog''', + '''vendor''', +] + +[[rules]] +description = "Adafruit API Key" +id = "adafruit-api-key" +regex = '''(?i)(?:adafruit)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "adafruit", +] + +[[rules]] +description = "Adobe Client ID (OAuth Web)" +id = "adobe-client-id" +regex = '''(?i)(?:adobe)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "adobe", +] + +[[rules]] +description = "Adobe Client Secret" +id = "adobe-client-secret" +regex = '''(?i)\b((p8e-)(?i)[a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "p8e-", +] + +[[rules]] +description = "Age secret key" +id = "age secret key" +regex = '''AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}''' +keywords = [ + "age-secret-key-1", +] + +[[rules]] +description = "Airtable API Key" +id = "airtable-api-key" +regex = '''(?i)(?:airtable)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{17})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "airtable", +] + +[[rules]] +description = "Algolia API Key" +id = "algolia-api-key" +regex = '''(?i)(?:algolia)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "algolia", +] + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-access-key-id" +regex = '''(?i)\b((LTAI)(?i)[a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "ltai", +] + +[[rules]] +description = "Alibaba Secret Key" +id = "alibaba-secret-key" +regex = '''(?i)(?:alibaba)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "alibaba", +] + +[[rules]] +description = "Asana Client ID" +id = "asana-client-id" +regex = '''(?i)(?:asana)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "asana", +] + +[[rules]] +description = "Asana Client Secret" +id = "asana-client-secret" +regex = '''(?i)(?:asana)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "asana", +] + +[[rules]] +description = "Atlassian API token" +id = "atlassian-api-token" +regex = '''(?i)(?:atlassian|confluence|jira)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "atlassian","confluence","jira", +] + +[[rules]] +description = "Authress Service Client Access Key" +id = "authress-service-client-access-key" +regex = '''(?i)\b((?:sc|ext|scauth|authress)_[a-z0-9]{5,30}\.[a-z0-9]{4,6}\.acc_[a-z0-9-]{10,32}\.[a-z0-9+/_=-]{30,120})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "sc_","ext_","scauth_","authress_", +] + +[[rules]] +description = "AWS" +id = "aws-access-token" +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]] +description = "Beamer API token" +id = "beamer-api-token" +regex = '''(?i)(?:beamer)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(b_[a-z0-9=_\-]{44})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "beamer", +] + +[[rules]] +description = "Bitbucket Client ID" +id = "bitbucket-client-id" +regex = '''(?i)(?:bitbucket)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "bitbucket", +] + +[[rules]] +description = "Bitbucket Client Secret" +id = "bitbucket-client-secret" +regex = '''(?i)(?:bitbucket)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "bitbucket", +] + +[[rules]] +description = "Bittrex Access Key" +id = "bittrex-access-key" +regex = '''(?i)(?:bittrex)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "bittrex", +] + +[[rules]] +description = "Bittrex Secret Key" +id = "bittrex-secret-key" +regex = '''(?i)(?:bittrex)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "bittrex", +] + +[[rules]] +description = "Clojars API token" +id = "clojars-api-token" +regex = '''(?i)(CLOJARS_)[a-z0-9]{60}''' +keywords = [ + "clojars", +] + +[[rules]] +description = "Codecov Access Token" +id = "codecov-access-token" +regex = '''(?i)(?:codecov)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "codecov", +] + +[[rules]] +description = "Coinbase Access Token" +id = "coinbase-access-token" +regex = '''(?i)(?:coinbase)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "coinbase", +] + +[[rules]] +description = "Confluent Access Token" +id = "confluent-access-token" +regex = '''(?i)(?:confluent)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "confluent", +] + +[[rules]] +description = "Confluent Secret Key" +id = "confluent-secret-key" +regex = '''(?i)(?:confluent)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "confluent", +] + +[[rules]] +description = "Contentful delivery API token" +id = "contentful-delivery-api-token" +regex = '''(?i)(?:contentful)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{43})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "contentful", +] + +[[rules]] +description = "Databricks API token" +id = "databricks-api-token" +regex = '''(?i)\b(dapi[a-h0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "dapi", +] + +[[rules]] +description = "Datadog Access Token" +id = "datadog-access-token" +regex = '''(?i)(?:datadog)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "datadog", +] + +[[rules]] +description = "Defined Networking API token" +id = "defined-networking-api-token" +regex = '''(?i)(?:dnkey)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(dnkey-[a-z0-9=_\-]{26}-[a-z0-9=_\-]{52})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "dnkey", +] + +[[rules]] +description = "DigitalOcean OAuth Access Token" +id = "digitalocean-access-token" +regex = '''(?i)\b(doo_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "doo_v1_", +] + +[[rules]] +description = "DigitalOcean Personal Access Token" +id = "digitalocean-pat" +regex = '''(?i)\b(dop_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "dop_v1_", +] + +[[rules]] +description = "DigitalOcean OAuth Refresh Token" +id = "digitalocean-refresh-token" +regex = '''(?i)\b(dor_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "dor_v1_", +] + +[[rules]] +description = "Discord API key" +id = "discord-api-token" +regex = '''(?i)(?:discord)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "discord", +] + +[[rules]] +description = "Discord client ID" +id = "discord-client-id" +regex = '''(?i)(?:discord)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9]{18})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "discord", +] + +[[rules]] +description = "Discord client secret" +id = "discord-client-secret" +regex = '''(?i)(?:discord)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "discord", +] + +[[rules]] +description = "Doppler API token" +id = "doppler-api-token" +regex = '''(dp\.pt\.)(?i)[a-z0-9]{43}''' +keywords = [ + "doppler", +] + +[[rules]] +description = "Droneci Access Token" +id = "droneci-access-token" +regex = '''(?i)(?:droneci)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "droneci", +] + +[[rules]] +description = "Dropbox API secret" +id = "dropbox-api-token" +regex = '''(?i)(?:dropbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{15})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "dropbox", +] + +[[rules]] +description = "Dropbox long lived API token" +id = "dropbox-long-lived-api-token" +regex = '''(?i)(?:dropbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "dropbox", +] + +[[rules]] +description = "Dropbox short lived API token" +id = "dropbox-short-lived-api-token" +regex = '''(?i)(?:dropbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(sl\.[a-z0-9\-=_]{135})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "dropbox", +] + +[[rules]] +description = "Duffel API token" +id = "duffel-api-token" +regex = '''duffel_(test|live)_(?i)[a-z0-9_\-=]{43}''' +keywords = [ + "duffel", +] + +[[rules]] +description = "Dynatrace API token" +id = "dynatrace-api-token" +regex = '''dt0c01\.(?i)[a-z0-9]{24}\.[a-z0-9]{64}''' +keywords = [ + "dynatrace", +] + +[[rules]] +description = "EasyPost API token" +id = "easypost-api-token" +regex = '''\bEZAK(?i)[a-z0-9]{54}''' +keywords = [ + "ezak", +] + +[[rules]] +description = "EasyPost test API token" +id = "easypost-test-api-token" +regex = '''\bEZTK(?i)[a-z0-9]{54}''' +keywords = [ + "eztk", +] + +[[rules]] +description = "Etsy Access Token" +id = "etsy-access-token" +regex = '''(?i)(?:etsy)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "etsy", +] + +[[rules]] +description = "Facebook Access Token" +id = "facebook" +regex = '''(?i)(?:facebook)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "facebook", +] + +[[rules]] +description = "Fastly API key" +id = "fastly-api-token" +regex = '''(?i)(?:fastly)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "fastly", +] + +[[rules]] +description = "Finicity API token" +id = "finicity-api-token" +regex = '''(?i)(?:finicity)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "finicity", +] + +[[rules]] +description = "Finicity Client Secret" +id = "finicity-client-secret" +regex = '''(?i)(?:finicity)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "finicity", +] + +[[rules]] +description = "Finnhub Access Token" +id = "finnhub-access-token" +regex = '''(?i)(?:finnhub)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "finnhub", +] + +[[rules]] +description = "Flickr Access Token" +id = "flickr-access-token" +regex = '''(?i)(?:flickr)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "flickr", +] + +[[rules]] +description = "Flutterwave Encryption Key" +id = "flutterwave-encryption-key" +regex = '''FLWSECK_TEST-(?i)[a-h0-9]{12}''' +keywords = [ + "flwseck_test", +] + +[[rules]] +description = "Finicity Public Key" +id = "flutterwave-public-key" +regex = '''FLWPUBK_TEST-(?i)[a-h0-9]{32}-X''' +keywords = [ + "flwpubk_test", +] + +[[rules]] +description = "Flutterwave Secret Key" +id = "flutterwave-secret-key" +regex = '''FLWSECK_TEST-(?i)[a-h0-9]{32}-X''' +keywords = [ + "flwseck_test", +] + +[[rules]] +description = "Frame.io API token" +id = "frameio-api-token" +regex = '''fio-u-(?i)[a-z0-9\-_=]{64}''' +keywords = [ + "fio-u-", +] + +[[rules]] +description = "Freshbooks Access Token" +id = "freshbooks-access-token" +regex = '''(?i)(?:freshbooks)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "freshbooks", +] + +[[rules]] +description = "GCP API key" +id = "gcp-api-key" +regex = '''(?i)\b(AIza[0-9A-Za-z\\-_]{35})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "aiza", +] + +[[rules]] +description = "Generic API Key" +id = "generic-api-key" +regex = '''(?i)(?:key|api|token|secret|client|passwd|password|auth|access)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9a-z\-_.=]{10,150})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +entropy = 3.5 +keywords = [ + "key","api","token","secret","client","passwd","password","auth","access", +] +[rules.allowlist] +stopwords= [ + "client", + "endpoint", + "vpn", + "_ec2_", + "aws_", + "authorize", + "author", + "define", + "config", + "credential", + "setting", + "sample", + "xxxxxx", + "000000", + "buffer", + "delete", + "aaaaaa", + "fewfwef", + "getenv", + "env_", + "system", + "example", + "ecdsa", + "sha256", + "sha1", + "sha2", + "md5", + "alert", + "wizard", + "target", + "onboard", + "welcome", + "page", + "exploit", + "experiment", + "expire", + "rabbitmq", + "scraper", + "widget", + "music", + "dns_", + "dns-", + "yahoo", + "want", + "json", + "action", + "script", + "fix_", + "fix-", + "develop", + "compas", + "stripe", + "service", + "master", + "metric", + "tech", + "gitignore", + "rich", + "open", + "stack", + "irc_", + "irc-", + "sublime", + "kohana", + "has_", + "has-", + "fabric", + "wordpres", + "role", + "osx_", + "osx-", + "boost", + "addres", + "queue", + "working", + "sandbox", + "internet", + "print", + "vision", + "tracking", + "being", + "generator", + "traffic", + "world", + "pull", + "rust", + "watcher", + "small", + "auth", + "full", + "hash", + "more", + "install", + "auto", + "complete", + "learn", + "paper", + "installer", + "research", + "acces", + "last", + "binding", + "spine", + "into", + "chat", + "algorithm", + "resource", + "uploader", + "video", + "maker", + "next", + "proc", + "lock", + "robot", + "snake", + "patch", + "matrix", + "drill", + "terminal", + "term", + "stuff", + "genetic", + "generic", + "identity", + "audit", + "pattern", + "audio", + "web_", + "web-", + "crud", + "problem", + "statu", + "cms-", + "cms_", + "arch", + "coffee", + "workflow", + "changelog", + "another", + "uiview", + "content", + "kitchen", + "gnu_", + "gnu-", + "gnu.", + "conf", + "couchdb", + "client", + "opencv", + "rendering", + "update", + "concept", + "varnish", + "gui_", + "gui-", + "gui.", + "version", + "shared", + "extra", + "product", + "still", + "not_", + "not-", + "not.", + "drop", + "ring", + "png_", + "png-", + "png.", + "actively", + "import", + "output", + "backup", + "start", + "embedded", + "registry", + "pool", + "semantic", + "instagram", + "bash", + "system", + "ninja", + "drupal", + "jquery", + "polyfill", + "physic", + "league", + "guide", + "pack", + "synopsi", + "sketch", + "injection", + "svg_", + "svg-", + "svg.", + "friendly", + "wave", + "convert", + "manage", + "camera", + "link", + "slide", + "timer", + "wrapper", + "gallery", + "url_", + "url-", + "url.", + "todomvc", + "requirej", + "party", + "http", + "payment", + "async", + "library", + "home", + "coco", + "gaia", + "display", + "universal", + "func", + "metadata", + "hipchat", + "under", + "room", + "config", + "personal", + "realtime", + "resume", + "database", + "testing", + "tiny", + "basic", + "forum", + "meetup", + "yet_", + "yet-", + "yet.", + "cento", + "dead", + "fluentd", + "editor", + "utilitie", + "run_", + "run-", + "run.", + "box_", + "box-", + "box.", + "bot_", + "bot-", + "bot.", + "making", + "sample", + "group", + "monitor", + "ajax", + "parallel", + "cassandra", + "ultimate", + "site", + "get_", + "get-", + "get.", + "gen_", + "gen-", + "gen.", + "gem_", + "gem-", + "gem.", + "extended", + "image", + "knife", + "asset", + "nested", + "zero", + "plugin", + "bracket", + "mule", + "mozilla", + "number", + "act_", + "act-", + "act.", + "map_", + "map-", + "map.", + "micro", + "debug", + "openshift", + "chart", + "expres", + "backend", + "task", + "source", + "translate", + "jbos", + "composer", + "sqlite", + "profile", + "mustache", + "mqtt", + "yeoman", + "have", + "builder", + "smart", + "like", + "oauth", + "school", + "guideline", + "captcha", + "filter", + "bitcoin", + "bridge", + "color", + "toolbox", + "discovery", + "new_", + "new-", + "new.", + "dashboard", + "when", + "setting", + "level", + "post", + "standard", + "port", + "platform", + "yui_", + "yui-", + "yui.", + "grunt", + "animation", + "haskell", + "icon", + "latex", + "cheat", + "lua_", + "lua-", + "lua.", + "gulp", + "case", + "author", + "without", + "simulator", + "wifi", + "directory", + "lisp", + "list", + "flat", + "adventure", + "story", + "storm", + "gpu_", + "gpu-", + "gpu.", + "store", + "caching", + "attention", + "solr", + "logger", + "demo", + "shortener", + "hadoop", + "finder", + "phone", + "pipeline", + "range", + "textmate", + "showcase", + "app_", + "app-", + "app.", + "idiomatic", + "edit", + "our_", + "our-", + "our.", + "out_", + "out-", + "out.", + "sentiment", + "linked", + "why_", + "why-", + "why.", + "local", + "cube", + "gmail", + "job_", + "job-", + "job.", + "rpc_", + "rpc-", + "rpc.", + "contest", + "tcp_", + "tcp-", + "tcp.", + "usage", + "buildout", + "weather", + "transfer", + "automated", + "sphinx", + "issue", + "sas_", + "sas-", + "sas.", + "parallax", + "jasmine", + "addon", + "machine", + "solution", + "dsl_", + "dsl-", + "dsl.", + "episode", + "menu", + "theme", + "best", + "adapter", + "debugger", + "chrome", + "tutorial", + "life", + "step", + "people", + "joomla", + "paypal", + "developer", + "solver", + "team", + "current", + "love", + "visual", + "date", + "data", + "canva", + "container", + "future", + "xml_", + "xml-", + "xml.", + "twig", + "nagio", + "spatial", + "original", + "sync", + "archived", + "refinery", + "science", + "mapping", + "gitlab", + "play", + "ext_", + "ext-", + "ext.", + "session", + "impact", + "set_", + "set-", + "set.", + "see_", + "see-", + "see.", + "migration", + "commit", + "community", + "shopify", + "what'", + "cucumber", + "statamic", + "mysql", + "location", + "tower", + "line", + "code", + "amqp", + "hello", + "send", + "index", + "high", + "notebook", + "alloy", + "python", + "field", + "document", + "soap", + "edition", + "email", + "php_", + "php-", + "php.", + "command", + "transport", + "official", + "upload", + "study", + "secure", + "angularj", + "akka", + "scalable", + "package", + "request", + "con_", + "con-", + "con.", + "flexible", + "security", + "comment", + "module", + "flask", + "graph", + "flash", + "apache", + "change", + "window", + "space", + "lambda", + "sheet", + "bookmark", + "carousel", + "friend", + "objective", + "jekyll", + "bootstrap", + "first", + "article", + "gwt_", + "gwt-", + "gwt.", + "classic", + "media", + "websocket", + "touch", + "desktop", + "real", + "read", + "recorder", + "moved", + "storage", + "validator", + "add-on", + "pusher", + "scs_", + "scs-", + "scs.", + "inline", + "asp_", + "asp-", + "asp.", + "timeline", + "base", + "encoding", + "ffmpeg", + "kindle", + "tinymce", + "pretty", + "jpa_", + "jpa-", + "jpa.", + "used", + "user", + "required", + "webhook", + "download", + "resque", + "espresso", + "cloud", + "mongo", + "benchmark", + "pure", + "cakephp", + "modx", + "mode", + "reactive", + "fuel", + "written", + "flickr", + "mail", + "brunch", + "meteor", + "dynamic", + "neo_", + "neo-", + "neo.", + "new_", + "new-", + "new.", + "net_", + "net-", + "net.", + "typo", + "type", + "keyboard", + "erlang", + "adobe", + "logging", + "ckeditor", + "message", + "iso_", + "iso-", + "iso.", + "hook", + "ldap", + "folder", + "reference", + "railscast", + "www_", + "www-", + "www.", + "tracker", + "azure", + "fork", + "form", + "digital", + "exporter", + "skin", + "string", + "template", + "designer", + "gollum", + "fluent", + "entity", + "language", + "alfred", + "summary", + "wiki", + "kernel", + "calendar", + "plupload", + "symfony", + "foundry", + "remote", + "talk", + "search", + "dev_", + "dev-", + "dev.", + "del_", + "del-", + "del.", + "token", + "idea", + "sencha", + "selector", + "interface", + "create", + "fun_", + "fun-", + "fun.", + "groovy", + "query", + "grail", + "red_", + "red-", + "red.", + "laravel", + "monkey", + "slack", + "supported", + "instant", + "value", + "center", + "latest", + "work", + "but_", + "but-", + "but.", + "bug_", + "bug-", + "bug.", + "virtual", + "tweet", + "statsd", + "studio", + "path", + "real-time", + "frontend", + "notifier", + "coding", + "tool", + "firmware", + "flow", + "random", + "mediawiki", + "bosh", + "been", + "beer", + "lightbox", + "theory", + "origin", + "redmine", + "hub_", + "hub-", + "hub.", + "require", + "pro_", + "pro-", + "pro.", + "ant_", + "ant-", + "ant.", + "any_", + "any-", + "any.", + "recipe", + "closure", + "mapper", + "event", + "todo", + "model", + "redi", + "provider", + "rvm_", + "rvm-", + "rvm.", + "program", + "memcached", + "rail", + "silex", + "foreman", + "activity", + "license", + "strategy", + "batch", + "streaming", + "fast", + "use_", + "use-", + "use.", + "usb_", + "usb-", + "usb.", + "impres", + "academy", + "slider", + "please", + "layer", + "cros", + "now_", + "now-", + "now.", + "miner", + "extension", + "own_", + "own-", + "own.", + "app_", + "app-", + "app.", + "debian", + "symphony", + "example", + "feature", + "serie", + "tree", + "project", + "runner", + "entry", + "leetcode", + "layout", + "webrtc", + "logic", + "login", + "worker", + "toolkit", + "mocha", + "support", + "back", + "inside", + "device", + "jenkin", + "contact", + "fake", + "awesome", + "ocaml", + "bit_", + "bit-", + "bit.", + "drive", + "screen", + "prototype", + "gist", + "binary", + "nosql", + "rest", + "overview", + "dart", + "dark", + "emac", + "mongoid", + "solarized", + "homepage", + "emulator", + "commander", + "django", + "yandex", + "gradle", + "xcode", + "writer", + "crm_", + "crm-", + "crm.", + "jade", + "startup", + "error", + "using", + "format", + "name", + "spring", + "parser", + "scratch", + "magic", + "try_", + "try-", + "try.", + "rack", + "directive", + "challenge", + "slim", + "counter", + "element", + "chosen", + "doc_", + "doc-", + "doc.", + "meta", + "should", + "button", + "packet", + "stream", + "hardware", + "android", + "infinite", + "password", + "software", + "ghost", + "xamarin", + "spec", + "chef", + "interview", + "hubot", + "mvc_", + "mvc-", + "mvc.", + "exercise", + "leaflet", + "launcher", + "air_", + "air-", + "air.", + "photo", + "board", + "boxen", + "way_", + "way-", + "way.", + "computing", + "welcome", + "notepad", + "portfolio", + "cat_", + "cat-", + "cat.", + "can_", + "can-", + "can.", + "magento", + "yaml", + "domain", + "card", + "yii_", + "yii-", + "yii.", + "checker", + "browser", + "upgrade", + "only", + "progres", + "aura", + "ruby_", + "ruby-", + "ruby.", + "polymer", + "util", + "lite", + "hackathon", + "rule", + "log_", + "log-", + "log.", + "opengl", + "stanford", + "skeleton", + "history", + "inspector", + "help", + "soon", + "selenium", + "lab_", + "lab-", + "lab.", + "scheme", + "schema", + "look", + "ready", + "leveldb", + "docker", + "game", + "minimal", + "logstash", + "messaging", + "within", + "heroku", + "mongodb", + "kata", + "suite", + "picker", + "win_", + "win-", + "win.", + "wip_", + "wip-", + "wip.", + "panel", + "started", + "starter", + "front-end", + "detector", + "deploy", + "editing", + "based", + "admin", + "capture", + "spree", + "page", + "bundle", + "goal", + "rpg_", + "rpg-", + "rpg.", + "setup", + "side", + "mean", + "reader", + "cookbook", + "mini", + "modern", + "seed", + "dom_", + "dom-", + "dom.", + "doc_", + "doc-", + "doc.", + "dot_", + "dot-", + "dot.", + "syntax", + "sugar", + "loader", + "website", + "make", + "kit_", + "kit-", + "kit.", + "protocol", + "human", + "daemon", + "golang", + "manager", + "countdown", + "connector", + "swagger", + "map_", + "map-", + "map.", + "mac_", + "mac-", + "mac.", + "man_", + "man-", + "man.", + "orm_", + "orm-", + "orm.", + "org_", + "org-", + "org.", + "little", + "zsh_", + "zsh-", + "zsh.", + "shop", + "show", + "workshop", + "money", + "grid", + "server", + "octopres", + "svn_", + "svn-", + "svn.", + "ember", + "embed", + "general", + "file", + "important", + "dropbox", + "portable", + "public", + "docpad", + "fish", + "sbt_", + "sbt-", + "sbt.", + "done", + "para", + "network", + "common", + "readme", + "popup", + "simple", + "purpose", + "mirror", + "single", + "cordova", + "exchange", + "object", + "design", + "gateway", + "account", + "lamp", + "intellij", + "math", + "mit_", + "mit-", + "mit.", + "control", + "enhanced", + "emitter", + "multi", + "add_", + "add-", + "add.", + "about", + "socket", + "preview", + "vagrant", + "cli_", + "cli-", + "cli.", + "powerful", + "top_", + "top-", + "top.", + "radio", + "watch", + "fluid", + "amazon", + "report", + "couchbase", + "automatic", + "detection", + "sprite", + "pyramid", + "portal", + "advanced", + "plu_", + "plu-", + "plu.", + "runtime", + "git_", + "git-", + "git.", + "uri_", + "uri-", + "uri.", + "haml", + "node", + "sql_", + "sql-", + "sql.", + "cool", + "core", + "obsolete", + "handler", + "iphone", + "extractor", + "array", + "copy", + "nlp_", + "nlp-", + "nlp.", + "reveal", + "pop_", + "pop-", + "pop.", + "engine", + "parse", + "check", + "html", + "nest", + "all_", + "all-", + "all.", + "chinese", + "buildpack", + "what", + "tag_", + "tag-", + "tag.", + "proxy", + "style", + "cookie", + "feed", + "restful", + "compiler", + "creating", + "prelude", + "context", + "java", + "rspec", + "mock", + "backbone", + "light", + "spotify", + "flex", + "related", + "shell", + "which", + "clas", + "webapp", + "swift", + "ansible", + "unity", + "console", + "tumblr", + "export", + "campfire", + "conway'", + "made", + "riak", + "hero", + "here", + "unix", + "unit", + "glas", + "smtp", + "how_", + "how-", + "how.", + "hot_", + "hot-", + "hot.", + "debug", + "release", + "diff", + "player", + "easy", + "right", + "old_", + "old-", + "old.", + "animate", + "time", + "push", + "explorer", + "course", + "training", + "nette", + "router", + "draft", + "structure", + "note", + "salt", + "where", + "spark", + "trello", + "power", + "method", + "social", + "via_", + "via-", + "via.", + "vim_", + "vim-", + "vim.", + "select", + "webkit", + "github", + "ftp_", + "ftp-", + "ftp.", + "creator", + "mongoose", + "led_", + "led-", + "led.", + "movie", + "currently", + "pdf_", + "pdf-", + "pdf.", + "load", + "markdown", + "phalcon", + "input", + "custom", + "atom", + "oracle", + "phonegap", + "ubuntu", + "great", + "rdf_", + "rdf-", + "rdf.", + "popcorn", + "firefox", + "zip_", + "zip-", + "zip.", + "cuda", + "dotfile", + "static", + "openwrt", + "viewer", + "powered", + "graphic", + "les_", + "les-", + "les.", + "doe_", + "doe-", + "doe.", + "maven", + "word", + "eclipse", + "lab_", + "lab-", + "lab.", + "hacking", + "steam", + "analytic", + "option", + "abstract", + "archive", + "reality", + "switcher", + "club", + "write", + "kafka", + "arduino", + "angular", + "online", + "title", + "don't", + "contao", + "notice", + "analyzer", + "learning", + "zend", + "external", + "staging", + "busines", + "tdd_", + "tdd-", + "tdd.", + "scanner", + "building", + "snippet", + "modular", + "bower", + "stm_", + "stm-", + "stm.", + "lib_", + "lib-", + "lib.", + "alpha", + "mobile", + "clean", + "linux", + "nginx", + "manifest", + "some", + "raspberry", + "gnome", + "ide_", + "ide-", + "ide.", + "block", + "statistic", + "info", + "drag", + "youtube", + "koan", + "facebook", + "paperclip", + "art_", + "art-", + "art.", + "quality", + "tab_", + "tab-", + "tab.", + "need", + "dojo", + "shield", + "computer", + "stat", + "state", + "twitter", + "utility", + "converter", + "hosting", + "devise", + "liferay", + "updated", + "force", + "tip_", + "tip-", + "tip.", + "behavior", + "active", + "call", + "answer", + "deck", + "better", + "principle", + "ches", + "bar_", + "bar-", + "bar.", + "reddit", + "three", + "haxe", + "just", + "plug-in", + "agile", + "manual", + "tetri", + "super", + "beta", + "parsing", + "doctrine", + "minecraft", + "useful", + "perl", + "sharing", + "agent", + "switch", + "view", + "dash", + "channel", + "repo", + "pebble", + "profiler", + "warning", + "cluster", + "running", + "markup", + "evented", + "mod_", + "mod-", + "mod.", + "share", + "csv_", + "csv-", + "csv.", + "response", + "good", + "house", + "connect", + "built", + "build", + "find", + "ipython", + "webgl", + "big_", + "big-", + "big.", + "google", + "scala", + "sdl_", + "sdl-", + "sdl.", + "sdk_", + "sdk-", + "sdk.", + "native", + "day_", + "day-", + "day.", + "puppet", + "text", + "routing", + "helper", + "linkedin", + "crawler", + "host", + "guard", + "merchant", + "poker", + "over", + "writing", + "free", + "classe", + "component", + "craft", + "nodej", + "phoenix", + "longer", + "quick", + "lazy", + "memory", + "clone", + "hacker", + "middleman", + "factory", + "motion", + "multiple", + "tornado", + "hack", + "ssh_", + "ssh-", + "ssh.", + "review", + "vimrc", + "driver", + "driven", + "blog", + "particle", + "table", + "intro", + "importer", + "thrift", + "xmpp", + "framework", + "refresh", + "react", + "font", + "librarie", + "variou", + "formatter", + "analysi", + "karma", + "scroll", + "tut_", + "tut-", + "tut.", + "apple", + "tag_", + "tag-", + "tag.", + "tab_", + "tab-", + "tab.", + "category", + "ionic", + "cache", + "homebrew", + "reverse", + "english", + "getting", + "shipping", + "clojure", + "boot", + "book", + "branch", + "combination", + "combo", +] +[[rules]] +description = "GitHub App Token" +id = "github-app-token" +regex = '''(ghu|ghs)_[0-9a-zA-Z]{36}''' +keywords = [ + "ghu_","ghs_", +] + +[[rules]] +description = "GitHub Fine-Grained Personal Access Token" +id = "github-fine-grained-pat" +regex = '''github_pat_[0-9a-zA-Z_]{82}''' +keywords = [ + "github_pat_", +] + +[[rules]] +description = "GitHub OAuth Access Token" +id = "github-oauth" +regex = '''gho_[0-9a-zA-Z]{36}''' +keywords = [ + "gho_", +] + +[[rules]] +description = "GitHub Personal Access Token" +id = "github-pat" +regex = '''ghp_[0-9a-zA-Z]{36}''' +keywords = [ + "ghp_", +] + +[[rules]] +description = "GitHub Refresh Token" +id = "github-refresh-token" +regex = '''ghr_[0-9a-zA-Z]{36}''' +keywords = [ + "ghr_", +] + +[[rules]] +description = "GitLab Personal Access Token" +id = "gitlab-pat" +regex = '''glpat-[0-9a-zA-Z\-\_]{20}''' +keywords = [ + "glpat-", +] + +[[rules]] +description = "GitLab Pipeline Trigger Token" +id = "gitlab-ptt" +regex = '''glptt-[0-9a-f]{40}''' +keywords = [ + "glptt-", +] + +[[rules]] +description = "GitLab Runner Registration Token" +id = "gitlab-rrt" +regex = '''GR1348941[0-9a-zA-Z\-\_]{20}''' +keywords = [ + "gr1348941", +] + +[[rules]] +description = "Gitter Access Token" +id = "gitter-access-token" +regex = '''(?i)(?:gitter)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "gitter", +] + +[[rules]] +description = "GoCardless API token" +id = "gocardless-api-token" +regex = '''(?i)(?:gocardless)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(live_(?i)[a-z0-9\-_=]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "live_","gocardless", +] + +[[rules]] +description = "Grafana api key (or Grafana cloud api key)" +id = "grafana-api-key" +regex = '''(?i)\b(eyJrIjoi[A-Za-z0-9]{70,400}={0,2})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "eyjrijoi", +] + +[[rules]] +description = "Grafana cloud api token" +id = "grafana-cloud-api-token" +regex = '''(?i)\b(glc_[A-Za-z0-9+/]{32,400}={0,2})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "glc_", +] + +[[rules]] +description = "Grafana service account token" +id = "grafana-service-account-token" +regex = '''(?i)\b(glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "glsa_", +] + +[[rules]] +description = "HashiCorp Terraform user/org API token" +id = "hashicorp-tf-api-token" +regex = '''(?i)[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}''' +keywords = [ + "atlasv1", +] + +[[rules]] +description = "Heroku API Key" +id = "heroku-api-key" +regex = '''(?i)(?:heroku)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\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|;]|$)''' +secretGroup = 1 +keywords = [ + "heroku", +] + +[[rules]] +description = "HubSpot API Token" +id = "hubspot-api-key" +regex = '''(?i)(?:hubspot)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\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|;]|$)''' +secretGroup = 1 +keywords = [ + "hubspot", +] + +[[rules]] +description = "Intercom API Token" +id = "intercom-api-key" +regex = '''(?i)(?:intercom)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{60})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "intercom", +] + +[[rules]] +description = "JSON Web Token" +id = "jwt" +regex = '''(?i)\b(ey[0-9a-z]{30,34}\.ey[0-9a-z-\/_]{30,500}\.[0-9a-zA-Z-\/_]{10,200}={0,2})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "ey", +] + +[[rules]] +description = "Kraken Access Token" +id = "kraken-access-token" +regex = '''(?i)(?:kraken)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9\/=_\+\-]{80,90})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "kraken", +] + +[[rules]] +description = "Kucoin Access Token" +id = "kucoin-access-token" +regex = '''(?i)(?:kucoin)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "kucoin", +] + +[[rules]] +description = "Kucoin Secret Key" +id = "kucoin-secret-key" +regex = '''(?i)(?:kucoin)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\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|;]|$)''' +secretGroup = 1 +keywords = [ + "kucoin", +] + +[[rules]] +description = "Launchdarkly Access Token" +id = "launchdarkly-access-token" +regex = '''(?i)(?:launchdarkly)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "launchdarkly", +] + +[[rules]] +description = "Linear API Token" +id = "linear-api-key" +regex = '''lin_api_(?i)[a-z0-9]{40}''' +keywords = [ + "lin_api_", +] + +[[rules]] +description = "Linear Client Secret" +id = "linear-client-secret" +regex = '''(?i)(?:linear)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "linear", +] + +[[rules]] +description = "LinkedIn Client ID" +id = "linkedin-client-id" +regex = '''(?i)(?:linkedin|linked-in)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{14})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "linkedin","linked-in", +] + +[[rules]] +description = "LinkedIn Client secret" +id = "linkedin-client-secret" +regex = '''(?i)(?:linkedin|linked-in)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "linkedin","linked-in", +] + +[[rules]] +description = "Lob API Key" +id = "lob-api-key" +regex = '''(?i)(?:lob)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}((live|test)_[a-f0-9]{35})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "test_","live_", +] + +[[rules]] +description = "Lob Publishable API Key" +id = "lob-pub-api-key" +regex = '''(?i)(?:lob)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}((test|live)_pub_[a-f0-9]{31})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "test_pub","live_pub","_pub", +] + +[[rules]] +description = "Mailchimp API key" +id = "mailchimp-api-key" +regex = '''(?i)(?:mailchimp)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32}-us20)(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "mailchimp", +] + +[[rules]] +description = "Mailgun private API token" +id = "mailgun-private-api-token" +regex = '''(?i)(?:mailgun)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(key-[a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "mailgun", +] + +[[rules]] +description = "Mailgun public validation key" +id = "mailgun-pub-key" +regex = '''(?i)(?:mailgun)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(pubkey-[a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "mailgun", +] + +[[rules]] +description = "Mailgun webhook signing key" +id = "mailgun-signing-key" +regex = '''(?i)(?:mailgun)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "mailgun", +] + +[[rules]] +description = "MapBox API token" +id = "mapbox-api-token" +regex = '''(?i)(?:mapbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(pk\.[a-z0-9]{60}\.[a-z0-9]{22})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "mapbox", +] + +[[rules]] +description = "Mattermost Access Token" +id = "mattermost-access-token" +regex = '''(?i)(?:mattermost)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{26})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "mattermost", +] + +[[rules]] +description = "MessageBird API token" +id = "messagebird-api-token" +regex = '''(?i)(?:messagebird|message-bird|message_bird)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{25})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "messagebird","message-bird","message_bird", +] + +[[rules]] +description = "MessageBird client ID" +id = "messagebird-client-id" +regex = '''(?i)(?:messagebird|message-bird|message_bird)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\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|;]|$)''' +secretGroup = 1 +keywords = [ + "messagebird","message-bird","message_bird", +] + +[[rules]] +description = "Microsoft Teams Webhook" +id = "microsoft-teams-webhook" +regex = '''https:\/\/[a-z0-9]+\.webhook\.office\.com\/webhookb2\/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}@[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}\/IncomingWebhook\/[a-z0-9]{32}\/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}''' +keywords = [ + "webhook.office.com","webhookb2","incomingwebhook", +] + +[[rules]] +description = "Netlify Access Token" +id = "netlify-access-token" +regex = '''(?i)(?:netlify)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{40,46})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "netlify", +] + +[[rules]] +description = "New Relic ingest browser API token" +id = "new-relic-browser-api-token" +regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(NRJS-[a-f0-9]{19})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "nrjs-", +] + +[[rules]] +description = "New Relic user API ID" +id = "new-relic-user-api-id" +regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "new-relic","newrelic","new_relic", +] + +[[rules]] +description = "New Relic user API Key" +id = "new-relic-user-api-key" +regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(NRAK-[a-z0-9]{27})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "nrak", +] + +[[rules]] +description = "npm access token" +id = "npm-access-token" +regex = '''(?i)\b(npm_[a-z0-9]{36})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "npm_", +] + +[[rules]] +description = "Nytimes Access Token" +id = "nytimes-access-token" +regex = '''(?i)(?:nytimes|new-york-times,|newyorktimes)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "nytimes","new-york-times","newyorktimes", +] + +[[rules]] +description = "Okta Access Token" +id = "okta-access-token" +regex = '''(?i)(?:okta)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{42})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "okta", +] + +[[rules]] +description = "Plaid API Token" +id = "plaid-api-token" +regex = '''(?i)(?:plaid)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(access-(?:sandbox|development|production)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "plaid", +] + +[[rules]] +description = "Plaid Client ID" +id = "plaid-client-id" +regex = '''(?i)(?:plaid)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "plaid", +] + +[[rules]] +description = "Plaid Secret key" +id = "plaid-secret-key" +regex = '''(?i)(?:plaid)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "plaid", +] + +[[rules]] +description = "PlanetScale API token" +id = "planetscale-api-token" +regex = '''(?i)\b(pscale_tkn_(?i)[a-z0-9=\-_\.]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "pscale_tkn_", +] + +[[rules]] +description = "PlanetScale OAuth token" +id = "planetscale-oauth-token" +regex = '''(?i)\b(pscale_oauth_(?i)[a-z0-9=\-_\.]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "pscale_oauth_", +] + +[[rules]] +description = "PlanetScale password" +id = "planetscale-password" +regex = '''(?i)\b(pscale_pw_(?i)[a-z0-9=\-_\.]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "pscale_pw_", +] + +[[rules]] +description = "Postman API token" +id = "postman-api-token" +regex = '''(?i)\b(PMAK-(?i)[a-f0-9]{24}\-[a-f0-9]{34})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "pmak-", +] + +[[rules]] +description = "Prefect API token" +id = "prefect-api-token" +regex = '''(?i)\b(pnu_[a-z0-9]{36})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "pnu_", +] + +[[rules]] +description = "Private Key" +id = "private-key" +regex = '''(?i)-----BEGIN[ A-Z0-9_-]{0,100}PRIVATE KEY( BLOCK)?-----[\s\S-]*KEY( BLOCK)?----''' +keywords = [ + "-----begin", +] + +[[rules]] +description = "Pulumi API token" +id = "pulumi-api-token" +regex = '''(?i)\b(pul-[a-f0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "pul-", +] + +[[rules]] +description = "PyPI upload token" +id = "pypi-upload-token" +regex = '''pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}''' +keywords = [ + "pypi-ageichlwas5vcmc", +] + +[[rules]] +description = "RapidAPI Access Token" +id = "rapidapi-access-token" +regex = '''(?i)(?:rapidapi)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{50})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "rapidapi", +] + +[[rules]] +description = "Readme API token" +id = "readme-api-token" +regex = '''(?i)\b(rdme_[a-z0-9]{70})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "rdme_", +] + +[[rules]] +description = "Rubygem API token" +id = "rubygems-api-token" +regex = '''(?i)\b(rubygems_[a-f0-9]{48})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "rubygems_", +] + +[[rules]] +description = "Sendbird Access ID" +id = "sendbird-access-id" +regex = '''(?i)(?:sendbird)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\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|;]|$)''' +secretGroup = 1 +keywords = [ + "sendbird", +] + +[[rules]] +description = "Sendbird Access Token" +id = "sendbird-access-token" +regex = '''(?i)(?:sendbird)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "sendbird", +] + +[[rules]] +description = "SendGrid API token" +id = "sendgrid-api-token" +regex = '''(?i)\b(SG\.(?i)[a-z0-9=_\-\.]{66})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "sg.", +] + +[[rules]] +description = "Sendinblue API token" +id = "sendinblue-api-token" +regex = '''(?i)\b(xkeysib-[a-f0-9]{64}\-(?i)[a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "xkeysib-", +] + +[[rules]] +description = "Sentry Access Token" +id = "sentry-access-token" +regex = '''(?i)(?:sentry)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "sentry", +] + +[[rules]] +description = "Shippo API token" +id = "shippo-api-token" +regex = '''(?i)\b(shippo_(live|test)_[a-f0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "shippo_", +] + +[[rules]] +description = "Shopify access token" +id = "shopify-access-token" +regex = '''shpat_[a-fA-F0-9]{32}''' +keywords = [ + "shpat_", +] + +[[rules]] +description = "Shopify custom access token" +id = "shopify-custom-access-token" +regex = '''shpca_[a-fA-F0-9]{32}''' +keywords = [ + "shpca_", +] + +[[rules]] +description = "Shopify private app access token" +id = "shopify-private-app-access-token" +regex = '''shppa_[a-fA-F0-9]{32}''' +keywords = [ + "shppa_", +] + +[[rules]] +description = "Shopify shared secret" +id = "shopify-shared-secret" +regex = '''shpss_[a-fA-F0-9]{32}''' +keywords = [ + "shpss_", +] + +[[rules]] +description = "Sidekiq Secret" +id = "sidekiq-secret" +regex = '''(?i)(?:BUNDLE_ENTERPRISE__CONTRIBSYS__COM|BUNDLE_GEMS__CONTRIBSYS__COM)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{8}:[a-f0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "bundle_enterprise__contribsys__com","bundle_gems__contribsys__com", +] + +[[rules]] +description = "Sidekiq Sensitive URL" +id = "sidekiq-sensitive-url" +regex = '''(?i)\b(http(?:s??):\/\/)([a-f0-9]{8}:[a-f0-9]{8})@(?:gems.contribsys.com|enterprise.contribsys.com)(?:[\/|\#|\?|:]|$)''' +secretGroup = 2 +keywords = [ + "gems.contribsys.com","enterprise.contribsys.com", +] + +[[rules]] +description = "Slack token" +id = "slack-access-token" +regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})''' +keywords = [ + "xoxb","xoxa","xoxp","xoxr","xoxs", +] + +[[rules]] +description = "Slack Webhook" +id = "slack-web-hook" +regex = '''https:\/\/hooks.slack.com\/(services|workflows)\/[A-Za-z0-9+\/]{44,46}''' +keywords = [ + "hooks.slack.com", +] + +[[rules]] +description = "Square Access Token" +id = "square-access-token" +regex = '''(?i)\b(sq0atp-[0-9A-Za-z\-_]{22})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "sq0atp-", +] + +[[rules]] +description = "Squarespace Access Token" +id = "squarespace-access-token" +regex = '''(?i)(?:squarespace)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\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|;]|$)''' +secretGroup = 1 +keywords = [ + "squarespace", +] + +[[rules]] +description = "Stripe Access Token" +id = "stripe-access-token" +regex = '''(?i)(sk|pk)_(test|live)_[0-9a-z]{10,32}''' +keywords = [ + "sk_test","pk_test","sk_live","pk_live", +] + +[[rules]] +description = "SumoLogic Access ID" +id = "sumologic-access-id" +regex = '''(?i)(?:sumo)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{14})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "sumo", +] + +[[rules]] +description = "SumoLogic Access Token" +id = "sumologic-access-token" +regex = '''(?i)(?:sumo)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "sumo", +] + +[[rules]] +description = "Telegram Bot API Token" +id = "telegram-bot-api-token" +regex = '''(?i)(?:^|[^0-9])([0-9]{5,16}:A[a-zA-Z0-9_\-]{34})(?:$|[^a-zA-Z0-9_\-])''' +secretGroup = 1 +keywords = [ + "telegram","api","bot","token","url", +] + +[[rules]] +description = "Travis CI Access Token" +id = "travisci-access-token" +regex = '''(?i)(?:travis)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{22})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "travis", +] + +[[rules]] +description = "Twilio API Key" +id = "twilio-api-key" +regex = '''SK[0-9a-fA-F]{32}''' +keywords = [ + "twilio", +] + +[[rules]] +description = "Twitch API token" +id = "twitch-api-token" +regex = '''(?i)(?:twitch)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "twitch", +] + +[[rules]] +description = "Twitter Access Secret" +id = "twitter-access-secret" +regex = '''(?i)(?:twitter)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{45})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "twitter", +] + +[[rules]] +description = "Twitter Access Token" +id = "twitter-access-token" +regex = '''(?i)(?:twitter)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([0-9]{15,25}-[a-zA-Z0-9]{20,40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "twitter", +] + +[[rules]] +description = "Twitter API Key" +id = "twitter-api-key" +regex = '''(?i)(?:twitter)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{25})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "twitter", +] + +[[rules]] +description = "Twitter API Secret" +id = "twitter-api-secret" +regex = '''(?i)(?:twitter)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{50})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "twitter", +] + +[[rules]] +description = "Twitter Bearer Token" +id = "twitter-bearer-token" +regex = '''(?i)(?:twitter)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(A{22}[a-zA-Z0-9%]{80,100})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "twitter", +] + +[[rules]] +description = "Typeform API token" +id = "typeform-api-token" +regex = '''(?i)(?:typeform)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(tfp_[a-z0-9\-_\.=]{59})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "tfp_", +] + +[[rules]] +description = "Vault Batch Token" +id = "vault-batch-token" +regex = '''(?i)\b(hvb\.[a-z0-9_-]{138,212})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "hvb", +] + +[[rules]] +description = "Vault Service Token" +id = "vault-service-token" +regex = '''(?i)\b(hvs\.[a-z0-9_-]{90,100})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "hvs", +] + +[[rules]] +description = "Yandex Access Token" +id = "yandex-access-token" +regex = '''(?i)(?:yandex)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(t1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "yandex", +] + +[[rules]] +description = "Yandex API Key" +id = "yandex-api-key" +regex = '''(?i)(?:yandex)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(AQVN[A-Za-z0-9_\-]{35,38})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "yandex", +] + +[[rules]] +description = "Yandex AWS Access Token" +id = "yandex-aws-access-token" +regex = '''(?i)(?:yandex)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}(YC[a-zA-Z0-9_\-]{38})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "yandex", +] + +[[rules]] +description = "Zendesk Secret Key" +id = "zendesk-secret-key" +regex = '''(?i)(?:zendesk)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +secretGroup = 1 +keywords = [ + "zendesk", +] + + diff --git a/cli/config/rule.go b/cli/config/rule.go new file mode 100644 index 000000000..b7c8c1518 --- /dev/null +++ b/cli/config/rule.go @@ -0,0 +1,43 @@ +package config + +import ( + "regexp" +) + +// Rules contain information that define details on how to detect secrets +type Rule struct { + // Description is the description of the rule. + Description string + + // RuleID is a unique identifier for this rule + RuleID string + + // Entropy is a float representing the minimum shannon + // entropy a regex group must have to be considered a secret. + Entropy float64 + + // SecretGroup is an int used to extract secret from regex + // match and used as the group that will have its entropy + // checked if `entropy` is set. + SecretGroup int + + // Regex is a golang regular expression used to detect secrets. + Regex *regexp.Regexp + + // Path is a golang regular expression used to + // filter secrets by path + Path *regexp.Regexp + + // Tags is an array of strings used for metadata + // and reporting purposes. + Tags []string + + // Keywords are used for pre-regex check filtering. Rules that contain + // keywords will perform a quick string compare check to make sure the + // keyword(s) are in the content being scanned. + Keywords []string + + // Allowlist allows a rule to be ignored for specific + // regexes, paths, and/or commits + Allowlist Allowlist +} diff --git a/cli/config/utils.go b/cli/config/utils.go new file mode 100644 index 000000000..ada6ff0fe --- /dev/null +++ b/cli/config/utils.go @@ -0,0 +1,24 @@ +package config + +import ( + "regexp" +) + +func anyRegexMatch(f string, res []*regexp.Regexp) bool { + for _, re := range res { + if regexMatched(f, re) { + return true + } + } + return false +} + +func regexMatched(f string, re *regexp.Regexp) bool { + if re == nil { + return false + } + if re.FindString(f) != "" { + return true + } + return false +} diff --git a/cli/detect/baseline.go b/cli/detect/baseline.go new file mode 100644 index 000000000..bd4c25665 --- /dev/null +++ b/cli/detect/baseline.go @@ -0,0 +1,87 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package detect + +import ( + "encoding/json" + "fmt" + "io" + "os" + + "github.com/rs/zerolog/log" + + "github.com/Infisical/infisical-merge/report" +) + +func IsNew(finding report.Finding, baseline []report.Finding) bool { + // Explicitly testing each property as it gives significantly better performance in comparison to cmp.Equal(). Drawback is that + // the code requires maintanance if/when the Finding struct changes + for _, b := range baseline { + + if finding.Author == b.Author && + finding.Commit == b.Commit && + finding.Date == b.Date && + finding.Description == b.Description && + finding.Email == b.Email && + finding.EndColumn == b.EndColumn && + finding.EndLine == b.EndLine && + finding.Entropy == b.Entropy && + finding.File == b.File && + // Omit checking finding.Fingerprint - if the format of the fingerprint changes, the users will see unexpected behaviour + finding.Match == b.Match && + finding.Message == b.Message && + finding.RuleID == b.RuleID && + finding.Secret == b.Secret && + finding.StartColumn == b.StartColumn && + finding.StartLine == b.StartLine { + return false + } + } + return true +} + +func LoadBaseline(baselinePath string) ([]report.Finding, error) { + var previousFindings []report.Finding + jsonFile, err := os.Open(baselinePath) + if err != nil { + return nil, fmt.Errorf("could not open %s", baselinePath) + } + + defer func() { + if cerr := jsonFile.Close(); cerr != nil { + log.Warn().Err(cerr).Msg("problem closing jsonFile handle") + } + }() + + bytes, err := io.ReadAll(jsonFile) + if err != nil { + return nil, fmt.Errorf("could not read data from the file %s", baselinePath) + } + + err = json.Unmarshal(bytes, &previousFindings) + if err != nil { + return nil, fmt.Errorf("the format of the file %s is not supported", baselinePath) + } + + return previousFindings, nil +} diff --git a/cli/detect/baseline_test.go b/cli/detect/baseline_test.go new file mode 100644 index 000000000..91d2eb72e --- /dev/null +++ b/cli/detect/baseline_test.go @@ -0,0 +1,160 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package detect + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/Infisical/infisical-merge/report" +) + +func TestIsNew(t *testing.T) { + tests := []struct { + findings report.Finding + baseline []report.Finding + expect bool + }{ + { + findings: report.Finding{ + Author: "a", + Commit: "0000", + }, + baseline: []report.Finding{ + { + Author: "a", + Commit: "0000", + }, + }, + expect: false, + }, + { + findings: report.Finding{ + Author: "a", + Commit: "0000", + }, + baseline: []report.Finding{ + { + Author: "a", + Commit: "0002", + }, + }, + expect: true, + }, + { + findings: report.Finding{ + Author: "a", + Commit: "0000", + Tags: []string{"a", "b"}, + }, + baseline: []report.Finding{ + { + Author: "a", + Commit: "0000", + Tags: []string{"a", "c"}, + }, + }, + expect: false, // Updated tags doesn't make it a new finding + }, + } + for _, test := range tests { + assert.Equal(t, test.expect, IsNew(test.findings, test.baseline)) + } +} + +func TestFileLoadBaseline(t *testing.T) { + tests := []struct { + Filename string + ExpectedError error + }{ + { + Filename: "../testdata/baseline/baseline.csv", + ExpectedError: errors.New("the format of the file ../testdata/baseline/baseline.csv is not supported"), + }, + { + Filename: "../testdata/baseline/baseline.sarif", + ExpectedError: errors.New("the format of the file ../testdata/baseline/baseline.sarif is not supported"), + }, + { + Filename: "../testdata/baseline/notfound.json", + ExpectedError: errors.New("could not open ../testdata/baseline/notfound.json"), + }, + } + + for _, test := range tests { + _, err := LoadBaseline(test.Filename) + assert.Equal(t, test.ExpectedError.Error(), err.Error()) + } +} + +func TestIgnoreIssuesInBaseline(t *testing.T) { + tests := []struct { + findings []report.Finding + baseline []report.Finding + expectCount int + }{ + { + findings: []report.Finding{ + { + Author: "a", + Commit: "5", + }, + }, + baseline: []report.Finding{ + { + Author: "a", + Commit: "5", + }, + }, + expectCount: 0, + }, + { + findings: []report.Finding{ + { + Author: "a", + Commit: "5", + Fingerprint: "a", + }, + }, + baseline: []report.Finding{ + { + Author: "a", + Commit: "5", + Fingerprint: "b", + }, + }, + expectCount: 0, + }, + } + + for _, test := range tests { + d, _ := NewDetectorDefaultConfig() + d.baseline = test.baseline + for _, finding := range test.findings { + d.addFinding(finding) + } + assert.Equal(t, test.expectCount, len(d.findings)) + } +} diff --git a/cli/detect/detect.go b/cli/detect/detect.go new file mode 100644 index 000000000..84f058d4b --- /dev/null +++ b/cli/detect/detect.go @@ -0,0 +1,652 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package detect + +import ( + "bufio" + "context" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + "sync" + + "github.com/h2non/filetype" + + "github.com/Infisical/infisical-merge/config" + "github.com/Infisical/infisical-merge/detect/git" + "github.com/Infisical/infisical-merge/report" + + "github.com/fatih/semgroup" + "github.com/gitleaks/go-gitdiff/gitdiff" + ahocorasick "github.com/petar-dambovaliev/aho-corasick" + "github.com/rs/zerolog/log" + "github.com/spf13/viper" +) + +// Type used to differentiate between git scan types: +// $ gitleaks detect +// $ gitleaks protect +// $ gitleaks protect staged +type GitScanType int + +const ( + DetectType GitScanType = iota + ProtectType + ProtectStagedType + + gitleaksAllowSignature = "infisical-scan:ignore" +) + +// Detector is the main detector struct +type Detector struct { + // Config is the configuration for the detector + Config config.Config + + // Redact is a flag to redact findings. This is exported + // so users using gitleaks as a library can set this flag + // without calling `detector.Start(cmd *cobra.Command)` + Redact bool + + // verbose is a flag to print findings + Verbose bool + + // files larger than this will be skipped + MaxTargetMegaBytes int + + // followSymlinks is a flag to enable scanning symlink files + FollowSymlinks bool + + // NoColor is a flag to disable color output + NoColor bool + + // commitMap is used to keep track of commits that have been scanned. + // This is only used for logging purposes and git scans. + commitMap map[string]bool + + // findingMutex is to prevent concurrent access to the + // findings slice when adding findings. + findingMutex *sync.Mutex + + // findings is a slice of report.Findings. This is the result + // of the detector's scan which can then be used to generate a + // report. + findings []report.Finding + + // prefilter is a ahocorasick struct used for doing efficient string + // matching given a set of words (keywords from the rules in the config) + prefilter ahocorasick.AhoCorasick + + // a list of known findings that should be ignored + baseline []report.Finding + + // path to baseline + baselinePath string + + // gitleaksIgnore + gitleaksIgnore map[string]bool +} + +// Fragment contains the data to be scanned +type Fragment struct { + // Raw is the raw content of the fragment + Raw string + + // FilePath is the path to the file if applicable + FilePath string + SymlinkFile string + + // CommitSHA is the SHA of the commit if applicable + CommitSHA string + + // newlineIndices is a list of indices of newlines in the raw content. + // This is used to calculate the line location of a finding + newlineIndices [][]int + + // keywords is a map of all the keywords contain within the contents + // of this fragment + keywords map[string]bool +} + +// NewDetector creates a new detector with the given config +func NewDetector(cfg config.Config) *Detector { + builder := ahocorasick.NewAhoCorasickBuilder(ahocorasick.Opts{ + AsciiCaseInsensitive: true, + MatchOnlyWholeWords: false, + MatchKind: ahocorasick.LeftMostLongestMatch, + DFA: true, + }) + + return &Detector{ + commitMap: make(map[string]bool), + gitleaksIgnore: make(map[string]bool), + findingMutex: &sync.Mutex{}, + findings: make([]report.Finding, 0), + Config: cfg, + prefilter: builder.Build(cfg.Keywords), + } +} + +// NewDetectorDefaultConfig creates a new detector with the default config +func NewDetectorDefaultConfig() (*Detector, error) { + viper.SetConfigType("toml") + err := viper.ReadConfig(strings.NewReader(config.DefaultConfig)) + if err != nil { + return nil, err + } + var vc config.ViperConfig + err = viper.Unmarshal(&vc) + if err != nil { + return nil, err + } + cfg, err := vc.Translate() + if err != nil { + return nil, err + } + return NewDetector(cfg), nil +} + +func (d *Detector) AddGitleaksIgnore(gitleaksIgnorePath string) error { + log.Debug().Msg("found .gitleaksignore file") + file, err := os.Open(gitleaksIgnorePath) + + if err != nil { + return err + } + + // https://github.com/securego/gosec/issues/512 + defer func() { + if err := file.Close(); err != nil { + log.Warn().Msgf("Error closing .gitleaksignore file: %s\n", err) + } + }() + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + d.gitleaksIgnore[scanner.Text()] = true + } + return nil +} + +func (d *Detector) AddBaseline(baselinePath string, source string) error { + if baselinePath != "" { + absoluteSource, err := filepath.Abs(source) + if err != nil { + return err + } + + absoluteBaseline, err := filepath.Abs(baselinePath) + if err != nil { + return err + } + + relativeBaseline, err := filepath.Rel(absoluteSource, absoluteBaseline) + if err != nil { + return err + } + + baseline, err := LoadBaseline(baselinePath) + if err != nil { + return err + } + + d.baseline = baseline + baselinePath = relativeBaseline + + } + + d.baselinePath = baselinePath + return nil +} + +// DetectBytes scans the given bytes and returns a list of findings +func (d *Detector) DetectBytes(content []byte) []report.Finding { + return d.DetectString(string(content)) +} + +// DetectString scans the given string and returns a list of findings +func (d *Detector) DetectString(content string) []report.Finding { + return d.Detect(Fragment{ + Raw: content, + }) +} + +// detectRule scans the given fragment for the given rule and returns a list of findings +func (d *Detector) detectRule(fragment Fragment, rule config.Rule) []report.Finding { + var findings []report.Finding + + // check if filepath or commit is allowed for this rule + if rule.Allowlist.CommitAllowed(fragment.CommitSHA) || + rule.Allowlist.PathAllowed(fragment.FilePath) { + return findings + } + + if rule.Path != nil && rule.Regex == nil { + // Path _only_ rule + if rule.Path.Match([]byte(fragment.FilePath)) { + finding := report.Finding{ + Description: rule.Description, + File: fragment.FilePath, + SymlinkFile: fragment.SymlinkFile, + RuleID: rule.RuleID, + Match: fmt.Sprintf("file detected: %s", fragment.FilePath), + Tags: rule.Tags, + } + return append(findings, finding) + } + } else if rule.Path != nil { + // if path is set _and_ a regex is set, then we need to check both + // so if the path does not match, then we should return early and not + // consider the regex + if !rule.Path.Match([]byte(fragment.FilePath)) { + return findings + } + } + + // if path only rule, skip content checks + if rule.Regex == nil { + return findings + } + + // If flag configure and raw data size bigger then the flag + if d.MaxTargetMegaBytes > 0 { + rawLength := len(fragment.Raw) / 1000000 + if rawLength > d.MaxTargetMegaBytes { + log.Debug().Msgf("skipping file: %s scan due to size: %d", fragment.FilePath, rawLength) + return findings + } + } + + matchIndices := rule.Regex.FindAllStringIndex(fragment.Raw, -1) + for _, matchIndex := range matchIndices { + // extract secret from match + secret := strings.Trim(fragment.Raw[matchIndex[0]:matchIndex[1]], "\n") + + // determine location of match. Note that the location + // in the finding will be the line/column numbers of the _match_ + // not the _secret_, which will be different if the secretGroup + // value is set for this rule + loc := location(fragment, matchIndex) + + if matchIndex[1] > loc.endLineIndex { + loc.endLineIndex = matchIndex[1] + } + + finding := report.Finding{ + Description: rule.Description, + File: fragment.FilePath, + SymlinkFile: fragment.SymlinkFile, + RuleID: rule.RuleID, + StartLine: loc.startLine, + EndLine: loc.endLine, + StartColumn: loc.startColumn, + EndColumn: loc.endColumn, + Secret: secret, + Match: secret, + Tags: rule.Tags, + Line: fragment.Raw[loc.startLineIndex:loc.endLineIndex], + } + + if strings.Contains(fragment.Raw[loc.startLineIndex:loc.endLineIndex], + gitleaksAllowSignature) { + continue + } + + // extract secret from secret group if set + if rule.SecretGroup != 0 { + groups := rule.Regex.FindStringSubmatch(secret) + if len(groups) <= rule.SecretGroup || len(groups) == 0 { + // Config validation should prevent this + continue + } + secret = groups[rule.SecretGroup] + finding.Secret = secret + } + + // check if the regexTarget is defined in the allowlist "regexes" entry + allowlistTarget := finding.Secret + switch rule.Allowlist.RegexTarget { + case "match": + allowlistTarget = finding.Match + case "line": + allowlistTarget = finding.Line + } + + globalAllowlistTarget := finding.Secret + switch d.Config.Allowlist.RegexTarget { + case "match": + globalAllowlistTarget = finding.Match + case "line": + globalAllowlistTarget = finding.Line + } + if rule.Allowlist.RegexAllowed(allowlistTarget) || + d.Config.Allowlist.RegexAllowed(globalAllowlistTarget) { + continue + } + + // check if the secret is in the list of stopwords + if rule.Allowlist.ContainsStopWord(finding.Secret) || + d.Config.Allowlist.ContainsStopWord(finding.Secret) { + continue + } + + // check entropy + entropy := shannonEntropy(finding.Secret) + finding.Entropy = float32(entropy) + if rule.Entropy != 0.0 { + if entropy <= rule.Entropy { + // entropy is too low, skip this finding + continue + } + // NOTE: this is a goofy hack to get around the fact there golang's regex engine + // does not support positive lookaheads. Ideally we would want to add a + // restriction on generic rules regex that requires the secret match group + // contains both numbers and alphabetical characters, not just alphabetical characters. + // What this bit of code does is check if the ruleid is prepended with "generic" and enforces the + // secret contains both digits and alphabetical characters. + // TODO: this should be replaced with stop words + if strings.HasPrefix(rule.RuleID, "generic") { + if !containsDigit(secret) { + continue + } + } + } + + findings = append(findings, finding) + } + return findings +} + +// GitScan accepts a *gitdiff.File channel which contents a git history generated from +// the output of `git log -p ...`. startGitScan will look at each file (patch) in the history +// and determine if the patch contains any findings. +func (d *Detector) DetectGit(source string, logOpts string, gitScanType GitScanType) ([]report.Finding, error) { + var ( + gitdiffFiles <-chan *gitdiff.File + err error + ) + switch gitScanType { + case DetectType: + gitdiffFiles, err = git.GitLog(source, logOpts) + if err != nil { + return d.findings, err + } + case ProtectType: + gitdiffFiles, err = git.GitDiff(source, false) + if err != nil { + return d.findings, err + } + case ProtectStagedType: + gitdiffFiles, err = git.GitDiff(source, true) + if err != nil { + return d.findings, err + } + } + + s := semgroup.NewGroup(context.Background(), 4) + + for gitdiffFile := range gitdiffFiles { + gitdiffFile := gitdiffFile + + // skip binary files + if gitdiffFile.IsBinary || gitdiffFile.IsDelete { + continue + } + + // Check if commit is allowed + commitSHA := "" + if gitdiffFile.PatchHeader != nil { + commitSHA = gitdiffFile.PatchHeader.SHA + if d.Config.Allowlist.CommitAllowed(gitdiffFile.PatchHeader.SHA) { + continue + } + } + d.addCommit(commitSHA) + + s.Go(func() error { + for _, textFragment := range gitdiffFile.TextFragments { + if textFragment == nil { + return nil + } + + fragment := Fragment{ + Raw: textFragment.Raw(gitdiff.OpAdd), + CommitSHA: commitSHA, + FilePath: gitdiffFile.NewName, + } + + for _, finding := range d.Detect(fragment) { + d.addFinding(augmentGitFinding(finding, textFragment, gitdiffFile)) + } + } + return nil + }) + } + + if err := s.Wait(); err != nil { + return d.findings, err + } + log.Info().Msgf("%d commits scanned.", len(d.commitMap)) + log.Debug().Msg("Note: this number might be smaller than expected due to commits with no additions") + if git.ErrEncountered { + return d.findings, fmt.Errorf("%s", "git error encountered, see logs") + } + return d.findings, nil +} + +type scanTarget struct { + Path string + Symlink string +} + +// DetectFiles accepts a path to a source directory or file and begins a scan of the +// file or directory. +func (d *Detector) DetectFiles(source string) ([]report.Finding, error) { + s := semgroup.NewGroup(context.Background(), 4) + paths := make(chan scanTarget) + s.Go(func() error { + defer close(paths) + return filepath.Walk(source, + func(path string, fInfo os.FileInfo, err error) error { + if err != nil { + return err + } + if fInfo.Name() == ".git" && fInfo.IsDir() { + return filepath.SkipDir + } + if fInfo.Size() == 0 { + return nil + } + if fInfo.Mode().IsRegular() { + paths <- scanTarget{ + Path: path, + Symlink: "", + } + } + if fInfo.Mode().Type() == fs.ModeSymlink && d.FollowSymlinks { + realPath, err := filepath.EvalSymlinks(path) + if err != nil { + return err + } + realPathFileInfo, _ := os.Stat(realPath) + if realPathFileInfo.IsDir() { + log.Debug().Msgf("found symlinked directory: %s -> %s [skipping]", path, realPath) + return nil + } + paths <- scanTarget{ + Path: realPath, + Symlink: path, + } + } + return nil + }) + }) + for pa := range paths { + p := pa + s.Go(func() error { + b, err := os.ReadFile(p.Path) + if err != nil { + return err + } + + mimetype, err := filetype.Match(b) + if err != nil { + return err + } + if mimetype.MIME.Type == "application" { + return nil // skip binary files + } + + fragment := Fragment{ + Raw: string(b), + FilePath: p.Path, + } + if p.Symlink != "" { + fragment.SymlinkFile = p.Symlink + } + for _, finding := range d.Detect(fragment) { + // need to add 1 since line counting starts at 1 + finding.EndLine++ + finding.StartLine++ + d.addFinding(finding) + } + + return nil + }) + } + + if err := s.Wait(); err != nil { + return d.findings, err + } + + return d.findings, nil +} + +// DetectReader accepts an io.Reader and a buffer size for the reader in KB +func (d *Detector) DetectReader(r io.Reader, bufSize int) ([]report.Finding, error) { + reader := bufio.NewReader(r) + buf := make([]byte, 0, 1000*bufSize) + findings := []report.Finding{} + + for { + n, err := reader.Read(buf[:cap(buf)]) + buf = buf[:n] + if err != nil { + if err != io.EOF { + return findings, err + } + break + } + + fragment := Fragment{ + Raw: string(buf), + } + for _, finding := range d.Detect(fragment) { + findings = append(findings, finding) + if d.Verbose { + printFinding(finding, d.NoColor) + } + } + } + + return findings, nil +} + +// Detect scans the given fragment and returns a list of findings +func (d *Detector) Detect(fragment Fragment) []report.Finding { + var findings []report.Finding + + // initiate fragment keywords + fragment.keywords = make(map[string]bool) + + // check if filepath is allowed + if fragment.FilePath != "" && (d.Config.Allowlist.PathAllowed(fragment.FilePath) || + fragment.FilePath == d.Config.Path || (d.baselinePath != "" && fragment.FilePath == d.baselinePath)) { + return findings + } + + // add newline indices for location calculation in detectRule + fragment.newlineIndices = regexp.MustCompile("\n").FindAllStringIndex(fragment.Raw, -1) + + // build keyword map for prefiltering rules + normalizedRaw := strings.ToLower(fragment.Raw) + matches := d.prefilter.FindAll(normalizedRaw) + for _, m := range matches { + fragment.keywords[normalizedRaw[m.Start():m.End()]] = true + } + + for _, rule := range d.Config.Rules { + if len(rule.Keywords) == 0 { + // if not keywords are associated with the rule always scan the + // fragment using the rule + findings = append(findings, d.detectRule(fragment, rule)...) + continue + } + fragmentContainsKeyword := false + // check if keywords are in the fragment + for _, k := range rule.Keywords { + if _, ok := fragment.keywords[strings.ToLower(k)]; ok { + fragmentContainsKeyword = true + } + } + if fragmentContainsKeyword { + findings = append(findings, d.detectRule(fragment, rule)...) + } + } + return filter(findings, d.Redact) +} + +// addFinding synchronously adds a finding to the findings slice +func (d *Detector) addFinding(finding report.Finding) { + if finding.Commit == "" { + finding.Fingerprint = fmt.Sprintf("%s:%s:%d", finding.File, finding.RuleID, finding.StartLine) + } else { + finding.Fingerprint = fmt.Sprintf("%s:%s:%s:%d", finding.Commit, finding.File, finding.RuleID, finding.StartLine) + } + // check if we should ignore this finding + if _, ok := d.gitleaksIgnore[finding.Fingerprint]; ok { + log.Debug().Msgf("ignoring finding with Fingerprint %s", + finding.Fingerprint) + return + } + + if d.baseline != nil && !IsNew(finding, d.baseline) { + log.Debug().Msgf("baseline duplicate -- ignoring finding with Fingerprint %s", finding.Fingerprint) + return + } + + d.findingMutex.Lock() + d.findings = append(d.findings, finding) + if d.Verbose { + printFinding(finding, d.NoColor) + } + d.findingMutex.Unlock() +} + +// addCommit synchronously adds a commit to the commit slice +func (d *Detector) addCommit(commit string) { + d.commitMap[commit] = true +} diff --git a/cli/detect/detect_test.go b/cli/detect/detect_test.go new file mode 100644 index 000000000..5a0f50828 --- /dev/null +++ b/cli/detect/detect_test.go @@ -0,0 +1,754 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package detect + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + + "github.com/Infisical/infisical-merge/config" + "github.com/Infisical/infisical-merge/report" +) + +const configPath = "../testdata/config/" +const repoBasePath = "../testdata/repos/" + +func TestDetect(t *testing.T) { + tests := []struct { + cfgName string + baselinePath string + fragment Fragment + // NOTE: for expected findings, all line numbers will be 0 + // because line deltas are added _after_ the finding is created. + // I.e, if the finding is from a --no-git file, the line number will be + // increase by 1 in DetectFromFiles(). If the finding is from git, + // the line number will be increased by the patch delta. + expectedFindings []report.Finding + wantError error + }{ + { + cfgName: "simple", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OKIA\ // infisical-scan:ignore"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "simple", + fragment: Fragment{ + Raw: `awsToken := \ + + \"AKIALALEMEL33243OKIA\ // infisical-scan:ignore" + + `, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "simple", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OKIA\" + + // infisical-scan:ignore" + + `, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{ + { + Description: "AWS Access Key", + Secret: "AKIALALEMEL33243OKIA", + Match: "AKIALALEMEL33243OKIA", + File: "tmp.go", + Line: `awsToken := \"AKIALALEMEL33243OKIA\"`, + RuleID: "aws-access-key", + Tags: []string{"key", "AWS"}, + StartLine: 0, + EndLine: 0, + StartColumn: 15, + EndColumn: 34, + Entropy: 3.1464393, + }, + }, + }, + { + cfgName: "escaped_character_group", + fragment: Fragment{ + Raw: `pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{ + { + Description: "PyPI upload token", + Secret: "pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB", + Match: "pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB", + Line: `pypi-AgEIcHlwaS5vcmcAAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAA-AAAAAAAAAAB`, + File: "tmp.go", + RuleID: "pypi-upload-token", + Tags: []string{"key", "pypi"}, + StartLine: 0, + EndLine: 0, + StartColumn: 1, + EndColumn: 86, + Entropy: 1.9606875, + }, + }, + }, + { + cfgName: "simple", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OLIA\"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{ + { + Description: "AWS Access Key", + Secret: "AKIALALEMEL33243OLIA", + Match: "AKIALALEMEL33243OLIA", + Line: `awsToken := \"AKIALALEMEL33243OLIA\"`, + File: "tmp.go", + RuleID: "aws-access-key", + Tags: []string{"key", "AWS"}, + StartLine: 0, + EndLine: 0, + StartColumn: 15, + EndColumn: 34, + Entropy: 3.0841837, + }, + }, + }, + { + cfgName: "simple", + fragment: Fragment{ + Raw: `export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef;`, + FilePath: "tmp.sh", + }, + expectedFindings: []report.Finding{ + { + Description: "Sidekiq Secret", + Match: "BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef;", + Secret: "cafebabe:deadbeef", + Line: `export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef;`, + File: "tmp.sh", + RuleID: "sidekiq-secret", + Tags: []string{}, + Entropy: 2.6098502, + StartLine: 0, + EndLine: 0, + StartColumn: 8, + EndColumn: 60, + }, + }, + }, + { + cfgName: "simple", + fragment: Fragment{ + Raw: `echo hello1; export BUNDLE_ENTERPRISE__CONTRIBSYS__COM="cafebabe:deadbeef" && echo hello2`, + FilePath: "tmp.sh", + }, + expectedFindings: []report.Finding{ + { + Description: "Sidekiq Secret", + Match: "BUNDLE_ENTERPRISE__CONTRIBSYS__COM=\"cafebabe:deadbeef\"", + Secret: "cafebabe:deadbeef", + File: "tmp.sh", + Line: `echo hello1; export BUNDLE_ENTERPRISE__CONTRIBSYS__COM="cafebabe:deadbeef" && echo hello2`, + RuleID: "sidekiq-secret", + Tags: []string{}, + Entropy: 2.6098502, + StartLine: 0, + EndLine: 0, + StartColumn: 21, + EndColumn: 74, + }, + }, + }, + { + cfgName: "simple", + fragment: Fragment{ + Raw: `url = "http://cafeb4b3:d3adb33f@enterprise.contribsys.com:80/path?param1=true¶m2=false#heading1"`, + FilePath: "tmp.sh", + }, + expectedFindings: []report.Finding{ + { + Description: "Sidekiq Sensitive URL", + Match: "http://cafeb4b3:d3adb33f@enterprise.contribsys.com:", + Secret: "cafeb4b3:d3adb33f", + File: "tmp.sh", + Line: `url = "http://cafeb4b3:d3adb33f@enterprise.contribsys.com:80/path?param1=true¶m2=false#heading1"`, + RuleID: "sidekiq-sensitive-url", + Tags: []string{}, + Entropy: 2.984234, + StartLine: 0, + EndLine: 0, + StartColumn: 8, + EndColumn: 58, + }, + }, + }, + { + cfgName: "allow_aws_re", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OLIA\"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "allow_path", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OLIA\"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "allow_commit", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OLIA\"`, + FilePath: "tmp.go", + CommitSHA: "allowthiscommit", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "entropy_group", + fragment: Fragment{ + Raw: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{ + { + Description: "Discord API key", + Match: "Discord_Public_Key = \"e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5\"", + Secret: "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5", + Line: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + File: "tmp.go", + RuleID: "discord-api-key", + Tags: []string{}, + Entropy: 3.7906237, + StartLine: 0, + EndLine: 0, + StartColumn: 7, + EndColumn: 93, + }, + }, + }, + { + cfgName: "generic_with_py_path", + fragment: Fragment{ + Raw: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "generic_with_py_path", + fragment: Fragment{ + Raw: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FilePath: "tmp.py", + }, + expectedFindings: []report.Finding{ + { + Description: "Generic API Key", + Match: "Key = \"e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5\"", + Secret: "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5", + Line: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + File: "tmp.py", + RuleID: "generic-api-key", + Tags: []string{}, + Entropy: 3.7906237, + StartLine: 0, + EndLine: 0, + StartColumn: 22, + EndColumn: 93, + }, + }, + }, + { + cfgName: "path_only", + fragment: Fragment{ + Raw: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FilePath: "tmp.py", + }, + expectedFindings: []report.Finding{ + { + Description: "Python Files", + Match: "file detected: tmp.py", + File: "tmp.py", + RuleID: "python-files-only", + Tags: []string{}, + }, + }, + }, + { + cfgName: "bad_entropy_group", + fragment: Fragment{ + Raw: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{}, + wantError: fmt.Errorf("Discord API key invalid regex secret group 5, max regex secret group 3"), + }, + { + cfgName: "simple", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OLIA\"`, + FilePath: filepath.Join(configPath, "simple.toml"), + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "allow_global_aws_re", + fragment: Fragment{ + Raw: `awsToken := \"AKIALALEMEL33243OLIA\"`, + FilePath: "tmp.go", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "generic_with_py_path", + fragment: Fragment{ + Raw: `const Discord_Public_Key = "load2523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FilePath: "tmp.py", + }, + expectedFindings: []report.Finding{}, + }, + { + cfgName: "path_only", + baselinePath: ".baseline.json", + fragment: Fragment{ + Raw: `const Discord_Public_Key = "e7322523fb86ed64c836a979cf8465fbd436378c653c1db38f9ae87bc62a6fd5"`, + FilePath: ".baseline.json", + }, + expectedFindings: []report.Finding{}, + }, + } + + for _, tt := range tests { + viper.Reset() + viper.AddConfigPath(configPath) + viper.SetConfigName(tt.cfgName) + viper.SetConfigType("toml") + err := viper.ReadInConfig() + if err != nil { + t.Error(err) + } + + var vc config.ViperConfig + err = viper.Unmarshal(&vc) + if err != nil { + t.Error(err) + } + cfg, err := vc.Translate() + cfg.Path = filepath.Join(configPath, tt.cfgName+".toml") + if tt.wantError != nil { + if err == nil { + t.Errorf("expected error") + } + assert.Equal(t, tt.wantError, err) + } + d := NewDetector(cfg) + d.baselinePath = tt.baselinePath + + findings := d.Detect(tt.fragment) + assert.ElementsMatch(t, tt.expectedFindings, findings) + } +} + +// TestFromGit tests the FromGit function +func TestFromGit(t *testing.T) { + tests := []struct { + cfgName string + source string + logOpts string + expectedFindings []report.Finding + }{ + { + source: filepath.Join(repoBasePath, "small"), + cfgName: "simple", + expectedFindings: []report.Finding{ + { + Description: "AWS Access Key", + StartLine: 20, + EndLine: 20, + StartColumn: 19, + EndColumn: 38, + Line: "\n awsToken := \"AKIALALEMEL33243OLIA\"", + Secret: "AKIALALEMEL33243OLIA", + Match: "AKIALALEMEL33243OLIA", + File: "main.go", + Date: "2021-11-02T23:37:53Z", + Commit: "1b6da43b82b22e4eaa10bcf8ee591e91abbfc587", + Author: "Zachary Rice", + Email: "zricer@protonmail.com", + Message: "Accidentally add a secret", + RuleID: "aws-access-key", + Tags: []string{"key", "AWS"}, + Entropy: 3.0841837, + Fingerprint: "1b6da43b82b22e4eaa10bcf8ee591e91abbfc587:main.go:aws-access-key:20", + }, + { + Description: "AWS Access Key", + StartLine: 9, + EndLine: 9, + StartColumn: 17, + EndColumn: 36, + Secret: "AKIALALEMEL33243OLIA", + Match: "AKIALALEMEL33243OLIA", + Line: "\n\taws_token := \"AKIALALEMEL33243OLIA\"", + File: "foo/foo.go", + Date: "2021-11-02T23:48:06Z", + Commit: "491504d5a31946ce75e22554cc34203d8e5ff3ca", + Author: "Zach Rice", + Email: "zricer@protonmail.com", + Message: "adding foo package with secret", + RuleID: "aws-access-key", + Tags: []string{"key", "AWS"}, + Entropy: 3.0841837, + Fingerprint: "491504d5a31946ce75e22554cc34203d8e5ff3ca:foo/foo.go:aws-access-key:9", + }, + }, + }, + { + source: filepath.Join(repoBasePath, "small"), + logOpts: "--all foo...", + cfgName: "simple", + expectedFindings: []report.Finding{ + { + Description: "AWS Access Key", + StartLine: 9, + EndLine: 9, + StartColumn: 17, + EndColumn: 36, + Secret: "AKIALALEMEL33243OLIA", + Line: "\n\taws_token := \"AKIALALEMEL33243OLIA\"", + Match: "AKIALALEMEL33243OLIA", + Date: "2021-11-02T23:48:06Z", + File: "foo/foo.go", + Commit: "491504d5a31946ce75e22554cc34203d8e5ff3ca", + Author: "Zach Rice", + Email: "zricer@protonmail.com", + Message: "adding foo package with secret", + RuleID: "aws-access-key", + Tags: []string{"key", "AWS"}, + Entropy: 3.0841837, + Fingerprint: "491504d5a31946ce75e22554cc34203d8e5ff3ca:foo/foo.go:aws-access-key:9", + }, + }, + }, + } + + err := moveDotGit("dotGit", ".git") + if err != nil { + t.Fatal(err) + } + defer func() { + if err := moveDotGit(".git", "dotGit"); err != nil { + t.Error(err) + } + }() + + for _, tt := range tests { + + viper.AddConfigPath(configPath) + viper.SetConfigName("simple") + viper.SetConfigType("toml") + err = viper.ReadInConfig() + if err != nil { + t.Error(err) + } + + var vc config.ViperConfig + err = viper.Unmarshal(&vc) + if err != nil { + t.Error(err) + } + cfg, err := vc.Translate() + if err != nil { + t.Error(err) + } + detector := NewDetector(cfg) + findings, err := detector.DetectGit(tt.source, tt.logOpts, DetectType) + if err != nil { + t.Error(err) + } + + for _, f := range findings { + f.Match = "" // remove lines cause copying and pasting them has some wack formatting + } + assert.ElementsMatch(t, tt.expectedFindings, findings) + } +} +func TestFromGitStaged(t *testing.T) { + tests := []struct { + cfgName string + source string + logOpts string + expectedFindings []report.Finding + }{ + { + source: filepath.Join(repoBasePath, "staged"), + cfgName: "simple", + expectedFindings: []report.Finding{ + { + Description: "AWS Access Key", + StartLine: 7, + EndLine: 7, + StartColumn: 18, + EndColumn: 37, + Line: "\n\taws_token2 := \"AKIALALEMEL33243OLIA\" // this one is not", + Match: "AKIALALEMEL33243OLIA", + Secret: "AKIALALEMEL33243OLIA", + File: "api/api.go", + SymlinkFile: "", + Commit: "", + Entropy: 3.0841837, + Author: "", + Email: "", + Date: "0001-01-01T00:00:00Z", + Message: "", + Tags: []string{ + "key", + "AWS", + }, + RuleID: "aws-access-key", + Fingerprint: "api/api.go:aws-access-key:7", + }, + }, + }, + } + + err := moveDotGit("dotGit", ".git") + if err != nil { + t.Fatal(err) + } + defer func() { + if err := moveDotGit(".git", "dotGit"); err != nil { + t.Error(err) + } + }() + + for _, tt := range tests { + + viper.AddConfigPath(configPath) + viper.SetConfigName("simple") + viper.SetConfigType("toml") + err = viper.ReadInConfig() + if err != nil { + t.Error(err) + } + + var vc config.ViperConfig + err = viper.Unmarshal(&vc) + if err != nil { + t.Error(err) + } + cfg, err := vc.Translate() + if err != nil { + t.Error(err) + } + detector := NewDetector(cfg) + detector.AddGitleaksIgnore(filepath.Join(tt.source, ".gitleaksignore")) + findings, err := detector.DetectGit(tt.source, tt.logOpts, ProtectStagedType) + if err != nil { + t.Error(err) + } + + for _, f := range findings { + f.Match = "" // remove lines cause copying and pasting them has some wack formatting + } + assert.ElementsMatch(t, tt.expectedFindings, findings) + } +} + +// TestFromFiles tests the FromFiles function +func TestFromFiles(t *testing.T) { + tests := []struct { + cfgName string + source string + expectedFindings []report.Finding + }{ + { + source: filepath.Join(repoBasePath, "nogit"), + cfgName: "simple", + expectedFindings: []report.Finding{ + { + Description: "AWS Access Key", + StartLine: 20, + EndLine: 20, + StartColumn: 16, + EndColumn: 35, + Match: "AKIALALEMEL33243OLIA", + Secret: "AKIALALEMEL33243OLIA", + Line: "\n\tawsToken := \"AKIALALEMEL33243OLIA\"", + File: "../testdata/repos/nogit/main.go", + SymlinkFile: "", + RuleID: "aws-access-key", + Tags: []string{"key", "AWS"}, + Entropy: 3.0841837, + Fingerprint: "../testdata/repos/nogit/main.go:aws-access-key:20", + }, + }, + }, + { + source: filepath.Join(repoBasePath, "nogit", "main.go"), + cfgName: "simple", + expectedFindings: []report.Finding{ + { + Description: "AWS Access Key", + StartLine: 20, + EndLine: 20, + StartColumn: 16, + EndColumn: 35, + Match: "AKIALALEMEL33243OLIA", + Secret: "AKIALALEMEL33243OLIA", + Line: "\n\tawsToken := \"AKIALALEMEL33243OLIA\"", + File: "../testdata/repos/nogit/main.go", + RuleID: "aws-access-key", + Tags: []string{"key", "AWS"}, + Entropy: 3.0841837, + Fingerprint: "../testdata/repos/nogit/main.go:aws-access-key:20", + }, + }, + }, + } + + for _, tt := range tests { + viper.AddConfigPath(configPath) + viper.SetConfigName("simple") + viper.SetConfigType("toml") + err := viper.ReadInConfig() + if err != nil { + t.Error(err) + } + + var vc config.ViperConfig + err = viper.Unmarshal(&vc) + if err != nil { + t.Error(err) + } + cfg, _ := vc.Translate() + detector := NewDetector(cfg) + detector.FollowSymlinks = true + findings, err := detector.DetectFiles(tt.source) + if err != nil { + t.Error(err) + } + + assert.ElementsMatch(t, tt.expectedFindings, findings) + } +} + +func TestDetectWithSymlinks(t *testing.T) { + tests := []struct { + cfgName string + source string + expectedFindings []report.Finding + }{ + { + source: filepath.Join(repoBasePath, "symlinks/file_symlink"), + cfgName: "simple", + expectedFindings: []report.Finding{ + { + Description: "Asymmetric Private Key", + StartLine: 1, + EndLine: 1, + StartColumn: 1, + EndColumn: 35, + Match: "-----BEGIN OPENSSH PRIVATE KEY-----", + Secret: "-----BEGIN OPENSSH PRIVATE KEY-----", + Line: "-----BEGIN OPENSSH PRIVATE KEY-----", + File: "../testdata/repos/symlinks/source_file/id_ed25519", + SymlinkFile: "../testdata/repos/symlinks/file_symlink/symlinked_id_ed25519", + RuleID: "apkey", + Tags: []string{"key", "AsymmetricPrivateKey"}, + Entropy: 3.587164, + Fingerprint: "../testdata/repos/symlinks/source_file/id_ed25519:apkey:1", + }, + }, + }, + } + + for _, tt := range tests { + viper.AddConfigPath(configPath) + viper.SetConfigName("simple") + viper.SetConfigType("toml") + err := viper.ReadInConfig() + if err != nil { + t.Error(err) + } + + var vc config.ViperConfig + err = viper.Unmarshal(&vc) + if err != nil { + t.Error(err) + } + cfg, _ := vc.Translate() + detector := NewDetector(cfg) + detector.FollowSymlinks = true + findings, err := detector.DetectFiles(tt.source) + if err != nil { + t.Error(err) + } + assert.ElementsMatch(t, tt.expectedFindings, findings) + } +} + +func moveDotGit(from, to string) error { + repoDirs, err := os.ReadDir("../testdata/repos") + if err != nil { + return err + } + for _, dir := range repoDirs { + if to == ".git" { + _, err := os.Stat(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), "dotGit")) + if os.IsNotExist(err) { + // dont want to delete the only copy of .git accidentally + continue + } + os.RemoveAll(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), ".git")) + } + if !dir.IsDir() { + continue + } + _, err := os.Stat(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), from)) + if os.IsNotExist(err) { + continue + } + + err = os.Rename(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), from), + fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), to)) + if err != nil { + return err + } + } + return nil +} diff --git a/cli/detect/git/git.go b/cli/detect/git/git.go new file mode 100644 index 000000000..6eb5e9d6d --- /dev/null +++ b/cli/detect/git/git.go @@ -0,0 +1,143 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package git + +import ( + "bufio" + "io" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/gitleaks/go-gitdiff/gitdiff" + "github.com/rs/zerolog/log" +) + +var ErrEncountered bool + +// GitLog returns a channel of gitdiff.File objects from the +// git log -p command for the given source. +func GitLog(source string, logOpts string) (<-chan *gitdiff.File, error) { + sourceClean := filepath.Clean(source) + var cmd *exec.Cmd + if logOpts != "" { + args := []string{"-C", sourceClean, "log", "-p", "-U0"} + args = append(args, strings.Split(logOpts, " ")...) + cmd = exec.Command("git", args...) + } else { + cmd = exec.Command("git", "-C", sourceClean, "log", "-p", "-U0", + "--full-history", "--all") + } + + log.Debug().Msgf("executing: %s", cmd.String()) + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + stderr, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + go listenForStdErr(stderr) + + if err := cmd.Start(); err != nil { + return nil, err + } + // HACK: to avoid https://github.com/zricethezav/gitleaks/issues/722 + time.Sleep(50 * time.Millisecond) + + return gitdiff.Parse(cmd, stdout) +} + +// GitDiff returns a channel of gitdiff.File objects from +// the git diff command for the given source. +func GitDiff(source string, staged bool) (<-chan *gitdiff.File, error) { + sourceClean := filepath.Clean(source) + var cmd *exec.Cmd + cmd = exec.Command("git", "-C", sourceClean, "diff", "-U0", ".") + if staged { + cmd = exec.Command("git", "-C", sourceClean, "diff", "-U0", + "--staged", ".") + } + log.Debug().Msgf("executing: %s", cmd.String()) + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + stderr, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + go listenForStdErr(stderr) + + if err := cmd.Start(); err != nil { + return nil, err + } + // HACK: to avoid https://github.com/zricethezav/gitleaks/issues/722 + time.Sleep(50 * time.Millisecond) + + return gitdiff.Parse(cmd, stdout) +} + +// listenForStdErr listens for stderr output from git and prints it to stdout +// then exits with exit code 1 +func listenForStdErr(stderr io.ReadCloser) { + scanner := bufio.NewScanner(stderr) + for scanner.Scan() { + // if git throws one of the following errors: + // + // exhaustive rename detection was skipped due to too many files. + // you may want to set your diff.renameLimit variable to at least + // (some large number) and retry the command. + // + // inexact rename detection was skipped due to too many files. + // you may want to set your diff.renameLimit variable to at least + // (some large number) and retry the command. + // + // we skip exiting the program as git log -p/git diff will continue + // to send data to stdout and finish executing. This next bit of + // code prevents gitleaks from stopping mid scan if this error is + // encountered + if strings.Contains(scanner.Text(), + "exhaustive rename detection was skipped") || + strings.Contains(scanner.Text(), + "inexact rename detection was skipped") || + strings.Contains(scanner.Text(), + "you may want to set your diff.renameLimit") { + log.Warn().Msg(scanner.Text()) + } else { + log.Error().Msgf("[git] %s", scanner.Text()) + + // asynchronously set this error flag to true so that we can + // capture a log message and exit with a non-zero exit code + // This value should get set before the `git` command exits so it's + // safe-ish, although I know I know, bad practice. + ErrEncountered = true + } + } +} diff --git a/cli/detect/git/git_test.go b/cli/detect/git/git_test.go new file mode 100644 index 000000000..3a2ea9c35 --- /dev/null +++ b/cli/detect/git/git_test.go @@ -0,0 +1,158 @@ +package git_test + +// TODO: commenting out this test for now because it's flaky. Alternatives to consider to get this working: +// -- use `git stash` instead of `restore()` + +// const repoBasePath = "../../testdata/repos/" + +// const expectPath = "../../testdata/expected/" + +// func TestGitLog(t *testing.T) { +// tests := []struct { +// source string +// logOpts string +// expected string +// }{ +// { +// source: filepath.Join(repoBasePath, "small"), +// expected: filepath.Join(expectPath, "git", "small.txt"), +// }, +// { +// source: filepath.Join(repoBasePath, "small"), +// expected: filepath.Join(expectPath, "git", "small-branch-foo.txt"), +// logOpts: "--all foo...", +// }, +// } + +// err := moveDotGit("dotGit", ".git") +// if err != nil { +// t.Fatal(err) +// } +// defer func() { +// if err = moveDotGit(".git", "dotGit"); err != nil { +// t.Fatal(err) +// } +// }() + +// for _, tt := range tests { +// files, err := git.GitLog(tt.source, tt.logOpts) +// if err != nil { +// t.Error(err) +// } + +// var diffSb strings.Builder +// for f := range files { +// for _, tf := range f.TextFragments { +// diffSb.WriteString(tf.Raw(gitdiff.OpAdd)) +// } +// } + +// expectedBytes, err := os.ReadFile(tt.expected) +// if err != nil { +// t.Error(err) +// } +// expected := string(expectedBytes) +// if expected != diffSb.String() { +// // write string builder to .got file using os.Create +// err = os.WriteFile(strings.Replace(tt.expected, ".txt", ".got.txt", 1), []byte(diffSb.String()), 0644) +// if err != nil { +// t.Error(err) +// } +// t.Error("expected: ", expected, "got: ", diffSb.String()) +// } +// } +// } + +// func TestGitDiff(t *testing.T) { +// tests := []struct { +// source string +// expected string +// additions string +// target string +// }{ +// { +// source: filepath.Join(repoBasePath, "small"), +// expected: "this line is added\nand another one", +// additions: "this line is added\nand another one", +// target: filepath.Join(repoBasePath, "small", "main.go"), +// }, +// } + +// err := moveDotGit("dotGit", ".git") +// if err != nil { +// t.Fatal(err) +// } +// defer func() { +// if err = moveDotGit(".git", "dotGit"); err != nil { +// t.Fatal(err) +// } +// }() + +// for _, tt := range tests { +// noChanges, err := os.ReadFile(tt.target) +// if err != nil { +// t.Error(err) +// } +// err = os.WriteFile(tt.target, []byte(tt.additions), 0644) +// if err != nil { +// restore(tt.target, noChanges, t) +// t.Error(err) +// } + +// files, err := git.GitDiff(tt.source, false) +// if err != nil { +// restore(tt.target, noChanges, t) +// t.Error(err) +// } + +// for f := range files { +// sb := strings.Builder{} +// for _, tf := range f.TextFragments { +// sb.WriteString(tf.Raw(gitdiff.OpAdd)) +// } +// if sb.String() != tt.expected { +// restore(tt.target, noChanges, t) +// t.Error("expected: ", tt.expected, "got: ", sb.String()) +// } +// } +// restore(tt.target, noChanges, t) +// } +// } + +// func restore(path string, data []byte, t *testing.T) { +// err := os.WriteFile(path, data, 0644) +// if err != nil { +// t.Fatal(err) +// } +// } + +// func moveDotGit(from, to string) error { +// repoDirs, err := os.ReadDir("../../testdata/repos") +// if err != nil { +// return err +// } +// for _, dir := range repoDirs { +// if to == ".git" { +// _, err := os.Stat(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), "dotGit")) +// if os.IsNotExist(err) { +// // dont want to delete the only copy of .git accidentally +// continue +// } +// os.RemoveAll(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), ".git")) +// } +// if !dir.IsDir() { +// continue +// } +// _, err := os.Stat(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), from)) +// if os.IsNotExist(err) { +// continue +// } + +// err = os.Rename(fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), from), +// fmt.Sprintf("%s/%s/%s", repoBasePath, dir.Name(), to)) +// if err != nil { +// return err +// } +// } +// return nil +// } diff --git a/cli/detect/location.go b/cli/detect/location.go new file mode 100644 index 000000000..418af83f6 --- /dev/null +++ b/cli/detect/location.go @@ -0,0 +1,101 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package detect + +// Location represents a location in a file +type Location struct { + startLine int + endLine int + startColumn int + endColumn int + startLineIndex int + endLineIndex int +} + +func location(fragment Fragment, matchIndex []int) Location { + var ( + prevNewLine int + location Location + lineSet bool + _lineNum int + ) + + start := matchIndex[0] + end := matchIndex[1] + + // default startLineIndex to 0 + location.startLineIndex = 0 + + // Fixes: https://github.com/zricethezav/gitleaks/issues/1037 + // When a fragment does NOT have any newlines, a default "newline" + // will be counted to make the subsequent location calculation logic work + // for fragments will no newlines. + if len(fragment.newlineIndices) == 0 { + fragment.newlineIndices = [][]int{ + {len(fragment.Raw), len(fragment.Raw) + 1}, + } + } + + for lineNum, pair := range fragment.newlineIndices { + _lineNum = lineNum + newLineByteIndex := pair[0] + if prevNewLine <= start && start < newLineByteIndex { + lineSet = true + location.startLine = lineNum + location.endLine = lineNum + location.startColumn = (start - prevNewLine) + 1 // +1 because counting starts at 1 + location.startLineIndex = prevNewLine + location.endLineIndex = newLineByteIndex + } + if prevNewLine < end && end <= newLineByteIndex { + location.endLine = lineNum + location.endColumn = (end - prevNewLine) + location.endLineIndex = newLineByteIndex + } + prevNewLine = pair[0] + } + + if !lineSet { + // if lines never get set then that means the secret is most likely + // on the last line of the diff output and the diff output does not have + // a newline + location.startColumn = (start - prevNewLine) + 1 // +1 because counting starts at 1 + location.endColumn = (end - prevNewLine) + location.startLine = _lineNum + 1 + location.endLine = _lineNum + 1 + + // search for new line byte index + i := 0 + for end+i < len(fragment.Raw) { + if fragment.Raw[end+i] == '\n' { + break + } + if fragment.Raw[end+i] == '\r' { + break + } + i++ + } + location.endLineIndex = end + i + } + return location +} diff --git a/cli/detect/location_test.go b/cli/detect/location_test.go new file mode 100644 index 000000000..f76a6f814 --- /dev/null +++ b/cli/detect/location_test.go @@ -0,0 +1,82 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package detect + +import ( + "testing" +) + +// TestGetLocation tests the getLocation function. +func TestGetLocation(t *testing.T) { + tests := []struct { + linePairs [][]int + start int + end int + wantLocation Location + }{ + { + linePairs: [][]int{ + {0, 39}, + {40, 55}, + {56, 57}, + }, + start: 35, + end: 38, + wantLocation: Location{ + startLine: 1, + startColumn: 36, + endLine: 1, + endColumn: 38, + startLineIndex: 0, + endLineIndex: 40, + }, + }, + { + linePairs: [][]int{ + {0, 39}, + {40, 55}, + {56, 57}, + }, + start: 40, + end: 44, + wantLocation: Location{ + startLine: 2, + startColumn: 1, + endLine: 2, + endColumn: 4, + startLineIndex: 40, + endLineIndex: 56, + }, + }, + } + + for _, test := range tests { + loc := location(Fragment{newlineIndices: test.linePairs}, []int{test.start, test.end}) + if loc != test.wantLocation { + t.Errorf("\nstartLine %d\nstartColumn: %d\nendLine: %d\nendColumn: %d\nstartLineIndex: %d\nendlineIndex %d", + loc.startLine, loc.startColumn, loc.endLine, loc.endColumn, loc.startLineIndex, loc.endLineIndex) + + t.Error("got", loc, "want", test.wantLocation) + } + } +} diff --git a/cli/detect/utils.go b/cli/detect/utils.go new file mode 100644 index 000000000..462716239 --- /dev/null +++ b/cli/detect/utils.go @@ -0,0 +1,211 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package detect + +import ( + // "encoding/json" + "fmt" + "math" + "strings" + "time" + + "github.com/charmbracelet/lipgloss" + + "github.com/Infisical/infisical-merge/report" + + "github.com/gitleaks/go-gitdiff/gitdiff" + "github.com/rs/zerolog/log" +) + +// augmentGitFinding updates the start and end line numbers of a finding to include the +// delta from the git diff +func augmentGitFinding(finding report.Finding, textFragment *gitdiff.TextFragment, f *gitdiff.File) report.Finding { + if !strings.HasPrefix(finding.Match, "file detected") { + finding.StartLine += int(textFragment.NewPosition) + finding.EndLine += int(textFragment.NewPosition) + } + + if f.PatchHeader != nil { + finding.Commit = f.PatchHeader.SHA + finding.Message = f.PatchHeader.Message() + if f.PatchHeader.Author != nil { + finding.Author = f.PatchHeader.Author.Name + finding.Email = f.PatchHeader.Author.Email + } + finding.Date = f.PatchHeader.AuthorDate.UTC().Format(time.RFC3339) + } + return finding +} + +// shannonEntropy calculates the entropy of data using the formula defined here: +// https://en.wiktionary.org/wiki/Shannon_entropy +// Another way to think about what this is doing is calculating the number of bits +// needed to on average encode the data. So, the higher the entropy, the more random the data, the +// more bits needed to encode that data. +func shannonEntropy(data string) (entropy float64) { + if data == "" { + return 0 + } + + charCounts := make(map[rune]int) + for _, char := range data { + charCounts[char]++ + } + + invLength := 1.0 / float64(len(data)) + for _, count := range charCounts { + freq := float64(count) * invLength + entropy -= freq * math.Log2(freq) + } + + return entropy +} + +// filter will dedupe and redact findings +func filter(findings []report.Finding, redact bool) []report.Finding { + var retFindings []report.Finding + for _, f := range findings { + include := true + if strings.Contains(strings.ToLower(f.RuleID), "generic") { + for _, fPrime := range findings { + if f.StartLine == fPrime.StartLine && + f.Commit == fPrime.Commit && + f.RuleID != fPrime.RuleID && + strings.Contains(fPrime.Secret, f.Secret) && + !strings.Contains(strings.ToLower(fPrime.RuleID), "generic") { + + genericMatch := strings.Replace(f.Match, f.Secret, "REDACTED", -1) + betterMatch := strings.Replace(fPrime.Match, fPrime.Secret, "REDACTED", -1) + log.Trace().Msgf("skipping %s finding (%s), %s rule takes precendence (%s)", f.RuleID, genericMatch, fPrime.RuleID, betterMatch) + include = false + break + } + } + } + + if redact { + f.Redact() + } + if include { + retFindings = append(retFindings, f) + } + } + return retFindings +} + +func printFinding(f report.Finding, noColor bool) { + // trim all whitespace and tabs + f.Line = strings.TrimSpace(f.Line) + f.Secret = strings.TrimSpace(f.Secret) + f.Match = strings.TrimSpace(f.Match) + + isFileMatch := strings.HasPrefix(f.Match, "file detected:") + skipColor := noColor + finding := "" + var secret lipgloss.Style + + // Matches from filenames do not have a |line| or |secret| + if !isFileMatch { + matchInLineIDX := strings.Index(f.Line, f.Match) + secretInMatchIdx := strings.Index(f.Match, f.Secret) + + skipColor = false + + if matchInLineIDX == -1 || noColor { + skipColor = true + matchInLineIDX = 0 + } + + start := f.Line[0:matchInLineIDX] + startMatchIdx := 0 + if matchInLineIDX > 20 { + startMatchIdx = matchInLineIDX - 20 + start = "..." + f.Line[startMatchIdx:matchInLineIDX] + } + + matchBeginning := lipgloss.NewStyle().SetString(f.Match[0:secretInMatchIdx]).Foreground(lipgloss.Color("#f5d445")) + secret = lipgloss.NewStyle().SetString(f.Secret). + Bold(true). + Italic(true). + Foreground(lipgloss.Color("#f05c07")) + matchEnd := lipgloss.NewStyle().SetString(f.Match[secretInMatchIdx+len(f.Secret):]).Foreground(lipgloss.Color("#f5d445")) + + lineEndIdx := matchInLineIDX + len(f.Match) + if len(f.Line)-1 <= lineEndIdx { + lineEndIdx = len(f.Line) - 1 + } + + lineEnd := f.Line[lineEndIdx:] + + if len(f.Secret) > 100 { + secret = lipgloss.NewStyle().SetString(f.Secret[0:100] + "..."). + Bold(true). + Italic(true). + Foreground(lipgloss.Color("#f05c07")) + } + if len(lineEnd) > 20 { + lineEnd = lineEnd[0:20] + "..." + } + + finding = fmt.Sprintf("%s%s%s%s%s\n", strings.TrimPrefix(strings.TrimLeft(start, " "), "\n"), matchBeginning, secret, matchEnd, lineEnd) + } + + if skipColor || isFileMatch { + fmt.Printf("%-12s %s\n", "Finding:", f.Match) + fmt.Printf("%-12s %s\n", "Secret:", f.Secret) + } else { + fmt.Printf("%-12s %s", "Finding:", finding) + fmt.Printf("%-12s %s\n", "Secret:", secret) + } + + fmt.Printf("%-12s %s\n", "RuleID:", f.RuleID) + fmt.Printf("%-12s %f\n", "Entropy:", f.Entropy) + if f.File == "" { + fmt.Println("") + return + } + fmt.Printf("%-12s %s\n", "File:", f.File) + fmt.Printf("%-12s %d\n", "Line:", f.StartLine) + if f.Commit == "" { + fmt.Printf("%-12s %s\n", "Fingerprint:", f.Fingerprint) + fmt.Println("") + return + } + fmt.Printf("%-12s %s\n", "Commit:", f.Commit) + fmt.Printf("%-12s %s\n", "Author:", f.Author) + fmt.Printf("%-12s %s\n", "Email:", f.Email) + fmt.Printf("%-12s %s\n", "Date:", f.Date) + fmt.Printf("%-12s %s\n", "Fingerprint:", f.Fingerprint) + fmt.Println("") +} + +func containsDigit(s string) bool { + for _, c := range s { + switch c { + case '1', '2', '3', '4', '5', '6', '7', '8', '9': + return true + } + + } + return false +} diff --git a/cli/go.mod b/cli/go.mod index d1aadd208..640e6dc0c 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -4,12 +4,20 @@ go 1.19 require ( github.com/99designs/keyring v1.2.2 + github.com/charmbracelet/lipgloss v0.5.0 + github.com/fatih/semgroup v1.2.0 + github.com/gitleaks/go-gitdiff v0.8.0 + github.com/h2non/filetype v1.1.3 github.com/mattn/go-isatty v0.0.14 github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a github.com/muesli/mango-cobra v1.2.0 github.com/muesli/reflow v0.3.0 github.com/muesli/roff v0.1.0 + github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 + github.com/rs/zerolog v1.26.1 github.com/spf13/cobra v1.6.1 + github.com/spf13/viper v1.8.1 + github.com/stretchr/testify v1.8.0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d golang.org/x/term v0.5.0 ) @@ -19,22 +27,42 @@ require ( github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/danieljoos/wincred v1.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/denisbrodbeck/machineid v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-openapi/errors v0.20.2 // indirect github.com/go-openapi/strfmt v0.21.3 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/muesli/mango v0.1.0 // indirect github.com/muesli/mango-pflag v0.1.0 // indirect + github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect github.com/oklog/ulid v1.3.1 // indirect + github.com/pelletier/go-toml v1.9.3 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/posthog/posthog-go v0.0.0-20221221115252-24dfed35d71a // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.mongodb.org/mongo-driver v1.10.0 // indirect golang.org/x/net v0.7.0 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( @@ -43,6 +71,5 @@ require ( github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jedib0t/go-pretty v4.3.0+incompatible github.com/manifoldco/promptui v0.9.0 - github.com/sirupsen/logrus v1.9.0 github.com/spf13/pflag v1.0.5 // indirect ) diff --git a/cli/go.sum b/cli/go.sum index 2b514ea6e..574452d45 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -1,9 +1,59 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8= +github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -13,6 +63,13 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= @@ -20,10 +77,30 @@ github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnG github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= +github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/semgroup v1.2.0 h1:h/OLXwEM+3NNyAdZEpMiH1OzfplU09i2qXPVThGZvyg= +github.com/fatih/semgroup v1.2.0/go.mod h1:1KAD4iIYfXjE4U13B48VM4z9QUwV5Tt8O4rS879kgm8= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gitleaks/go-gitdiff v0.8.0 h1:7aExTZm+K/M/EQKOyYcub8rIAdWK6ONxPGuRzxmWW+0= +github.com/gitleaks/go-gitdiff v0.8.0/go.mod h1:pKz0X4YzCKZs30BL+weqBIG7mx0jl4tF1uXV9ZyNvrA= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= @@ -32,35 +109,153 @@ github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPr github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= +github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= @@ -72,75 +267,465 @@ github.com/muesli/mango-cobra v1.2.0 h1:DQvjzAM0PMZr85Iv9LIMaYISpTOliMEg+uMFtNbY github.com/muesli/mango-cobra v1.2.0/go.mod h1:vMJL54QytZAJhCT13LPVDfkvCUJ5/4jNUKF/8NC2UjA= github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe7Sg= github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0= +github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= +github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 h1:STjmj0uFfRryL9fzRA/OupNppeAID6QJYPMavTL7jtY= +github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 h1:lL+y4Xv20pVlCGyLzNHRC0I0rIHhIL1lTvHizoS/dU8= +github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posthog/posthog-go v0.0.0-20221221115252-24dfed35d71a h1:Ey0XWvrg6u6hyIn1Kd/jCCmL+bMv9El81tvuGBbxZGg= +github.com/posthog/posthog-go v0.0.0-20221221115252-24dfed35d71a/go.mod h1:oa2sAs9tGai3VldabTV0eWejt/O4/OOD7azP8GaikqU= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= +github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= +github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/cli/main.go b/cli/main.go index a51661ff6..75152ffc4 100644 --- a/cli/main.go +++ b/cli/main.go @@ -3,8 +3,15 @@ Copyright (c) 2023 Infisical Inc. */ package main -import "github.com/Infisical/infisical-merge/packages/cmd" +import ( + "os" + + "github.com/Infisical/infisical-merge/packages/cmd" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) func main() { + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) cmd.Execute() } diff --git a/cli/packages/api/api.go b/cli/packages/api/api.go index f0a347800..4ace4c387 100644 --- a/cli/packages/api/api.go +++ b/cli/packages/api/api.go @@ -2,10 +2,11 @@ package api import ( "fmt" + "net/http" "github.com/Infisical/infisical-merge/packages/config" "github.com/go-resty/resty/v2" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const USER_AGENT = "cli" @@ -179,6 +180,19 @@ func CallLogin2V2(httpClient *resty.Client, request GetLoginTwoV2Request) (GetLo SetBody(request). Post(fmt.Sprintf("%v/v2/auth/login2", config.INFISICAL_URL)) + cookies := response.Cookies() + // Find a cookie by name + cookieName := "jid" + var refreshToken *http.Cookie + for _, cookie := range cookies { + if cookie.Name == cookieName { + refreshToken = cookie + break + } + } + + loginTwoV2Response.RefreshToken = refreshToken.Value + if err != nil { return GetLoginTwoV2Response{}, fmt.Errorf("CallLogin2V2: Unable to complete api request [err=%s]", err) } @@ -222,7 +236,7 @@ func CallIsAuthenticated(httpClient *resty.Client) bool { } if response.IsError() { - log.Debugln(fmt.Errorf("CallIsAuthenticated: Unsuccessful response: [response=%v]", response)) + log.Debug().Msgf("CallIsAuthenticated: Unsuccessful response: [response=%v]", response) return false } @@ -247,3 +261,26 @@ func CallGetAccessibleEnvironments(httpClient *resty.Client, request GetAccessib return accessibleEnvironmentsResponse, nil } + +func CallGetNewAccessTokenWithRefreshToken(httpClient *resty.Client, refreshToken string) (GetNewAccessTokenWithRefreshTokenResponse, error) { + var newAccessToken GetNewAccessTokenWithRefreshTokenResponse + response, err := httpClient. + R(). + SetResult(&newAccessToken). + SetHeader("User-Agent", USER_AGENT). + SetCookie(&http.Cookie{ + Name: "jid", + Value: refreshToken, + }). + Post(fmt.Sprintf("%v/v1/auth/token", config.INFISICAL_URL)) + + if err != nil { + return GetNewAccessTokenWithRefreshTokenResponse{}, err + } + + if response.IsError() { + return GetNewAccessTokenWithRefreshTokenResponse{}, fmt.Errorf("CallGetNewAccessTokenWithRefreshToken: Unsuccessful response: [response=%v]", response) + } + + return newAccessToken, nil +} diff --git a/cli/packages/api/model.go b/cli/packages/api/model.go index 71354c84c..bce2a34d6 100644 --- a/cli/packages/api/model.go +++ b/cli/packages/api/model.go @@ -281,6 +281,7 @@ type GetLoginTwoV2Response struct { ProtectedKey string `json:"protectedKey"` ProtectedKeyIV string `json:"protectedKeyIV"` ProtectedKeyTag string `json:"protectedKeyTag"` + RefreshToken string `json:"RefreshToken"` } type VerifyMfaTokenRequest struct { @@ -314,3 +315,7 @@ type VerifyMfaTokenErrorResponse struct { Application string `json:"application"` Extra []interface{} `json:"extra"` } + +type GetNewAccessTokenWithRefreshTokenResponse struct { + Token string `json:"token"` +} diff --git a/cli/packages/cmd/export.go b/cli/packages/cmd/export.go index 07512798b..453d1b75c 100644 --- a/cli/packages/cmd/export.go +++ b/cli/packages/cmd/export.go @@ -11,7 +11,8 @@ import ( "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/util" - log "github.com/sirupsen/logrus" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -30,11 +31,6 @@ var exportCmd = &cobra.Command{ DisableFlagsInUseLine: true, Example: "infisical export --env=prod --format=json > secrets.json", Args: cobra.NoArgs, - PreRun: func(cmd *cobra.Command, args []string) { - toggleDebug(cmd, args) - // util.RequireLogin() - // util.RequireLocalWorkspaceFile() - }, Run: func(cmd *cobra.Command, args []string) { environmentName, _ := cmd.Flags().GetString("env") if !cmd.Flags().Changed("env") { @@ -100,6 +96,8 @@ var exportCmd = &cobra.Command{ } fmt.Print(output) + + Telemetry.CaptureEvent("cli-command:export", posthog.NewProperties().Set("secretsCount", len(secrets)).Set("version", util.CLI_VERSION)) }, } @@ -175,8 +173,7 @@ func formatAsJson(envs []models.SingleEnvironmentVariable) string { // Dump as a json array json, err := json.Marshal(envs) if err != nil { - log.Errorln("Unable to marshal environment variables to JSON") - log.Debugln(err) + log.Err(err).Msgf("Unable to marshal environment variables to JSON") return "" } return string(json) diff --git a/cli/packages/cmd/init.go b/cli/packages/cmd/init.go index 1562f6856..64387a837 100644 --- a/cli/packages/cmd/init.go +++ b/cli/packages/cmd/init.go @@ -12,14 +12,15 @@ import ( "github.com/Infisical/infisical-merge/packages/util" "github.com/go-resty/resty/v2" "github.com/manifoldco/promptui" - log "github.com/sirupsen/logrus" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) // runCmd represents the run command var initCmd = &cobra.Command{ Use: "init", - Short: "Used to initialize your project with Infisical", + Short: "Used to connect your local project with Infisical project", DisableFlagsInUseLine: true, Example: "infisical init", Args: cobra.ExactArgs(0), @@ -30,8 +31,8 @@ var initCmd = &cobra.Command{ if util.WorkspaceConfigFileExistsInCurrentPath() { shouldOverride, err := shouldOverrideWorkspacePrompt() if err != nil { - log.Errorln("Unable to parse your answer") - log.Debug(err) + log.Error().Msg("Unable to parse your answer") + log.Debug().Err(err) return } @@ -78,6 +79,9 @@ var initCmd = &cobra.Command{ if err != nil { util.HandleError(err) } + + Telemetry.CaptureEvent("cli-command:init", posthog.NewProperties().Set("version", util.CLI_VERSION)) + }, } diff --git a/cli/packages/cmd/logging.go b/cli/packages/cmd/logging.go deleted file mode 100644 index db1afa34f..000000000 --- a/cli/packages/cmd/logging.go +++ /dev/null @@ -1,27 +0,0 @@ -package cmd - -import ( - "fmt" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var debugLogging bool - -type PlainFormatter struct { -} - -func (f *PlainFormatter) Format(entry *log.Entry) ([]byte, error) { - return []byte(fmt.Sprintf("%s\n", entry.Message)), nil -} -func toggleDebug(cmd *cobra.Command, args []string) { - if debugLogging { - log.Info("Debug logs enabled") - log.SetLevel(log.DebugLevel) - log.SetFormatter(&log.TextFormatter{}) - } else { - plainFormatter := new(PlainFormatter) - log.SetFormatter(plainFormatter) - } -} diff --git a/cli/packages/cmd/login.go b/cli/packages/cmd/login.go index b85ba5cfe..ab0f531c2 100644 --- a/cli/packages/cmd/login.go +++ b/cli/packages/cmd/login.go @@ -22,7 +22,8 @@ import ( "github.com/fatih/color" "github.com/go-resty/resty/v2" "github.com/manifoldco/promptui" - log "github.com/sirupsen/logrus" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "golang.org/x/crypto/argon2" ) @@ -44,12 +45,11 @@ var loginCmd = &cobra.Command{ Use: "login", Short: "Login into your Infisical account", DisableFlagsInUseLine: true, - PreRun: toggleDebug, Run: func(cmd *cobra.Command, args []string) { currentLoggedInUserDetails, err := util.GetCurrentLoggedInUserDetails() // if the key can't be found or there is an error getting current credentials from key ring, allow them to override if err != nil && (strings.Contains(err.Error(), "The specified item could not be found in the keyring") || strings.Contains(err.Error(), "unable to get key from Keyring") || strings.Contains(err.Error(), "GetUserCredsFromKeyRing")) { - log.Debug(err) + log.Debug().Err(err) } else if err != nil { util.HandleError(err) } @@ -67,7 +67,7 @@ var loginCmd = &cobra.Command{ //override domain domainQuery := true - if config.INFISICAL_URL_MANUAL_OVERRIDE != util.INFISICAL_DEFAULT_API_URL { + if config.INFISICAL_URL_MANUAL_OVERRIDE != "" && config.INFISICAL_URL_MANUAL_OVERRIDE != util.INFISICAL_DEFAULT_API_URL { overrideDomain, err := DomainOverridePrompt() if err != nil { util.HandleError(err) @@ -97,8 +97,8 @@ var loginCmd = &cobra.Command{ loginOneResponse, loginTwoResponse, err := getFreshUserCredentials(email, password) if err != nil { - log.Infoln("Unable to authenticate with the provided credentials, please try again") - log.Debugln(err) + log.Warn().Msg("Unable to authenticate with the provided credentials, please ensure your email and password are correct") + log.Debug().Err(err) return } @@ -152,7 +152,7 @@ var loginCmd = &cobra.Command{ var decryptedPrivateKey []byte if loginTwoResponse.EncryptionVersion == 1 { - log.Debug("Login version 1") + log.Debug().Msg("Login version 1") encryptedPrivateKey, _ := base64.StdEncoding.DecodeString(loginTwoResponse.EncryptedPrivateKey) tag, err := base64.StdEncoding.DecodeString(loginTwoResponse.Tag) if err != nil { @@ -175,7 +175,7 @@ var loginCmd = &cobra.Command{ decryptedPrivateKey = computedDecryptedPrivateKey } else if loginTwoResponse.EncryptionVersion == 2 { - log.Debug("Login version 2") + log.Debug().Msg("Login version 2") protectedKey, err := base64.StdEncoding.DecodeString(loginTwoResponse.ProtectedKey) if err != nil { util.HandleError(err) @@ -239,22 +239,23 @@ var loginCmd = &cobra.Command{ } if string(decryptedPrivateKey) == "" || email == "" || loginTwoResponse.Token == "" { - log.Debugf("[decryptedPrivateKey=%s] [email=%s] [loginTwoResponse.Token=%s]", string(decryptedPrivateKey), email, loginTwoResponse.Token) + log.Debug().Msgf("[decryptedPrivateKey=%s] [email=%s] [loginTwoResponse.Token=%s]", string(decryptedPrivateKey), email, loginTwoResponse.Token) util.PrintErrorMessageAndExit("We were unable to fetch required details to complete your login. Run with -d to see more info") } userCredentialsToBeStored := &models.UserCredentials{ - Email: email, - PrivateKey: string(decryptedPrivateKey), - JTWToken: loginTwoResponse.Token, + Email: email, + PrivateKey: string(decryptedPrivateKey), + JTWToken: loginTwoResponse.Token, + RefreshToken: loginTwoResponse.RefreshToken, } err = util.StoreUserCredsInKeyRing(userCredentialsToBeStored) if err != nil { currentVault, _ := util.GetCurrentVaultBackend() - log.Errorf("Unable to store your credentials in system vault [%s]. Rerun with flag -d to see full logs", currentVault) - log.Errorln("To trouble shoot further, read https://infisical.com/docs/cli/faq") - log.Debugln(err) + log.Error().Msgf("Unable to store your credentials in system vault [%s]. Rerun with flag -d to see full logs", currentVault) + log.Error().Msgf("\nTo trouble shoot further, read https://infisical.com/docs/cli/faq") + log.Debug().Err(err) return } @@ -276,6 +277,7 @@ var loginCmd = &cobra.Command{ plainBold.Println("\nQuick links") fmt.Println("- Learn to inject secrets into your application at https://infisical.com/docs/cli/usage") fmt.Println("- Stuck? Join our slack for quick support https://infisical.com/slack") + Telemetry.CaptureEvent("cli-command:login", posthog.NewProperties().Set("infisical-backend", config.INFISICAL_URL).Set("version", util.CLI_VERSION)) }, } @@ -397,7 +399,7 @@ func askForLoginCredentials() (email string, password string, err error) { } func getFreshUserCredentials(email string, password string) (*api.GetLoginOneV2Response, *api.GetLoginTwoV2Response, error) { - log.Debugln("getFreshUserCredentials:", "email", email, "password", password) + log.Debug().Msg(fmt.Sprint("getFreshUserCredentials: ", "email", email, "password: ", password)) httpClient := resty.New() httpClient.SetRetryCount(5) @@ -413,7 +415,7 @@ func getFreshUserCredentials(email string, password string) (*api.GetLoginOneV2R }) if err != nil { - util.HandleError(err) + return nil, nil, err } // **** Login 2 diff --git a/cli/packages/cmd/pre-commit-script/pre-commit-without-bang.sh b/cli/packages/cmd/pre-commit-script/pre-commit-without-bang.sh new file mode 100644 index 000000000..e47643cc9 --- /dev/null +++ b/cli/packages/cmd/pre-commit-script/pre-commit-without-bang.sh @@ -0,0 +1,20 @@ + + +# MANAGED BY INFISICAL CLI (Do not modify): START +infisicalScanEnabled=$(git config --bool hooks.infisical-scan) + +if [ "$infisicalScanEnabled" != "false" ]; then + infisical scan git-changes -v --staged + exitCode=$? + if [ $exitCode -eq 1 ]; then + echo "Commit blocked: Infisical scan has uncovered secrets in your git commit" + echo "To disable the Infisical scan precommit hook run the following command:" + echo "" + echo " git config hooks.infisical-scan false" + echo "" + exit 1 + fi +else + echo 'Warning: infisical scan precommit disabled' +fi +# MANAGED BY INFISICAL CLI (Do not modify): END \ No newline at end of file diff --git a/cli/packages/cmd/pre-commit-script/pre-commit.sh b/cli/packages/cmd/pre-commit-script/pre-commit.sh new file mode 100644 index 000000000..f899a1a51 --- /dev/null +++ b/cli/packages/cmd/pre-commit-script/pre-commit.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# MANAGED BY INFISICAL CLI (Do not modify): START +infisicalScanEnabled=$(git config --bool hooks.infisical-scan) + +if [ "$infisicalScanEnabled" != "false" ]; then + infisical scan git-changes -v --staged + exitCode=$? + if [ $exitCode -eq 1 ]; then + echo "Commit blocked: Infisical scan has uncovered secrets in your git commit" + echo "To disable the Infisical scan precommit hook run the following command:" + echo "" + echo " git config hooks.infisical-scan false" + echo "" + exit 1 + fi +else + echo 'Warning: infisical scan precommit disabled' +fi +# MANAGED BY INFISICAL CLI (Do not modify): END \ No newline at end of file diff --git a/cli/packages/cmd/reset.go b/cli/packages/cmd/reset.go index 6c378fd4c..0007f2687 100644 --- a/cli/packages/cmd/reset.go +++ b/cli/packages/cmd/reset.go @@ -7,18 +7,16 @@ import ( "os" "github.com/Infisical/infisical-merge/packages/util" + "github.com/posthog/posthog-go" "github.com/spf13/cobra" ) var resetCmd = &cobra.Command{ Use: "reset", - Short: "Used delete all Infisical related data on your machine", + Short: "Used to delete all Infisical related data on your machine", DisableFlagsInUseLine: true, Example: "infisical reset", Args: cobra.NoArgs, - PreRun: func(cmd *cobra.Command, args []string) { - toggleDebug(cmd, args) - }, Run: func(cmd *cobra.Command, args []string) { // delete config _, pathToDir, err := util.GetFullConfigFilePath() @@ -40,6 +38,7 @@ var resetCmd = &cobra.Command{ util.DeleteBackupSecrets() util.PrintSuccessMessage("Reset successful") + Telemetry.CaptureEvent("cli-command:reset", posthog.NewProperties().Set("version", util.CLI_VERSION)) }, } diff --git a/cli/packages/cmd/root.go b/cli/packages/cmd/root.go index ac827feb3..9c7814ecc 100644 --- a/cli/packages/cmd/root.go +++ b/cli/packages/cmd/root.go @@ -5,13 +5,19 @@ package cmd import ( "os" + "strings" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/Infisical/infisical-merge/packages/config" + "github.com/Infisical/infisical-merge/packages/telemetry" "github.com/Infisical/infisical-merge/packages/util" ) +var Telemetry *telemetry.Telemetry + var rootCmd = &cobra.Command{ Use: "infisical", Short: "Infisical CLI is used to inject environment variables into any process", @@ -30,11 +36,14 @@ func Execute() { } func init() { - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - rootCmd.PersistentFlags().BoolVarP(&debugLogging, "debug", "d", false, "Enable verbose logging") + cobra.OnInitialize(initLog) + rootCmd.PersistentFlags().StringP("log-level", "l", "info", "log level (trace, debug, info, warn, error, fatal)") + rootCmd.PersistentFlags().Bool("telemetry", true, "Infisical collects non-sensitive telemetry data to enhance features and improve user experience. Participation is voluntary") rootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", util.INFISICAL_DEFAULT_API_URL, "Point the CLI to your own backend [can also set via environment variable name: INFISICAL_API_URL]") rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { - util.CheckForUpdate() + if !util.IsRunningInDocker() { + util.CheckForUpdate() + } } // if config.INFISICAL_URL is set to the default value, check if INFISICAL_URL is set in the environment @@ -45,4 +54,30 @@ func init() { } } + isTelemetryOn, _ := rootCmd.PersistentFlags().GetBool("telemetry") + Telemetry = telemetry.NewTelemetry(isTelemetryOn) +} + +func initLog() { + zerolog.SetGlobalLevel(zerolog.InfoLevel) + ll, err := rootCmd.Flags().GetString("log-level") + if err != nil { + log.Fatal().Msg(err.Error()) + } + switch strings.ToLower(ll) { + case "trace": + zerolog.SetGlobalLevel(zerolog.TraceLevel) + case "debug": + zerolog.SetGlobalLevel(zerolog.DebugLevel) + case "info": + zerolog.SetGlobalLevel(zerolog.InfoLevel) + case "warn": + zerolog.SetGlobalLevel(zerolog.WarnLevel) + case "err", "error": + zerolog.SetGlobalLevel(zerolog.ErrorLevel) + case "fatal": + zerolog.SetGlobalLevel(zerolog.FatalLevel) + default: + zerolog.SetGlobalLevel(zerolog.InfoLevel) + } } diff --git a/cli/packages/cmd/run.go b/cli/packages/cmd/run.go index ba60c9fec..afce399d5 100644 --- a/cli/packages/cmd/run.go +++ b/cli/packages/cmd/run.go @@ -15,7 +15,8 @@ import ( "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/util" "github.com/fatih/color" - log "github.com/sirupsen/logrus" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -28,7 +29,6 @@ var runCmd = &cobra.Command{ Use: "run [any infisical run command flags] -- [your application start command]", Short: "Used to inject environments variables into your application process", DisableFlagsInUseLine: true, - PreRun: toggleDebug, Args: func(cmd *cobra.Command, args []string) error { // Check if the --command flag has been set commandFlagSet := cmd.Flags().Changed("command") @@ -124,7 +124,9 @@ var runCmd = &cobra.Command{ env = append(env, s) } - log.Debugf("injecting the following environment variables into shell: %v", env) + log.Debug().Msgf("injecting the following environment variables into shell: %v", env) + + Telemetry.CaptureEvent("cli-command:run", posthog.NewProperties().Set("secretsCount", len(secrets)).Set("environment", environmentName).Set("isUsingServiceToken", infisicalToken != "").Set("single-command", strings.Join(args, " ")).Set("multi-command", cmd.Flag("command").Value.String()).Set("version", util.CLI_VERSION)) if cmd.Flags().Changed("command") { command := cmd.Flag("command").Value.String() @@ -217,7 +219,7 @@ func executeMultipleCommandWithEnvs(fullCommand string, secretsCount int, env [] cmd.Env = env color.Green("Injecting %v Infisical secrets into your application process", secretsCount) - log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand) + log.Debug().Msgf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand) return execCmd(cmd) } diff --git a/cli/packages/cmd/scan.go b/cli/packages/cmd/scan.go new file mode 100644 index 000000000..1226e3319 --- /dev/null +++ b/cli/packages/cmd/scan.go @@ -0,0 +1,586 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package cmd + +import ( + _ "embed" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/Infisical/infisical-merge/config" + "github.com/Infisical/infisical-merge/detect" + "github.com/Infisical/infisical-merge/packages/util" + "github.com/Infisical/infisical-merge/report" + "github.com/manifoldco/promptui" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +const configDescription = `config file path +order of precedence: +1. --config flag +2. env var INFISICAL_SCAN_CONFIG +3. (--source/-s)/.infisical-scan.toml +If none of the three options are used, then Infisical will use the default scan config` + +//go:embed pre-commit-script/pre-commit.sh +var preCommitTemplate []byte + +//go:embed pre-commit-script/pre-commit-without-bang.sh +var preCommitTemplateAppend []byte + +const ( + defaultHooksPath = ".git/hooks/" + preCommitFile = "pre-commit" +) + +func init() { + // scan flag for only scan command + scanCmd.Flags().String("log-opts", "", "git log options") + scanCmd.Flags().Bool("no-git", false, "treat git repo as a regular directory and scan those files, --log-opts has no effect on the scan when --no-git is set") + scanCmd.Flags().Bool("pipe", false, "scan input from stdin, ex: `cat some_file | infisical scan --pipe`") + scanCmd.Flags().Bool("follow-symlinks", false, "scan files that are symlinks to other files") + + // global scan flags + scanCmd.PersistentFlags().StringP("config", "c", "", configDescription) + scanCmd.PersistentFlags().Int("exit-code", 1, "exit code when leaks have been encountered") + scanCmd.PersistentFlags().StringP("source", "s", ".", "path to source") + scanCmd.PersistentFlags().StringP("report-path", "r", "", "report file") + scanCmd.PersistentFlags().StringP("report-format", "f", "json", "output format (json, csv, sarif)") + scanCmd.PersistentFlags().StringP("baseline-path", "b", "", "path to baseline with issues that can be ignored") + scanCmd.PersistentFlags().BoolP("verbose", "v", false, "show verbose output from scan (which file, where in the file, what secret)") + scanCmd.PersistentFlags().BoolP("no-color", "", false, "turn off color for verbose output") + scanCmd.PersistentFlags().Int("max-target-megabytes", 0, "files larger than this will be skipped") + scanCmd.PersistentFlags().Bool("redact", false, "redact secrets from logs and stdout") + + // scan git changes command flags + scanGitChangesCmd.Flags().Bool("staged", false, "detect secrets in a --staged state") + scanGitChangesCmd.Flags().String("log-opts", "", "git log options") + + // find config source + err := viper.BindPFlag("config", scanCmd.PersistentFlags().Lookup("config")) + if err != nil { + log.Fatal().Msgf("err binding config %s", err.Error()) + } + + // add flags to main + scanCmd.AddCommand(scanGitChangesCmd) + rootCmd.AddCommand(scanCmd) + + installCmd.Flags().Bool("pre-commit-hook", false, "installs pre commit hook for Git repository") + scanCmd.AddCommand(installCmd) +} + +func initScanConfig(cmd *cobra.Command) { + cfgPath, err := cmd.Flags().GetString("config") + if err != nil { + log.Fatal().Msg(err.Error()) + } + + if cfgPath != "" { + viper.SetConfigFile(cfgPath) + log.Debug().Msgf("using scan config %s from `--config`", cfgPath) + } else if os.Getenv(config.DefaultScanConfigEnvName) != "" { + envPath := os.Getenv(config.DefaultScanConfigEnvName) + viper.SetConfigFile(envPath) + log.Debug().Msgf("using scan config from %s env var: %s", config.DefaultScanConfigEnvName, envPath) + } else { + source, err := cmd.Flags().GetString("source") + if err != nil { + log.Fatal().Msg(err.Error()) + } + fileInfo, err := os.Stat(source) + if err != nil { + log.Fatal().Msg(err.Error()) + } + + if !fileInfo.IsDir() { + log.Debug().Msgf("unable to load scan config from %s since --source=%s is a file, using default config", + filepath.Join(source, config.DefaultScanConfigFileName), source) + viper.SetConfigType("toml") + if err = viper.ReadConfig(strings.NewReader(config.DefaultConfig)); err != nil { + log.Fatal().Msgf("err reading toml %s", err.Error()) + } + return + } + + if _, err := os.Stat(filepath.Join(source, config.DefaultScanConfigFileName)); os.IsNotExist(err) { + log.Debug().Msgf("no scan config found in path %s, using default scan config", filepath.Join(source, config.DefaultScanConfigFileName)) + viper.SetConfigType("toml") + if err = viper.ReadConfig(strings.NewReader(config.DefaultConfig)); err != nil { + log.Fatal().Msgf("err reading default scan config toml %s", err.Error()) + } + return + } else { + log.Debug().Msgf("using existing scan config %s from `(--source)/%s`", filepath.Join(source, config.DefaultScanConfigFileName), config.DefaultScanConfigFileName) + } + + viper.AddConfigPath(source) + viper.SetConfigName(config.DefaultScanConfigFileName) + viper.SetConfigType("toml") + } + if err := viper.ReadInConfig(); err != nil { + log.Fatal().Msgf("unable to load scan config, err: %s", err) + } +} + +var installCmd = &cobra.Command{ + Use: "install", + Short: "Install scanning scripts and tools. Use --help flag to see all options", + Args: cobra.ExactArgs(0), + Run: func(cmd *cobra.Command, args []string) { + installPrecommit := cmd.Flags().Changed("pre-commit-hook") + if installPrecommit { + hooksPath, err := getHooksPath() + if err != nil { + fmt.Printf("Error: %s\n", err) + return + } + + if hooksPath != ".git/hooks" { + defaultHookOverride, err := overrideDefaultHooksPath(hooksPath) + if err != nil { + fmt.Printf("Error: %s\n", err) + } + + if defaultHookOverride { + ConfigureGitHooksPath() + + log.Info().Msgf("To switch back previous githooks manager run: git config core.hooksPath %s\n", hooksPath) + return + } else { + log.Warn().Msgf("To automatically configure this hook, you need to switch the path of the Hooks. Alternatively, you can manually configure this hook by setting your pre-commit script to run command [infisical scan git-changes -v --staged].\n") + return + } + } + + err = createOrUpdatePreCommitFile(hooksPath) + if err != nil { + fmt.Printf("Error: %s\n", err) + return + } + + log.Info().Msgf("Pre-commit hook successfully added. Infisical scan should now run on each commit you make\n") + + Telemetry.CaptureEvent("cli-command:install --pre-commit-hook", posthog.NewProperties().Set("version", util.CLI_VERSION)) + + return + } + }} + +var scanCmd = &cobra.Command{ + Use: "scan", + Short: "Scan for leaked secrets in git history, directories, and files", + Run: func(cmd *cobra.Command, args []string) { + initScanConfig(cmd) + + var ( + vc config.ViperConfig + findings []report.Finding + err error + ) + + // Load config + if err = viper.Unmarshal(&vc); err != nil { + log.Fatal().Err(err).Msg("Failed to load config") + } + cfg, err := vc.Translate() + if err != nil { + log.Fatal().Err(err).Msg("Failed to load config") + } + cfg.Path, _ = cmd.Flags().GetString("config") + + // start timer + start := time.Now() + + // Setup detector + detector := detect.NewDetector(cfg) + detector.Config.Path, err = cmd.Flags().GetString("config") + if err != nil { + log.Fatal().Err(err).Msg("") + } + source, err := cmd.Flags().GetString("source") + if err != nil { + log.Fatal().Err(err).Msg("") + } + // if config path is not set, then use the {source}/.infisical-scan.toml path. + // note that there may not be a `{source}/.infisical-scan.toml` file, this is ok. + if detector.Config.Path == "" { + detector.Config.Path = filepath.Join(source, config.DefaultScanConfigFileName) + } + // set verbose flag + if detector.Verbose, err = cmd.Flags().GetBool("verbose"); err != nil { + log.Fatal().Err(err).Msg("") + } + // set redact flag + if detector.Redact, err = cmd.Flags().GetBool("redact"); err != nil { + log.Fatal().Err(err).Msg("") + } + if detector.MaxTargetMegaBytes, err = cmd.Flags().GetInt("max-target-megabytes"); err != nil { + log.Fatal().Err(err).Msg("") + } + // set color flag + if detector.NoColor, err = cmd.Flags().GetBool("no-color"); err != nil { + log.Fatal().Err(err).Msg("") + } + + if fileExists(filepath.Join(source, config.DefaultInfisicalIgnoreFineName)) { + if err = detector.AddGitleaksIgnore(filepath.Join(source, config.DefaultInfisicalIgnoreFineName)); err != nil { + log.Fatal().Err(err).Msg("could not call AddInfisicalIgnore") + } + } + + // ignore findings from the baseline (an existing report in json format generated earlier) + baselinePath, _ := cmd.Flags().GetString("baseline-path") + if baselinePath != "" { + err = detector.AddBaseline(baselinePath, source) + if err != nil { + log.Error().Msgf("Could not load baseline. The path must point to report generated by `infisical scan` using the default format: %s", err) + } + } + + // set follow symlinks flag + if detector.FollowSymlinks, err = cmd.Flags().GetBool("follow-symlinks"); err != nil { + log.Fatal().Err(err).Msg("") + } + + // set exit code + exitCode, err := cmd.Flags().GetInt("exit-code") + if err != nil { + log.Fatal().Err(err).Msg("could not get exit code") + } + + // determine what type of scan: + // - git: scan the history of the repo + // - no-git: scan files by treating the repo as a plain directory + noGit, err := cmd.Flags().GetBool("no-git") + if err != nil { + log.Fatal().Err(err).Msg("could not call GetBool() for no-git") + } + fromPipe, err := cmd.Flags().GetBool("pipe") + if err != nil { + log.Fatal().Err(err) + } + + log.Info().Msgf("scanning for exposed secrets...") + + // start the detector scan + if noGit { + findings, err = detector.DetectFiles(source) + if err != nil { + // don't exit on error, just log it + log.Error().Err(err).Msg("") + } + } else if fromPipe { + findings, err = detector.DetectReader(os.Stdin, 10) + if err != nil { + // log fatal to exit, no need to continue since a report + // will not be generated when scanning from a pipe...for now + log.Fatal().Err(err).Msg("") + } + } else { + var logOpts string + logOpts, err = cmd.Flags().GetString("log-opts") + if err != nil { + log.Fatal().Err(err).Msg("") + } + findings, err = detector.DetectGit(source, logOpts, detect.DetectType) + if err != nil { + // don't exit on error, just log it + log.Error().Err(err).Msg("") + } + } + + // log info about the scan + if err == nil { + log.Info().Msgf("scan completed in %s", FormatDuration(time.Since(start))) + if len(findings) != 0 { + log.Warn().Msgf("leaks found: %d", len(findings)) + } else { + log.Info().Msg("no leaks found") + } + } else { + log.Warn().Msgf("partial scan completed in %s", FormatDuration(time.Since(start))) + if len(findings) != 0 { + log.Warn().Msgf("%d leaks found in partial scan", len(findings)) + } else { + log.Warn().Msg("no leaks found in partial scan") + } + } + + Telemetry.CaptureEvent("cli-command:scan", posthog.NewProperties().Set("risks", len(findings)).Set("version", util.CLI_VERSION)) + + // write report if desired + reportPath, _ := cmd.Flags().GetString("report-path") + ext, _ := cmd.Flags().GetString("report-format") + if reportPath != "" { + if err := report.Write(findings, cfg, ext, reportPath); err != nil { + log.Fatal().Err(err).Msg("could not write") + } + } + + if err != nil { + os.Exit(1) + } + + if len(findings) != 0 { + os.Exit(exitCode) + } + }, +} + +var scanGitChangesCmd = &cobra.Command{ + Use: "git-changes", + Short: "Scan for secrets in uncommitted changes in a git repo", + Run: func(cmd *cobra.Command, args []string) { + initScanConfig(cmd) + + var vc config.ViperConfig + + if err := viper.Unmarshal(&vc); err != nil { + log.Fatal().Err(err).Msg("Failed to load config") + } + cfg, err := vc.Translate() + if err != nil { + log.Fatal().Err(err).Msg("Failed to load config") + } + + cfg.Path, _ = cmd.Flags().GetString("config") + exitCode, _ := cmd.Flags().GetInt("exit-code") + staged, _ := cmd.Flags().GetBool("staged") + start := time.Now() + + // Setup detector + detector := detect.NewDetector(cfg) + detector.Config.Path, err = cmd.Flags().GetString("config") + if err != nil { + log.Fatal().Err(err).Msg("") + } + source, err := cmd.Flags().GetString("source") + if err != nil { + log.Fatal().Err(err).Msg("") + } + // if config path is not set, then use the {source}/.infisical-scan.toml path. + // note that there may not be a `{source}/.infisical-scan.toml` file, this is ok. + if detector.Config.Path == "" { + detector.Config.Path = filepath.Join(source, config.DefaultScanConfigFileName) + } + // set verbose flag + if detector.Verbose, err = cmd.Flags().GetBool("verbose"); err != nil { + log.Fatal().Err(err).Msg("") + } + // set redact flag + if detector.Redact, err = cmd.Flags().GetBool("redact"); err != nil { + log.Fatal().Err(err).Msg("") + } + if detector.MaxTargetMegaBytes, err = cmd.Flags().GetInt("max-target-megabytes"); err != nil { + log.Fatal().Err(err).Msg("") + } + // set color flag + if detector.NoColor, err = cmd.Flags().GetBool("no-color"); err != nil { + log.Fatal().Err(err).Msg("") + } + + if fileExists(filepath.Join(source, config.DefaultInfisicalIgnoreFineName)) { + if err = detector.AddGitleaksIgnore(filepath.Join(source, config.DefaultInfisicalIgnoreFineName)); err != nil { + log.Fatal().Err(err).Msg("could not call AddInfisicalIgnore") + } + } + + // get log options for git scan + logOpts, err := cmd.Flags().GetString("log-opts") + if err != nil { + log.Fatal().Err(err).Msg("") + } + + log.Info().Msgf("scanning for exposed secrets...") + + // start git scan + var findings []report.Finding + if staged { + findings, err = detector.DetectGit(source, logOpts, detect.ProtectStagedType) + } else { + findings, err = detector.DetectGit(source, logOpts, detect.ProtectType) + } + if err != nil { + // don't exit on error, just log it + log.Error().Err(err).Msg("") + } + + // log info about the scan + log.Info().Msgf("scan completed in %s", FormatDuration(time.Since(start))) + if len(findings) != 0 { + log.Warn().Msgf("leaks found: %d", len(findings)) + } else { + log.Info().Msg("no leaks found") + } + + Telemetry.CaptureEvent("cli-command:scan git-changes", posthog.NewProperties().Set("risks", len(findings)).Set("version", util.CLI_VERSION)) + + reportPath, _ := cmd.Flags().GetString("report-path") + ext, _ := cmd.Flags().GetString("report-format") + if reportPath != "" { + if err = report.Write(findings, cfg, ext, reportPath); err != nil { + log.Fatal().Err(err).Msg("") + } + } + if len(findings) != 0 { + os.Exit(exitCode) + } + }, +} + +func fileExists(fileName string) bool { + // check for a .infisicalignore file + info, err := os.Stat(fileName) + if err != nil && !os.IsNotExist(err) { + return false + } + + if info != nil && err == nil { + if !info.IsDir() { + return true + } + } + return false +} + +func FormatDuration(d time.Duration) string { + scale := 100 * time.Second + // look for the max scale that is smaller than d + for scale > d { + scale = scale / 10 + } + return d.Round(scale / 100).String() +} + +func overrideDefaultHooksPath(managedHook string) (bool, error) { + YES := "Yes" + NO := "No" + + options := []string{YES, NO} + optionsPrompt := promptui.Select{ + Label: fmt.Sprintf("Your hooks path is set to [%s] but needs to be [.git/hooks] for automatic configuration. Would you like to switch? ", managedHook), + Items: options, + Size: 2, + } + + _, selectedOption, err := optionsPrompt.Run() + if err != nil { + return false, err + } + + return selectedOption == YES, err +} + +func ConfigureGitHooksPath() { + cmd := exec.Command("git", "config", "core.hooksPath", ".git/hooks") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + log.Fatal().Msgf("Failed to configure git hooks path: %v", err) + } +} + +// GetGitRoot returns the root directory of the current Git repository. +func GetGitRoot() (string, error) { + cmd := exec.Command("git", "rev-parse", "--show-toplevel") + output, err := cmd.Output() + + if err != nil { + return "", fmt.Errorf("failed to get git root directory: %w", err) + } + + gitRoot := strings.TrimSpace(string(output)) // Remove any trailing newline + return gitRoot, nil +} + +func getHooksPath() (string, error) { + out, err := exec.Command("git", "config", "core.hooksPath").Output() + if err != nil { + if len(out) == 0 { + out = []byte(".git/hooks") // set the default hook + } else { + log.Error().Msgf("Failed to get Git hooks path: %s\nOutput: %s\n", err, out) + } + } + + hooksPath := strings.TrimSpace(string(out)) + return hooksPath, nil +} + +func createOrUpdatePreCommitFile(hooksPath string) error { + // File doesn't exist, create a new one + rootGitRepoPath, err := GetGitRoot() + if err != nil { + return err + } + + filePath := fmt.Sprintf("%s/%s/%s", rootGitRepoPath, hooksPath, preCommitFile) + + _, err = os.Stat(filePath) + if err == nil { + // File already exists, check if it contains the managed comments + content, err := ioutil.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read pre-commit file: %s", err) + } + + if strings.Contains(string(content), "# MANAGED BY INFISICAL CLI (Do not modify): START") && + strings.Contains(string(content), "# MANAGED BY INFISICAL CLI (Do not modify): END") { + return nil + } + + // File already exists, append the template content + file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0755) + if err != nil { + return fmt.Errorf("failed to open pre-commit file: %s", err) + } + + defer file.Close() + + _, err = file.Write(preCommitTemplateAppend) + if err != nil { + return fmt.Errorf("failed to append to pre-commit file: %s", err) + } + + } else if os.IsNotExist(err) { + err = os.WriteFile(filePath, preCommitTemplate, 0755) + if err != nil { + return fmt.Errorf("failed to create pre-commit file: %s", err) + } + } else { + // Error occurred while checking file status + return fmt.Errorf("failed to check pre-commit file status: %s", err) + } + + return nil +} diff --git a/cli/packages/cmd/secrets.go b/cli/packages/cmd/secrets.go index 69a4539a6..26835eff1 100644 --- a/cli/packages/cmd/secrets.go +++ b/cli/packages/cmd/secrets.go @@ -19,7 +19,8 @@ import ( "github.com/Infisical/infisical-merge/packages/util" "github.com/Infisical/infisical-merge/packages/visualize" "github.com/go-resty/resty/v2" - log "github.com/sirupsen/logrus" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -28,7 +29,6 @@ var secretsCmd = &cobra.Command{ Short: "Used to create, read update and delete secrets", Use: "secrets", DisableFlagsInUseLine: true, - PreRun: toggleDebug, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { environmentName, _ := cmd.Flags().GetString("env") @@ -64,6 +64,7 @@ var secretsCmd = &cobra.Command{ } visualize.PrintAllSecretDetails(secrets) + Telemetry.CaptureEvent("cli-command:secrets", posthog.NewProperties().Set("secretCount", len(secrets)).Set("version", util.CLI_VERSION)) }, } @@ -73,7 +74,6 @@ var secretsGetCmd = &cobra.Command{ Use: "get [secrets]", DisableFlagsInUseLine: true, Args: cobra.MinimumNArgs(1), - PreRun: toggleDebug, Run: getSecretsByNames, } @@ -83,7 +83,6 @@ var secretsGenerateExampleEnvCmd = &cobra.Command{ Use: "generate-example-env", DisableFlagsInUseLine: true, Args: cobra.NoArgs, - PreRun: toggleDebug, Run: generateExampleEnv, } @@ -92,7 +91,6 @@ var secretsSetCmd = &cobra.Command{ Short: "Used set secrets", Use: "set [secrets]", DisableFlagsInUseLine: true, - PreRun: toggleDebug, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { util.RequireLocalWorkspaceFile() @@ -134,7 +132,7 @@ var secretsSetCmd = &cobra.Command{ currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey) if len(currentUsersPrivateKey) == 0 || len(encryptedWorkspaceKeySenderPublicKey) == 0 { - log.Debugf("Missing credentials for generating plainTextEncryptionKey: [currentUsersPrivateKey=%s] [encryptedWorkspaceKeySenderPublicKey=%s]", currentUsersPrivateKey, encryptedWorkspaceKeySenderPublicKey) + log.Debug().Msgf("Missing credentials for generating plainTextEncryptionKey: [currentUsersPrivateKey=%s] [encryptedWorkspaceKeySenderPublicKey=%s]", currentUsersPrivateKey, encryptedWorkspaceKeySenderPublicKey) util.PrintErrorMessageAndExit("Some required user credentials are missing to generate your [plainTextEncryptionKey]. Please run [infisical login] then try again") } @@ -270,6 +268,8 @@ var secretsSetCmd = &cobra.Command{ } visualize.Table(headers, rows) + + Telemetry.CaptureEvent("cli-command:secrets set", posthog.NewProperties().Set("version", util.CLI_VERSION)) }, } @@ -278,7 +278,6 @@ var secretsDeleteCmd = &cobra.Command{ Short: "Used to delete secrets by name", Use: "delete [secrets]", DisableFlagsInUseLine: true, - PreRun: toggleDebug, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { environmentName, _ := cmd.Flags().GetString("env") @@ -338,6 +337,7 @@ var secretsDeleteCmd = &cobra.Command{ fmt.Printf("secret name(s) [%v] have been deleted from your project \n", strings.Join(args, ", ")) + Telemetry.CaptureEvent("cli-command:secrets delete", posthog.NewProperties().Set("secretCount", len(secrets)).Set("version", util.CLI_VERSION)) }, } @@ -382,6 +382,7 @@ func getSecretsByNames(cmd *cobra.Command, args []string) { } visualize.PrintAllSecretDetails(requestedSecrets) + Telemetry.CaptureEvent("cli-command:secrets get", posthog.NewProperties().Set("secretCount", len(secrets)).Set("version", util.CLI_VERSION)) } func generateExampleEnv(cmd *cobra.Command, args []string) { @@ -570,6 +571,8 @@ func generateExampleEnv(cmd *cobra.Command, args []string) { fmt.Println(strings.Join(dashedList, "")) } fmt.Println(strings.Join(fullyGeneratedDocuments, "")) + + Telemetry.CaptureEvent("cli-command:generate-example-env", posthog.NewProperties().Set("secretCount", len(secrets)).Set("version", util.CLI_VERSION)) } func CenterString(s string, numStars int) string { diff --git a/cli/packages/cmd/user.go b/cli/packages/cmd/user.go index 6fef0ac8a..0d8f1b214 100644 --- a/cli/packages/cmd/user.go +++ b/cli/packages/cmd/user.go @@ -8,6 +8,7 @@ import ( "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/util" "github.com/manifoldco/promptui" + "github.com/posthog/posthog-go" "github.com/spf13/cobra" ) @@ -78,6 +79,8 @@ var switchCmd = &cobra.Command{ if err != nil { util.HandleError(err, "") } + + Telemetry.CaptureEvent("cli-command:user switch", posthog.NewProperties().Set("numberOfLoggedInProfiles", len(loggedInProfiles)).Set("version", util.CLI_VERSION)) }, } @@ -174,7 +177,7 @@ var domainCmd = &cobra.Command{ if err != nil { util.HandleError(err, "") } - + Telemetry.CaptureEvent("cli-command:user domain", posthog.NewProperties().Set("version", util.CLI_VERSION)) }, } diff --git a/cli/packages/cmd/vault.go b/cli/packages/cmd/vault.go index d9e32769e..e6662c5d6 100644 --- a/cli/packages/cmd/vault.go +++ b/cli/packages/cmd/vault.go @@ -4,9 +4,12 @@ Copyright (c) 2023 Infisical Inc. package cmd import ( + "fmt" + "github.com/99designs/keyring" "github.com/Infisical/infisical-merge/packages/util" - log "github.com/sirupsen/logrus" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -15,25 +18,24 @@ var vaultSetCmd = &cobra.Command{ Use: "set [vault-name]", Short: "Used to set the vault backend to store your login details securely at rest", DisableFlagsInUseLine: true, - PreRun: toggleDebug, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { wantedVaultTypeName := args[0] currentVaultBackend, err := util.GetCurrentVaultBackend() if err != nil { - log.Errorf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err) + log.Error().Msgf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err) return } if wantedVaultTypeName == string(currentVaultBackend) { - log.Errorf("You are already on vault backend [%s]", currentVaultBackend) + log.Error().Msgf("You are already on vault backend [%s]", currentVaultBackend) return } if isVaultToSwitchToValid(wantedVaultTypeName) { configFile, err := util.GetConfigFile() if err != nil { - log.Errorf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err) + log.Error().Msgf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err) return } @@ -42,13 +44,15 @@ var vaultSetCmd = &cobra.Command{ err = util.WriteConfigFile(&configFile) if err != nil { - log.Errorf("Unable to set vault to [%s] because an error occurred when saving the config file [err=%s]", wantedVaultTypeName, err) + log.Error().Msgf("Unable to set vault to [%s] because an error occurred when saving the config file [err=%s]", wantedVaultTypeName, err) return } - log.Infof("Successfully, switched vault backend from [%s] to [%s]. Please login in again to store your login details in the new vault with [infisical login]", currentVaultBackend, wantedVaultTypeName) + fmt.Printf("\nSuccessfully, switched vault backend from [%s] to [%s]. Please login in again to store your login details in the new vault with [infisical login]", currentVaultBackend, wantedVaultTypeName) + + Telemetry.CaptureEvent("cli-command:vault set", posthog.NewProperties().Set("currentVault", currentVaultBackend).Set("wantedVault", wantedVaultTypeName).Set("version", util.CLI_VERSION)) } else { - log.Errorf("The requested vault type [%s] is not available on this system. Only the following vault backends are available for you system: %s", wantedVaultTypeName, keyring.AvailableBackends()) + log.Error().Msgf("The requested vault type [%s] is not available on this system. Only the following vault backends are available for you system: %s", wantedVaultTypeName, keyring.AvailableBackends()) } }, } @@ -58,7 +62,6 @@ var vaultCmd = &cobra.Command{ Use: "vault", Short: "Used to manage where your Infisical login token is saved on your machine", DisableFlagsInUseLine: true, - PreRun: toggleDebug, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { printAvailableVaultBackends() @@ -66,17 +69,19 @@ var vaultCmd = &cobra.Command{ } func printAvailableVaultBackends() { - log.Infof("The following vaults are available on your system:") + fmt.Printf("The following vaults are available on your system:") for _, backend := range keyring.AvailableBackends() { - log.Infof("- %s", backend) + fmt.Printf("\n- %s", backend) } currentVaultBackend, err := util.GetCurrentVaultBackend() if err != nil { - log.Errorf("printAvailableVaultBackends: unable to print the available vault backend because of error [err=%s]", err) + log.Error().Msgf("printAvailableVaultBackends: unable to print the available vault backend because of error [err=%s]", err) } - log.Infof("\nYou are currently using [%s] vault to store your login credentials", string(currentVaultBackend)) + Telemetry.CaptureEvent("cli-command:vault", posthog.NewProperties().Set("currentVault", currentVaultBackend).Set("version", util.CLI_VERSION)) + + fmt.Printf("\n\nYou are currently using [%s] vault to store your login credentials", string(currentVaultBackend)) } // Checks if the vault that the user wants to switch to is a valid available vault diff --git a/cli/packages/models/cli.go b/cli/packages/models/cli.go index b9b0ab7b5..22f72e2da 100644 --- a/cli/packages/models/cli.go +++ b/cli/packages/models/cli.go @@ -5,9 +5,10 @@ import ( ) type UserCredentials struct { - Email string `json:"email"` - PrivateKey string `json:"privateKey"` - JTWToken string `json:"JTWToken"` + Email string `json:"email"` + PrivateKey string `json:"privateKey"` + JTWToken string `json:"JTWToken"` + RefreshToken string `json:"RefreshToken"` } // The file struct for Infisical config file diff --git a/cli/packages/models/error.go b/cli/packages/models/error.go deleted file mode 100644 index f6d58cb5a..000000000 --- a/cli/packages/models/error.go +++ /dev/null @@ -1,17 +0,0 @@ -package models - -import log "github.com/sirupsen/logrus" - -// Custom error type so that we can give helpful messages in CLI -type Error struct { - Err error - FriendlyMessage string -} - -func (e *Error) printFriendlyMessage() { - log.Infoln(e.FriendlyMessage) -} - -func (e *Error) printDebuError() { - log.Debugln(e.Err) -} diff --git a/cli/packages/telemetry/telemetry.go b/cli/packages/telemetry/telemetry.go new file mode 100644 index 000000000..ffd743457 --- /dev/null +++ b/cli/packages/telemetry/telemetry.go @@ -0,0 +1,82 @@ +package telemetry + +import ( + "github.com/Infisical/infisical-merge/packages/util" + "github.com/denisbrodbeck/machineid" + "github.com/posthog/posthog-go" + "github.com/rs/zerolog/log" +) + +var POSTHOG_API_KEY_FOR_CLI string + +type Telemetry struct { + isEnabled bool + posthogClient posthog.Client +} + +type NoOpLogger struct{} + +func (NoOpLogger) Logf(format string, args ...interface{}) { + log.Debug().Msgf(format, args...) +} + +func (NoOpLogger) Errorf(format string, args ...interface{}) { + log.Debug().Msgf(format, args...) +} + +func NewTelemetry(telemetryIsEnabled bool) *Telemetry { + if POSTHOG_API_KEY_FOR_CLI != "" { + client, _ := posthog.NewWithConfig( + POSTHOG_API_KEY_FOR_CLI, + posthog.Config{ + Logger: NoOpLogger{}, + }, + ) + + return &Telemetry{isEnabled: telemetryIsEnabled, posthogClient: client} + } else { + return &Telemetry{isEnabled: false} + } +} + +func (t *Telemetry) CaptureEvent(eventName string, properties posthog.Properties) { + userIdentity, err := t.GetDistinctId() + if err != nil { + return + } + + if t.isEnabled { + t.posthogClient.Enqueue(posthog.Capture{ + DistinctId: userIdentity, + Event: eventName, + Properties: properties, + }) + + defer t.posthogClient.Close() + } +} + +func (t *Telemetry) GetDistinctId() (string, error) { + var distinctId string + var outputErr error + + machineId, err := machineid.ID() + if err != nil { + outputErr = err + } + + infisicalConfig, err := util.GetConfigFile() + if err != nil { + outputErr = err + } + + if infisicalConfig.LoggedInUserEmail != "" { + distinctId = infisicalConfig.LoggedInUserEmail + } else if machineId != "" { + distinctId = "anonymous_cli_" + machineId + } else { + distinctId = "" + } + + return distinctId, outputErr +} diff --git a/cli/packages/util/check-for-update.go b/cli/packages/util/check-for-update.go index 53eb6dfb7..e59c04326 100644 --- a/cli/packages/util/check-for-update.go +++ b/cli/packages/util/check-for-update.go @@ -5,15 +5,15 @@ import ( "errors" "fmt" "io" + "io/ioutil" "net/http" "os" "os/exec" "runtime" "strings" - log "github.com/sirupsen/logrus" - "github.com/fatih/color" + "github.com/rs/zerolog/log" ) func CheckForUpdate() { @@ -22,7 +22,7 @@ func CheckForUpdate() { } latestVersion, err := getLatestTag("Infisical", "infisical") if err != nil { - log.Debug(err) + log.Debug().Err(err) // do nothing and continue return } @@ -51,7 +51,7 @@ func CheckForUpdate() { } func getLatestTag(repoOwner string, repoName string) (string, error) { - url := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", repoOwner, repoName) + url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", repoOwner, repoName) resp, err := http.Get(url) if err != nil { return "", err @@ -67,29 +67,18 @@ func getLatestTag(repoOwner string, repoName string) (string, error) { return "", err } - var tags []struct { - Name string `json:"name"` + var releaseTag struct { + TagName string `json:"tag_name"` } - if err := json.Unmarshal(body, &tags); err != nil { + if err := json.Unmarshal(body, &releaseTag); err != nil { return "", fmt.Errorf("failed to unmarshal github response: %w", err) } - // Filter tags with prefix "infisical-cli/" - prefix := "infisical-cli/v" - var validTags []string - for _, tag := range tags { - if strings.HasPrefix(tag.Name, prefix) { - validTags = append(validTags, tag.Name) - } - } - - if len(validTags) == 0 { - return "", errors.New("no tags for the CLI is found") - } + tag_prefix := "infisical-cli/v" // Extract the version from the first valid tag - version := strings.TrimPrefix(validTags[0], prefix) + version := strings.TrimPrefix(releaseTag.TagName, tag_prefix) return version, nil } @@ -143,3 +132,16 @@ func getLinuxPackageManager() string { return "" } + +func IsRunningInDocker() bool { + if _, err := os.Stat("/.dockerenv"); err == nil { + return true + } + + cgroup, err := ioutil.ReadFile("/proc/self/cgroup") + if err != nil { + return false + } + + return strings.Contains(string(cgroup), "docker") +} diff --git a/cli/packages/util/config.go b/cli/packages/util/config.go index 60b330c1e..e6c6fddb4 100644 --- a/cli/packages/util/config.go +++ b/cli/packages/util/config.go @@ -9,7 +9,7 @@ import ( "github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/models" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) func WriteInitalConfig(userCredentials *models.UserCredentials) error { @@ -73,7 +73,7 @@ func WriteInitalConfig(userCredentials *models.UserCredentials) error { func ConfigFileExists() bool { fullConfigFileURI, _, err := GetFullConfigFilePath() if err != nil { - log.Debugln("There was an error when creating the full path to config file", err) + log.Debug().Err(err).Msgf("There was an error when creating the full path to config file") return false } @@ -88,7 +88,7 @@ func WorkspaceConfigFileExistsInCurrentPath() bool { if _, err := os.Stat(INFISICAL_WORKSPACE_CONFIG_FILE_NAME); err == nil { return true } else { - log.Debugln(err) + log.Debug().Err(err) return false } } @@ -125,7 +125,7 @@ func FindWorkspaceConfigFile() (string, error) { _, err := os.Stat(path) if err == nil { // file found - log.Debugf("FindWorkspaceConfigFile: workspace file found at [path=%s]", path) + log.Debug().Msgf("FindWorkspaceConfigFile: workspace file found at [path=%s]", path) return path, nil } diff --git a/cli/packages/util/credentials.go b/cli/packages/util/credentials.go index 9147a717a..c93fc6027 100644 --- a/cli/packages/util/credentials.go +++ b/cli/packages/util/credentials.go @@ -9,6 +9,7 @@ import ( "github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/models" "github.com/go-resty/resty/v2" + "github.com/rs/zerolog/log" ) type LoggedInUserDetails struct { @@ -96,6 +97,20 @@ func GetCurrentLoggedInUserDetails() (LoggedInUserDetails, error) { } isAuthenticated := api.CallIsAuthenticated(httpClient) + + if !isAuthenticated { + accessTokenResponse, _ := api.CallGetNewAccessTokenWithRefreshToken(httpClient, userCreds.RefreshToken) + if accessTokenResponse.Token != "" { + isAuthenticated = true + userCreds.JTWToken = accessTokenResponse.Token + + err = StoreUserCredsInKeyRing(&userCreds) + if err != nil { + log.Debug().Msg("unable to store your user credentials with new access token") + } + } + } + if !isAuthenticated { return LoggedInUserDetails{ IsUserLoggedIn: true, // was logged in diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go index 8527c4059..d96ac3899 100644 --- a/cli/packages/util/helper.go +++ b/cli/packages/util/helper.go @@ -74,23 +74,12 @@ func ConfigContainsEmail(users []models.LoggedInUser, email string) bool { } func RequireLogin() { - currentUserDetails, err := GetCurrentLoggedInUserDetails() + // get the config file that stores the current logged in user email + configFile, _ := GetConfigFile() - if err != nil { - HandleError(err, "unable to retrieve your login details") - } - - if !currentUserDetails.IsUserLoggedIn { + if configFile.LoggedInUserEmail == "" { PrintErrorMessageAndExit("You must be logged in to run this command. To login, run [infisical login]") } - - if currentUserDetails.LoginExpired { - PrintErrorMessageAndExit("Your login expired, please login in again. To login, run [infisical login]") - } - - if currentUserDetails.UserCredentials.Email == "" && currentUserDetails.UserCredentials.JTWToken == "" && currentUserDetails.UserCredentials.PrivateKey == "" { - PrintErrorMessageAndExit("One or more of your login details is empty. Please try logging in again via by running [infisical login]") - } } func RequireServiceToken() { diff --git a/cli/packages/util/secrets.go b/cli/packages/util/secrets.go index 42a535b5a..a713abddb 100644 --- a/cli/packages/util/secrets.go +++ b/cli/packages/util/secrets.go @@ -12,9 +12,8 @@ import ( "github.com/Infisical/infisical-merge/packages/api" "github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/models" - log "github.com/sirupsen/logrus" - "github.com/go-resty/resty/v2" + "github.com/rs/zerolog/log" ) func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.SingleEnvironmentVariable, api.GetServiceTokenDetailsResponse, error) { @@ -97,7 +96,7 @@ func GetPlainTextSecretsViaJTW(JTWToken string, receiversPrivateKey string, work } if len(currentUsersPrivateKey) == 0 || len(encryptedWorkspaceKeySenderPublicKey) == 0 { - log.Debugf("Missing credentials for generating plainTextEncryptionKey: [currentUsersPrivateKey=%s] [encryptedWorkspaceKeySenderPublicKey=%s]", currentUsersPrivateKey, encryptedWorkspaceKeySenderPublicKey) + log.Debug().Msgf("Missing credentials for generating plainTextEncryptionKey: [currentUsersPrivateKey=%s] [encryptedWorkspaceKeySenderPublicKey=%s]", currentUsersPrivateKey, encryptedWorkspaceKeySenderPublicKey) PrintErrorMessageAndExit("Some required user credentials are missing to generate your [plainTextEncryptionKey]. Please run [infisical login] then try again") } @@ -136,12 +135,12 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models if infisicalToken == "" { if isConnected { - log.Debug("GetAllEnvironmentVariables: Connected to internet, checking logged in creds") + log.Debug().Msg("GetAllEnvironmentVariables: Connected to internet, checking logged in creds") RequireLocalWorkspaceFile() RequireLogin() } - log.Debug("GetAllEnvironmentVariables: Trying to fetch secrets using logged in details") + log.Debug().Msg("GetAllEnvironmentVariables: Trying to fetch secrets using logged in details") loggedInUserDetails, err := GetCurrentLoggedInUserDetails() if err != nil { @@ -164,7 +163,7 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models } secretsToReturn, errorToReturn = GetPlainTextSecretsViaJTW(loggedInUserDetails.UserCredentials.JTWToken, loggedInUserDetails.UserCredentials.PrivateKey, workspaceFile.WorkspaceId, params.Environment, params.TagSlugs) - log.Debugf("GetAllEnvironmentVariables: Trying to fetch secrets JTW token [err=%s]", errorToReturn) + log.Debug().Msgf("GetAllEnvironmentVariables: Trying to fetch secrets JTW token [err=%s]", errorToReturn) backupSecretsEncryptionKey := []byte(loggedInUserDetails.UserCredentials.PrivateKey)[0:32] if errorToReturn == nil { @@ -182,7 +181,7 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models } } else { - log.Debug("Trying to fetch secrets using service token") + log.Debug().Msg("Trying to fetch secrets using service token") secretsToReturn, _, errorToReturn = GetPlainTextSecretsViaServiceToken(infisicalToken) // if serviceTokenDetails.Environment != params.Environment { @@ -515,7 +514,7 @@ func DeleteBackupSecrets() error { func GetEnvFromWorkspaceFile() string { workspaceFile, err := GetWorkSpaceFromFile() if err != nil { - log.Debugf("getEnvFromWorkspaceFile: [err=%s]", err) + log.Debug().Msgf("getEnvFromWorkspaceFile: [err=%s]", err) return "" } @@ -529,17 +528,17 @@ func GetEnvFromWorkspaceFile() string { func GetEnvelopmentBasedOnGitBranch(workspaceFile models.WorkspaceConfigFile) string { branch, err := getCurrentBranch() if err != nil { - log.Debugf("getEnvelopmentBasedOnGitBranch: [err=%s]", err) + log.Debug().Msgf("getEnvelopmentBasedOnGitBranch: [err=%s]", err) } envBasedOnGitBranch, ok := workspaceFile.GitBranchToEnvironmentMapping[branch] - log.Debugf("GetEnvelopmentBasedOnGitBranch: [envBasedOnGitBranch=%s] [ok=%t]", envBasedOnGitBranch, ok) + log.Debug().Msgf("GetEnvelopmentBasedOnGitBranch: [envBasedOnGitBranch=%s] [ok=%t]", envBasedOnGitBranch, ok) if err == nil && ok { return envBasedOnGitBranch } else { - log.Debugf("getEnvelopmentBasedOnGitBranch: [err=%s]", err) + log.Debug().Msgf("getEnvelopmentBasedOnGitBranch: [err=%s]", err) return "" } } diff --git a/cli/packages/util/vault.go b/cli/packages/util/vault.go index 0852e5f48..ff45be1ca 100644 --- a/cli/packages/util/vault.go +++ b/cli/packages/util/vault.go @@ -54,10 +54,12 @@ func GetKeyRing() (keyring.Keyring, error) { } func fileKeyringPassphrasePrompt(prompt string) (string, error) { - if password, ok := os.LookupEnv("INFISICAL_VAULT_FILE_PASSPHRASE"); ok { + if password, ok := os.LookupEnv("VAULT_PASS"); ok { + return password, nil + } else if password, ok := os.LookupEnv("INFISICAL_VAULT_FILE_PASSPHRASE"); ok { return password, nil } else { - fmt.Println("You may set the environment variable `INFISICAL_VAULT_FILE_PASSPHRASE` with your password to avoid typing it") + fmt.Println("To avoid repeatedly typing your password, set the environment variable `VAULT_PASS` to your password") } fmt.Fprintf(os.Stderr, "%s:", prompt) diff --git a/cli/packages/visualize/visualize.go b/cli/packages/visualize/visualize.go index 8599f2405..365cbeac4 100644 --- a/cli/packages/visualize/visualize.go +++ b/cli/packages/visualize/visualize.go @@ -8,7 +8,7 @@ import ( "github.com/mattn/go-isatty" "github.com/muesli/ansi" "github.com/muesli/reflow/truncate" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" "golang.org/x/term" ) @@ -39,9 +39,9 @@ func Table(headers [3]string, rows [][3]string) { width, _, err := term.GetSize(int(os.Stdout.Fd())) if err != nil { if shouldTruncate { - log.Errorf("error getting terminal size: %s", err) + log.Error().Msgf("error getting terminal size: %s", err) } else { - log.Debug(err) + log.Debug().Err(err) } } diff --git a/cli/report/constants.go b/cli/report/constants.go new file mode 100644 index 000000000..8bad495cb --- /dev/null +++ b/cli/report/constants.go @@ -0,0 +1,25 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +package report + +const version = "v8.0.0" +const driver = "gitleaks" diff --git a/cli/report/csv.go b/cli/report/csv.go new file mode 100644 index 000000000..0a30c9fd5 --- /dev/null +++ b/cli/report/csv.go @@ -0,0 +1,81 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "encoding/csv" + "io" + "strconv" +) + +// writeCsv writes the list of findings to a writeCloser. +func writeCsv(f []Finding, w io.WriteCloser) error { + if len(f) == 0 { + return nil + } + defer w.Close() + cw := csv.NewWriter(w) + err := cw.Write([]string{"RuleID", + "Commit", + "File", + "SymlinkFile", + "Secret", + "Match", + "StartLine", + "EndLine", + "StartColumn", + "EndColumn", + "Author", + "Message", + "Date", + "Email", + "Fingerprint", + }) + if err != nil { + return err + } + for _, f := range f { + err = cw.Write([]string{f.RuleID, + f.Commit, + f.File, + f.SymlinkFile, + f.Secret, + f.Match, + strconv.Itoa(f.StartLine), + strconv.Itoa(f.EndLine), + strconv.Itoa(f.StartColumn), + strconv.Itoa(f.EndColumn), + f.Author, + f.Message, + f.Date, + f.Email, + f.Fingerprint, + }) + if err != nil { + return err + } + } + + cw.Flush() + return cw.Error() +} diff --git a/cli/report/csv_test.go b/cli/report/csv_test.go new file mode 100644 index 000000000..967026519 --- /dev/null +++ b/cli/report/csv_test.go @@ -0,0 +1,108 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestWriteCSV(t *testing.T) { + tests := []struct { + findings []Finding + testReportName string + expected string + wantEmpty bool + }{ + { + testReportName: "simple", + expected: filepath.Join(expectPath, "report", "csv_simple.csv"), + findings: []Finding{ + { + RuleID: "test-rule", + Match: "line containing secret", + Secret: "a secret", + StartLine: 1, + EndLine: 2, + StartColumn: 1, + EndColumn: 2, + Message: "opps", + File: "auth.py", + SymlinkFile: "", + Commit: "0000000000000000", + Author: "John Doe", + Email: "johndoe@gmail.com", + Date: "10-19-2003", + Fingerprint: "fingerprint", + }, + }}, + { + + wantEmpty: true, + testReportName: "empty", + expected: filepath.Join(expectPath, "report", "this_should_not_exist.csv"), + findings: []Finding{}}, + } + + for _, test := range tests { + tmpfile, err := os.Create(filepath.Join(tmpPath, test.testReportName+".csv")) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + err = writeCsv(test.findings, tmpfile) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + got, err := os.ReadFile(tmpfile.Name()) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + if test.wantEmpty { + if len(got) > 0 { + t.Errorf("Expected empty file, got %s", got) + } + os.Remove(tmpfile.Name()) + continue + } + want, err := os.ReadFile(test.expected) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + + if string(got) != string(want) { + err = os.WriteFile(strings.Replace(test.expected, ".csv", ".got.csv", 1), got, 0644) + if err != nil { + t.Error(err) + } + t.Errorf("got %s, want %s", string(got), string(want)) + } + + os.Remove(tmpfile.Name()) + } +} diff --git a/cli/report/finding.go b/cli/report/finding.go new file mode 100644 index 000000000..be461072b --- /dev/null +++ b/cli/report/finding.go @@ -0,0 +1,72 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "strings" +) + +// Finding contains information about strings that +// have been captured by a tree-sitter query. +type Finding struct { + Description string + StartLine int + EndLine int + StartColumn int + EndColumn int + + Line string `json:"-"` + + Match string + + // Secret contains the full content of what is matched in + // the tree-sitter query. + Secret string + + // File is the name of the file containing the finding + File string + SymlinkFile string + Commit string + + // Entropy is the shannon entropy of Value + Entropy float32 + + Author string + Email string + Date string + Message string + Tags []string + + // Rule is the name of the rule that was matched + RuleID string + + // unique identifer + Fingerprint string +} + +// Redact removes sensitive information from a finding. +func (f *Finding) Redact() { + f.Line = strings.Replace(f.Line, f.Secret, "REDACTED", -1) + f.Match = strings.Replace(f.Match, f.Secret, "REDACTED", -1) + f.Secret = "REDACTED" +} diff --git a/cli/report/finding_test.go b/cli/report/finding_test.go new file mode 100644 index 000000000..cdb74a329 --- /dev/null +++ b/cli/report/finding_test.go @@ -0,0 +1,48 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +package report + +import "testing" + +func TestRedact(t *testing.T) { + tests := []struct { + findings []Finding + redact bool + }{ + { + redact: true, + findings: []Finding{ + { + Secret: "line containing secret", + Match: "secret", + }, + }}, + } + for _, test := range tests { + for _, f := range test.findings { + f.Redact() + if f.Secret != "REDACTED" { + t.Error("redact not redacting: ", f.Secret) + } + } + } +} diff --git a/cli/report/json.go b/cli/report/json.go new file mode 100644 index 000000000..d091ac3c5 --- /dev/null +++ b/cli/report/json.go @@ -0,0 +1,37 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "encoding/json" + "io" +) + +func writeJson(findings []Finding, w io.WriteCloser) error { + if len(findings) == 0 { + findings = []Finding{} + } + encoder := json.NewEncoder(w) + encoder.SetIndent("", " ") + return encoder.Encode(findings) +} diff --git a/cli/report/json_test.go b/cli/report/json_test.go new file mode 100644 index 000000000..e81aaa827 --- /dev/null +++ b/cli/report/json_test.go @@ -0,0 +1,111 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestWriteJSON(t *testing.T) { + tests := []struct { + findings []Finding + testReportName string + expected string + wantEmpty bool + }{ + { + testReportName: "simple", + expected: filepath.Join(expectPath, "report", "json_simple.json"), + findings: []Finding{ + { + + Description: "", + RuleID: "test-rule", + Match: "line containing secret", + Secret: "a secret", + StartLine: 1, + EndLine: 2, + StartColumn: 1, + EndColumn: 2, + Message: "opps", + File: "auth.py", + SymlinkFile: "", + Commit: "0000000000000000", + Author: "John Doe", + Email: "johndoe@gmail.com", + Date: "10-19-2003", + Tags: []string{}, + }, + }}, + { + + testReportName: "empty", + expected: filepath.Join(expectPath, "report", "empty.json"), + findings: []Finding{}}, + } + + for _, test := range tests { + // create tmp file using os.TempDir() + tmpfile, err := os.Create(filepath.Join(tmpPath, test.testReportName+".json")) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + err = writeJson(test.findings, tmpfile) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + got, err := os.ReadFile(tmpfile.Name()) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + if test.wantEmpty { + if len(got) > 0 { + os.Remove(tmpfile.Name()) + t.Errorf("Expected empty file, got %s", got) + } + os.Remove(tmpfile.Name()) + continue + } + want, err := os.ReadFile(test.expected) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + + if string(got) != string(want) { + err = os.WriteFile(strings.Replace(test.expected, ".json", ".got.json", 1), got, 0644) + if err != nil { + t.Error(err) + } + t.Errorf("got %s, want %s", string(got), string(want)) + } + + os.Remove(tmpfile.Name()) + } +} diff --git a/cli/report/report.go b/cli/report/report.go new file mode 100644 index 000000000..1191a4f33 --- /dev/null +++ b/cli/report/report.go @@ -0,0 +1,54 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "os" + "strings" + + "github.com/Infisical/infisical-merge/config" +) + +const ( + // https://cwe.mitre.org/data/definitions/798.html + CWE = "CWE-798" + CWE_DESCRIPTION = "Use of Hard-coded Credentials" +) + +func Write(findings []Finding, cfg config.Config, ext string, reportPath string) error { + file, err := os.Create(reportPath) + if err != nil { + return err + } + ext = strings.ToLower(ext) + switch ext { + case ".json", "json": + err = writeJson(findings, file) + case ".csv", "csv": + err = writeCsv(findings, file) + case ".sarif", "sarif": + err = writeSarif(cfg, findings, file) + } + + return err +} diff --git a/cli/report/report_test.go b/cli/report/report_test.go new file mode 100644 index 000000000..ef38f19c2 --- /dev/null +++ b/cli/report/report_test.go @@ -0,0 +1,133 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "os" + "path/filepath" + "strconv" + "testing" + + "github.com/Infisical/infisical-merge/config" +) + +const ( + expectPath = "../testdata/expected/" + tmpPath = "../testdata/tmp" +) + +func TestReport(t *testing.T) { + tests := []struct { + findings []Finding + ext string + wantEmpty bool + }{ + { + ext: "json", + findings: []Finding{ + { + RuleID: "test-rule", + }, + }, + }, + { + ext: ".json", + findings: []Finding{ + { + RuleID: "test-rule", + }, + }, + }, + { + ext: ".jsonj", + findings: []Finding{ + { + RuleID: "test-rule", + }, + }, + wantEmpty: true, + }, + { + ext: ".csv", + findings: []Finding{ + { + RuleID: "test-rule", + }, + }, + }, + { + ext: "csv", + findings: []Finding{ + { + RuleID: "test-rule", + }, + }, + }, + { + ext: "CSV", + findings: []Finding{ + { + RuleID: "test-rule", + }, + }, + }, + // { + // ext: "SARIF", + // findings: []Finding{ + // { + // RuleID: "test-rule", + // }, + // }, + // }, + } + + for i, test := range tests { + tmpfile, err := os.Create(filepath.Join(tmpPath, strconv.Itoa(i)+test.ext)) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + err = Write(test.findings, config.Config{}, test.ext, tmpfile.Name()) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + got, err := os.ReadFile(tmpfile.Name()) + if err != nil { + os.Remove(tmpfile.Name()) + t.Error(err) + } + os.Remove(tmpfile.Name()) + + if len(got) == 0 && !test.wantEmpty { + t.Errorf("got empty file with extension " + test.ext) + } + + if test.wantEmpty { + if len(got) > 0 { + t.Errorf("Expected empty file, got %s", got) + } + continue + } + } +} diff --git a/cli/report/sarif.go b/cli/report/sarif.go new file mode 100644 index 000000000..e5120887a --- /dev/null +++ b/cli/report/sarif.go @@ -0,0 +1,237 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/Infisical/infisical-merge/config" +) + +func writeSarif(cfg config.Config, findings []Finding, w io.WriteCloser) error { + sarif := Sarif{ + Schema: "https://json.schemastore.org/sarif-2.1.0.json", + Version: "2.1.0", + Runs: getRuns(cfg, findings), + } + + encoder := json.NewEncoder(w) + encoder.SetIndent("", " ") + return encoder.Encode(sarif) +} + +func getRuns(cfg config.Config, findings []Finding) []Runs { + return []Runs{ + { + Tool: getTool(cfg), + Results: getResults(findings), + }, + } +} + +func getTool(cfg config.Config) Tool { + tool := Tool{ + Driver: Driver{ + Name: driver, + SemanticVersion: version, + InformationUri: "https://github.com/Infisical/infisical", + Rules: getRules(cfg), + }, + } + + // if this tool has no rules, ensure that it is represented as [] instead of null/nil + if hasEmptyRules(tool) { + tool.Driver.Rules = make([]Rules, 0) + } + + return tool +} + +func hasEmptyRules(tool Tool) bool { + return len(tool.Driver.Rules) == 0 +} + +func getRules(cfg config.Config) []Rules { + // TODO for _, rule := range cfg.Rules { + var rules []Rules + for _, rule := range cfg.OrderedRules() { + shortDescription := ShortDescription{ + Text: rule.Description, + } + if rule.Regex != nil { + shortDescription = ShortDescription{ + Text: rule.Regex.String(), + } + } else if rule.Path != nil { + shortDescription = ShortDescription{ + Text: rule.Path.String(), + } + } + rules = append(rules, Rules{ + ID: rule.RuleID, + Name: rule.Description, + Description: shortDescription, + }) + } + return rules +} + +func messageText(f Finding) string { + if f.Commit == "" { + return fmt.Sprintf("%s has detected secret for file %s.", f.RuleID, f.File) + } + + return fmt.Sprintf("%s has detected secret for file %s at commit %s.", f.RuleID, f.File, f.Commit) + +} + +func getResults(findings []Finding) []Results { + results := []Results{} + for _, f := range findings { + r := Results{ + Message: Message{ + Text: messageText(f), + }, + RuleId: f.RuleID, + Locations: getLocation(f), + // This information goes in partial fingerprings until revision + // data can be added somewhere else + PartialFingerPrints: PartialFingerPrints{ + CommitSha: f.Commit, + Email: f.Email, + CommitMessage: f.Message, + Date: f.Date, + Author: f.Author, + }, + } + results = append(results, r) + } + return results +} + +func getLocation(f Finding) []Locations { + uri := f.File + if f.SymlinkFile != "" { + uri = f.SymlinkFile + } + return []Locations{ + { + PhysicalLocation: PhysicalLocation{ + ArtifactLocation: ArtifactLocation{ + URI: uri, + }, + Region: Region{ + StartLine: f.StartLine, + EndLine: f.EndLine, + StartColumn: f.StartColumn, + EndColumn: f.EndColumn, + Snippet: Snippet{ + Text: f.Secret, + }, + }, + }, + }, + } +} + +type PartialFingerPrints struct { + CommitSha string `json:"commitSha"` + Email string `json:"email"` + Author string `json:"author"` + Date string `json:"date"` + CommitMessage string `json:"commitMessage"` +} + +type Sarif struct { + Schema string `json:"$schema"` + Version string `json:"version"` + Runs []Runs `json:"runs"` +} + +type ShortDescription struct { + Text string `json:"text"` +} + +type FullDescription struct { + Text string `json:"text"` +} + +type Rules struct { + ID string `json:"id"` + Name string `json:"name"` + Description ShortDescription `json:"shortDescription"` +} + +type Driver struct { + Name string `json:"name"` + SemanticVersion string `json:"semanticVersion"` + InformationUri string `json:"informationUri"` + Rules []Rules `json:"rules"` +} + +type Tool struct { + Driver Driver `json:"driver"` +} + +type Message struct { + Text string `json:"text"` +} + +type ArtifactLocation struct { + URI string `json:"uri"` +} + +type Region struct { + StartLine int `json:"startLine"` + StartColumn int `json:"startColumn"` + EndLine int `json:"endLine"` + EndColumn int `json:"endColumn"` + Snippet Snippet `json:"snippet"` +} + +type Snippet struct { + Text string `json:"text"` +} + +type PhysicalLocation struct { + ArtifactLocation ArtifactLocation `json:"artifactLocation"` + Region Region `json:"region"` +} + +type Locations struct { + PhysicalLocation PhysicalLocation `json:"physicalLocation"` +} + +type Results struct { + Message Message `json:"message"` + RuleId string `json:"ruleId"` + Locations []Locations `json:"locations"` + PartialFingerPrints `json:"partialFingerprints"` +} + +type Runs struct { + Tool Tool `json:"tool"` + Results []Results `json:"results"` +} diff --git a/cli/report/sarif_test.go b/cli/report/sarif_test.go new file mode 100644 index 000000000..9331060f1 --- /dev/null +++ b/cli/report/sarif_test.go @@ -0,0 +1,122 @@ +// MIT License + +// Copyright (c) 2019 Zachary Rice + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package report + +const configPath = "../testdata/config/" + +// func TestWriteSarif(t *testing.T) { +// tests := []struct { +// findings []Finding +// testReportName string +// expected string +// wantEmpty bool +// cfgName string +// }{ +// { +// cfgName: "simple", +// testReportName: "simple", +// expected: filepath.Join(expectPath, "report", "sarif_simple.sarif"), +// findings: []Finding{ +// { + +// Description: "A test rule", +// RuleID: "test-rule", +// Match: "line containing secret", +// Secret: "a secret", +// StartLine: 1, +// EndLine: 2, +// StartColumn: 1, +// EndColumn: 2, +// Message: "opps", +// File: "auth.py", +// Commit: "0000000000000000", +// Author: "John Doe", +// Email: "johndoe@gmail.com", +// Date: "10-19-2003", +// Tags: []string{}, +// }, +// }}, +// } + +// for _, test := range tests { +// // create tmp file using os.TempDir() +// tmpfile, err := os.Create(filepath.Join(tmpPath, test.testReportName+".json")) +// if err != nil { +// os.Remove(tmpfile.Name()) +// t.Error(err) +// } +// viper.Reset() +// viper.AddConfigPath(configPath) +// viper.SetConfigName(test.cfgName) +// viper.SetConfigType("toml") +// err = viper.ReadInConfig() +// if err != nil { +// t.Error(err) +// } + +// var vc config.ViperConfig +// err = viper.Unmarshal(&vc) +// if err != nil { +// t.Error(err) +// } + +// cfg, err := vc.Translate() +// if err != nil { +// t.Error(err) +// } +// err = writeSarif(cfg, test.findings, tmpfile) +// fmt.Println(cfg) +// if err != nil { +// os.Remove(tmpfile.Name()) +// t.Error(err) +// } +// got, err := os.ReadFile(tmpfile.Name()) +// if err != nil { +// os.Remove(tmpfile.Name()) +// t.Error(err) +// } +// if test.wantEmpty { +// if len(got) > 0 { +// os.Remove(tmpfile.Name()) +// t.Errorf("Expected empty file, got %s", got) +// } +// os.Remove(tmpfile.Name()) +// continue +// } +// want, err := os.ReadFile(test.expected) +// if err != nil { +// os.Remove(tmpfile.Name()) +// t.Error(err) +// } + +// if string(got) != string(want) { +// err = os.WriteFile(strings.Replace(test.expected, ".sarif", ".got.sarif", 1), got, 0644) +// if err != nil { +// t.Error(err) +// } +// t.Errorf("got %s, want %s", string(got), string(want)) +// } + +// os.Remove(tmpfile.Name()) +// } +// } diff --git a/cli/testdata/baseline/baseline.csv b/cli/testdata/baseline/baseline.csv new file mode 100644 index 000000000..d3f953727 --- /dev/null +++ b/cli/testdata/baseline/baseline.csv @@ -0,0 +1,2 @@ +RuleID,Commit,File,Secret,Match,StartLine,EndLine,StartColumn,EndColumn,Author,Message,Date,Email,Fingerprint +1,b,c,f,s,m,s,e,s,e,a,m,f,r,f \ No newline at end of file diff --git a/cli/testdata/baseline/baseline.json b/cli/testdata/baseline/baseline.json new file mode 100644 index 000000000..3a4c5427f --- /dev/null +++ b/cli/testdata/baseline/baseline.json @@ -0,0 +1,40 @@ +[ + { + "Description": "PyPI upload token", + "StartLine": 32, + "EndLine": 32, + "StartColumn": 21, + "EndColumn": 106, + "Match": "************************", + "Secret": "************************", + "File": "detect/detect_test.go", + "Commit": "9326f35380636bcbe61e94b0584d1618c4b5c2c2", + "Entropy": 1.9606875, + "Author": "****", + "Email": "****", + "Date": "2022-03-07T14:33:06Z", + "Message": "Escape - character in regex character groups (#802)\n\n* fix char escape\n\n* add test\n\n* fix verbosity in make test", + "Tags": [], + "RuleID": "pypi-upload-token", + "Fingerprint": "9326f35380636bcbe61e94b0584d1618c4b5c2c2:detect/detect_test.go:pypi-upload-token:32" + }, + { + "Description": "PyPI upload token", + "StartLine": 33, + "EndLine": 33, + "StartColumn": 21, + "EndColumn": 106, + "Match": "************************", + "Secret": "************************", + "File": "detect/detect_test.go", + "Commit": "9326f35380636bcbe61e94b0584d1618c4b5c2c2", + "Entropy": 1.9606875, + "Author": "****", + "Email": "****", + "Date": "2022-03-07T14:33:06Z", + "Message": "Escape - character in regex character groups (#802)\n\n* fix char escape\n\n* add test\n\n* fix verbosity in make test", + "Tags": [], + "RuleID": "pypi-upload-token", + "Fingerprint": "9326f35380636bcbe61e94b0584d1618c4b5c2c2:detect/detect_test.go:pypi-upload-token:33" + } +] diff --git a/cli/testdata/baseline/baseline.sarif b/cli/testdata/baseline/baseline.sarif new file mode 100644 index 000000000..b2f84890a --- /dev/null +++ b/cli/testdata/baseline/baseline.sarif @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/sarif-2.1.0.json", + "version": "2.1.0", + "runs": [ + ] +} diff --git a/cli/testdata/config/allow_aws_re.toml b/cli/testdata/config/allow_aws_re.toml new file mode 100644 index 000000000..2e2d4f278 --- /dev/null +++ b/cli/testdata/config/allow_aws_re.toml @@ -0,0 +1,9 @@ +title = "simple config with allowlist for aws" + +[[rules]] + description = "AWS Access Key" + id = "aws-access-key" + regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' + tags = ["key", "AWS"] + [rules.allowlist] + regexes = ['''AKIALALEMEL33243OLIA'''] diff --git a/cli/testdata/config/allow_commit.toml b/cli/testdata/config/allow_commit.toml new file mode 100644 index 000000000..ee8fefd83 --- /dev/null +++ b/cli/testdata/config/allow_commit.toml @@ -0,0 +1,9 @@ +title = "simple config with allowlist for a specific commit" + +[[rules]] + description = "AWS Access Key" + id = "aws-access-key" + regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' + tags = ["key", "AWS"] + [rules.allowlist] + commits = ['''allowthiscommit'''] diff --git a/cli/testdata/config/allow_global_aws_re.toml b/cli/testdata/config/allow_global_aws_re.toml new file mode 100644 index 000000000..7b7c3eeed --- /dev/null +++ b/cli/testdata/config/allow_global_aws_re.toml @@ -0,0 +1,8 @@ +[[rules]] + description = "AWS Access Key" + id = "aws-access-key" + regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' + tags = ["key", "AWS"] + +[allowlist] + regexes = ['''AKIALALEMEL33243OLIA'''] diff --git a/cli/testdata/config/allow_path.toml b/cli/testdata/config/allow_path.toml new file mode 100644 index 000000000..0fa837701 --- /dev/null +++ b/cli/testdata/config/allow_path.toml @@ -0,0 +1,9 @@ +title = "simple config with allowlist for .go files" + +[[rules]] + description = "AWS Access Key" + id = "aws-access-key" + regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' + tags = ["key", "AWS"] + [rules.allowlist] + paths = ['''.go'''] diff --git a/cli/testdata/config/bad_entropy_group.toml b/cli/testdata/config/bad_entropy_group.toml new file mode 100755 index 000000000..8e4d1c25c --- /dev/null +++ b/cli/testdata/config/bad_entropy_group.toml @@ -0,0 +1,8 @@ +title = "gitleaks config" + +[[rules]] +id = "discord-api-key" +description = "Discord API key" +regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{64})['\"]''' +secretGroup = 5 +entropy = 3.5 diff --git a/cli/testdata/config/base.toml b/cli/testdata/config/base.toml new file mode 100644 index 000000000..ba7b2ce2c --- /dev/null +++ b/cli/testdata/config/base.toml @@ -0,0 +1,10 @@ +title = "gitleaks config" + +[extend] +path="../testdata/config/extend_1.toml" + +[[rules]] + description = "AWS Secret Key" + id = "aws-secret-key" + regex = '''(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}''' + tags = ["key", "AWS"] diff --git a/cli/testdata/config/entropy_group.toml b/cli/testdata/config/entropy_group.toml new file mode 100755 index 000000000..eacfc50ea --- /dev/null +++ b/cli/testdata/config/entropy_group.toml @@ -0,0 +1,8 @@ +title = "gitleaks config" + +[[rules]] +id = "discord-api-key" +description = "Discord API key" +regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{64})['\"]''' +secretGroup = 3 +entropy = 3.5 diff --git a/cli/testdata/config/escaped_character_group.toml b/cli/testdata/config/escaped_character_group.toml new file mode 100644 index 000000000..b28039539 --- /dev/null +++ b/cli/testdata/config/escaped_character_group.toml @@ -0,0 +1,8 @@ +title = "gitleaks config" +# https://learnxinyminutes.com/docs/toml/ for toml reference + +[[rules]] + id = "pypi-upload-token" + description = "PyPI upload token" + regex = '''pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}''' + tags = ["key", "pypi"] \ No newline at end of file diff --git a/cli/testdata/config/extend_1.toml b/cli/testdata/config/extend_1.toml new file mode 100644 index 000000000..1f4eec0f0 --- /dev/null +++ b/cli/testdata/config/extend_1.toml @@ -0,0 +1,10 @@ +title = "gitleaks extended 1" + +[extend] +path="../testdata/config/extend_2.toml" + +[[rules]] + description = "AWS Access Key" + id = "aws-access-key" + regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' + tags = ["key", "AWS"] diff --git a/cli/testdata/config/extend_2.toml b/cli/testdata/config/extend_2.toml new file mode 100644 index 000000000..7532c99e6 --- /dev/null +++ b/cli/testdata/config/extend_2.toml @@ -0,0 +1,10 @@ +title = "gitleaks extended 2" + +[extend] +path="../testdata/config/extend_3.toml" + +[[rules]] + description = "AWS Secret Key" + id = "aws-secret-key-again" + regex = '''(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}''' + tags = ["key", "AWS"] diff --git a/cli/testdata/config/extend_3.toml b/cli/testdata/config/extend_3.toml new file mode 100644 index 000000000..47644c296 --- /dev/null +++ b/cli/testdata/config/extend_3.toml @@ -0,0 +1,9 @@ +title = "gitleaks extended 3" + +## This should not be loaded since we can only extend configs to a depth of 3 + +[[rules]] + description = "AWS Secret Key" + id = "aws-secret-key-again-again" + regex = '''(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}''' + tags = ["key", "AWS"] diff --git a/cli/testdata/config/generic.toml b/cli/testdata/config/generic.toml new file mode 100644 index 000000000..625e44efc --- /dev/null +++ b/cli/testdata/config/generic.toml @@ -0,0 +1,8 @@ +title = "gitleaks config" + +[[rules]] +description = "Generic API Key" +id = "generic-api-key" +regex = '''(?i)((key|api|token|secret|password)[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\-_=]{8,64})['\"]''' +entropy = 3.7 +secretGroup = 4 diff --git a/cli/testdata/config/generic_with_py_path.toml b/cli/testdata/config/generic_with_py_path.toml new file mode 100644 index 000000000..a528893e9 --- /dev/null +++ b/cli/testdata/config/generic_with_py_path.toml @@ -0,0 +1,36 @@ +title = "gitleaks config" + +[[rules]] +description = "Generic API Key" +id = "generic-api-key" +regex = '''(?i)((key|api|token|secret|password)[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\-_=]{8,64})['\"]''' +path = '''.py''' +entropy = 3.7 +secretGroup = 4 + +[allowlist] +description = "global allow lists" +regexes = [ + '''219-09-9999''', + '''078-05-1120''', + '''(9[0-9]{2}|666)-\d{2}-\d{4}''', + '''process''', + '''getenv''', + '''\.env''', + '''env\(''', + '''env\.''', + '''setting''', + '''load''', + '''token''', + '''password''', + '''secret''', + '''api\_key''', + '''apikey''', + '''api\-key''', + ] +paths = [ + '''gitleaks.toml''', + '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', + '''(go.mod|go.sum)$''' +] + diff --git a/cli/testdata/config/path_only.toml b/cli/testdata/config/path_only.toml new file mode 100644 index 000000000..97a8a4870 --- /dev/null +++ b/cli/testdata/config/path_only.toml @@ -0,0 +1,6 @@ +title = "gitleaks config" + +[[rules]] +description = "Python Files" +id = "python-files-only" +path = '''.py''' diff --git a/cli/testdata/config/simple.toml b/cli/testdata/config/simple.toml new file mode 100644 index 000000000..c5fbea1c3 --- /dev/null +++ b/cli/testdata/config/simple.toml @@ -0,0 +1,222 @@ +title = "gitleaks config" +# https://learnxinyminutes.com/docs/toml/ for toml reference + +[[rules]] + description = "AWS Access Key" + id = "aws-access-key" + regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' + tags = ["key", "AWS"] + +[[rules]] + description = "AWS Secret Key" + id = "aws-secret-key" + regex = '''(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}''' + tags = ["key", "AWS"] + +[[rules]] + description = "AWS MWS key" + id = "aws-mws-key" + regex = '''amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}''' + tags = ["key", "AWS", "MWS"] + +[[rules]] + description = "Facebook Secret Key" + id = "facebook-secret-key" + regex = '''(?i)(facebook|fb)(.{0,20})?(?-i)['\"][0-9a-f]{32}['\"]''' + tags = ["key", "Facebook"] + +[[rules]] + description = "Facebook Client ID" + id = "facebook-client-id" + regex = '''(?i)(facebook|fb)(.{0,20})?['\"][0-9]{13,17}['\"]''' + tags = ["key", "Facebook"] + +[[rules]] + description = "Twitter Secret Key" + id = "twitter-secret-key" + regex = '''(?i)twitter(.{0,20})?['\"][0-9a-z]{35,44}['\"]''' + tags = ["key", "Twitter"] + +[[rules]] + description = "Twitter Client ID" + id = "twitter-client-id" + regex = '''(?i)twitter(.{0,20})?['\"][0-9a-z]{18,25}['\"]''' + tags = ["client", "Twitter"] + +[[rules]] + description = "Github Personal Access Token" + id = "github-pat" + regex = '''ghp_[0-9a-zA-Z]{36}''' + tags = ["key", "Github"] +[[rules]] + description = "Github OAuth Access Token" + id = "github-oauth" + regex = '''gho_[0-9a-zA-Z]{36}''' + tags = ["key", "Github"] +[[rules]] + id = "github-app" + description = "Github App Token" + regex = '''(ghu|ghs)_[0-9a-zA-Z]{36}''' + tags = ["key", "Github"] +[[rules]] + id = "github-refresh" + description = "Github Refresh Token" + regex = '''ghr_[0-9a-zA-Z]{76}''' + tags = ["key", "Github"] + +[[rules]] + id = "linkedin-client" + description = "LinkedIn Client ID" + regex = '''(?i)linkedin(.{0,20})?(?-i)[0-9a-z]{12}''' + tags = ["client", "LinkedIn"] + +[[rules]] + id = "linkedin-secret" + description = "LinkedIn Secret Key" + regex = '''(?i)linkedin(.{0,20})?[0-9a-z]{16}''' + tags = ["secret", "LinkedIn"] + +[[rules]] + id = "slack" + description = "Slack" + regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})?''' + tags = ["key", "Slack"] + +[[rules]] + id = "apkey" + description = "Asymmetric Private Key" + regex = '''-----BEGIN ((EC|PGP|DSA|RSA|OPENSSH) )?PRIVATE KEY( BLOCK)?-----''' + tags = ["key", "AsymmetricPrivateKey"] + +[[rules]] + id = "google" + description = "Google API key" + regex = '''AIza[0-9A-Za-z\-_]{35}''' + tags = ["key", "Google"] + +[[rules]] + id = "google" + description = "Google (GCP) Service Account" + regex = '''"type": "service_account"''' + tags = ["key", "Google"] + +[[rules]] + id = "heroku" + description = "Heroku API key" + regex = '''(?i)heroku(.{0,20})?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}''' + tags = ["key", "Heroku"] + +[[rules]] + id = "mailchimp" + description = "MailChimp API key" + regex = '''(?i)(mailchimp|mc)(.{0,20})?[0-9a-f]{32}-us[0-9]{1,2}''' + tags = ["key", "Mailchimp"] + +[[rules]] + id = "mailgun" + description = "Mailgun API key" + regex = '''((?i)(mailgun|mg)(.{0,20})?)?key-[0-9a-z]{32}''' + tags = ["key", "Mailgun"] + +[[rules]] + id = "paypal" + description = "PayPal Braintree access token" + regex = '''access_token\$production\$[0-9a-z]{16}\$[0-9a-f]{32}''' + tags = ["key", "Paypal"] + +[[rules]] + id = "piacatic" + description = "Picatic API key" + regex = '''sk_live_[0-9a-z]{32}''' + tags = ["key", "Picatic"] + +[[rules]] + id = "sendgrid" + description = "SendGrid API Key" + regex = '''SG\.[\w_]{16,32}\.[\w_]{16,64}''' + tags = ["key", "SendGrid"] + +[[rules]] + description = "Sidekiq Secret" + id = "sidekiq-secret" + regex = '''(?i)(?:BUNDLE_ENTERPRISE__CONTRIBSYS__COM|BUNDLE_GEMS__CONTRIBSYS__COM)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:=|\|\|:|<=|=>|:)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{8}:[a-f0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)''' + secretGroup = 1 + keywords = [ + "bundle_enterprise__contribsys__com","bundle_gems__contribsys__com", + ] + +[[rules]] + description = "Sidekiq Sensitive URL" + id = "sidekiq-sensitive-url" + regex = '''(?i)\b(http(?:s??):\/\/)([a-f0-9]{8}:[a-f0-9]{8})@(?:gems.contribsys.com|enterprise.contribsys.com)(?:[\/|\#|\?|:]|$)''' + secretGroup = 2 + keywords = [ + "gems.contribsys.com","enterprise.contribsys.com", + ] + +[[rules]] + id = "slack-webhook" + 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}''' + tags = ["key", "slack"] + +[[rules]] + id = "stripe" + description = "Stripe API key" + regex = '''(?i)stripe(.{0,20})?[sr]k_live_[0-9a-zA-Z]{24}''' + tags = ["key", "Stripe"] + +[[rules]] + id = "square" + description = "Square access token" + regex = '''sq0atp-[0-9A-Za-z\-_]{22}''' + tags = ["key", "square"] + +[[rules]] + id = "square-oauth" + description = "Square OAuth secret" + regex = '''sq0csp-[0-9A-Za-z\-_]{43}''' + tags = ["key", "square"] + +[[rules]] + id = "twilio" + description = "Twilio API key" + regex = '''(?i)twilio(.{0,20})?SK[0-9a-f]{32}''' + tags = ["key", "twilio"] + +[[rules]] + id = "dynatrace" + description = "Dynatrace ttoken" + regex = '''dt0[a-zA-Z]{1}[0-9]{2}\.[A-Z0-9]{24}\.[A-Z0-9]{64}''' + tags = ["key", "Dynatrace"] + +[[rules]] + id = "shopify" + description = "Shopify shared secret" + regex = '''shpss_[a-fA-F0-9]{32}''' + tags = ["key", "Shopify"] + +[[rules]] + id = "shopify-access" + description = "Shopify access token" + regex = '''shpat_[a-fA-F0-9]{32}''' + tags = ["key", "Shopify"] + +[[rules]] + id = "shopify-custom" + description = "Shopify custom app access token" + regex = '''shpca_[a-fA-F0-9]{32}''' + tags = ["key", "Shopify"] + +[[rules]] + id = "shopify-private" + description = "Shopify private app access token" + regex = '''shppa_[a-fA-F0-9]{32}''' + tags = ["key", "Shopify"] + +[[rules]] + id = "pypi" + description = "PyPI upload token" + regex = '''pypi-AgEIcHlwaS5vcmc[A-Za-z0-9-_]{50,1000}''' + tags = ["key", "pypi"] + diff --git a/cli/testdata/expected/git/small-branch-foo.txt b/cli/testdata/expected/git/small-branch-foo.txt new file mode 100644 index 000000000..b3554c7ac --- /dev/null +++ b/cli/testdata/expected/git/small-branch-foo.txt @@ -0,0 +1,17 @@ +import ( + "fmt" + "os" +) + // seems safer + aws_token := os.Getenv("AWS_TOKEN") +package foo + +import "fmt" + +func Foo() { + fmt.Println("foo") + + // seems safe + aws_token := "AKIALALEMEL33243OLIA" + fmt.Println(aws_token) +} diff --git a/cli/testdata/expected/git/small.txt b/cli/testdata/expected/git/small.txt new file mode 100644 index 000000000..7235dd3a8 --- /dev/null +++ b/cli/testdata/expected/git/small.txt @@ -0,0 +1,67 @@ +import ( + "fmt" + "os" +) + // seems safer + aws_token := os.Getenv("AWS_TOKEN") +package foo + +import "fmt" + +func Foo() { + fmt.Println("foo") + + // seems safe + aws_token := "AKIALALEMEL33243OLIA" + fmt.Println(aws_token) +} +package api + +import "fmt" + +func PrintHello() { + fmt.Println("hello") +} +import ( + "fmt" + "os" +) + var a = "initial" + fmt.Println(a) + var b, c int = 1, 2 + fmt.Println(b, c) + var d = true + fmt.Println(d) + var e int + fmt.Println(e) + // load secret via env + awsToken := os.Getenv("AWS_TOKEN") + + f := "apple" + fmt.Println(f) + + // opps I added a secret at line 20 + awsToken := "AKIALALEMEL33243OLIA" +package main + +import "fmt" + +func main() { + + var a = "initial" + fmt.Println(a) + + var b, c int = 1, 2 + fmt.Println(b, c) + + var d = true + fmt.Println(d) + + var e int + fmt.Println(e) + + f := "apple" + fmt.Println(f) +} +# test +This is a repo used for testing gitleaks diff --git a/cli/testdata/expected/report/csv_simple.csv b/cli/testdata/expected/report/csv_simple.csv new file mode 100644 index 000000000..a02ab0101 --- /dev/null +++ b/cli/testdata/expected/report/csv_simple.csv @@ -0,0 +1,2 @@ +RuleID,Commit,File,SymlinkFile,Secret,Match,StartLine,EndLine,StartColumn,EndColumn,Author,Message,Date,Email,Fingerprint +test-rule,0000000000000000,auth.py,,a secret,line containing secret,1,2,1,2,John Doe,opps,10-19-2003,johndoe@gmail.com,fingerprint diff --git a/cli/testdata/expected/report/empty.json b/cli/testdata/expected/report/empty.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/cli/testdata/expected/report/empty.json @@ -0,0 +1 @@ +[] diff --git a/cli/testdata/expected/report/json_simple.json b/cli/testdata/expected/report/json_simple.json new file mode 100644 index 000000000..c7516f118 --- /dev/null +++ b/cli/testdata/expected/report/json_simple.json @@ -0,0 +1,22 @@ +[ + { + "Description": "", + "StartLine": 1, + "EndLine": 2, + "StartColumn": 1, + "EndColumn": 2, + "Match": "line containing secret", + "Secret": "a secret", + "File": "auth.py", + "SymlinkFile": "", + "Commit": "0000000000000000", + "Entropy": 0, + "Author": "John Doe", + "Email": "johndoe@gmail.com", + "Date": "10-19-2003", + "Message": "opps", + "Tags": [], + "RuleID": "test-rule", + "Fingerprint": "" + } +] diff --git a/cli/testdata/expected/report/sarif_simple.got.sarif b/cli/testdata/expected/report/sarif_simple.got.sarif new file mode 100644 index 000000000..9708dd833 --- /dev/null +++ b/cli/testdata/expected/report/sarif_simple.got.sarif @@ -0,0 +1,302 @@ +{ + "$schema": "https://json.schemastore.org/sarif-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "gitleaks", + "semanticVersion": "v8.0.0", + "informationUri": "https://github.com/Infisical/infisical", + "rules": [ + { + "id": "aws-access-key", + "name": "AWS Access Key", + "shortDescription": { + "text": "(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}" + } + }, + { + "id": "aws-secret-key", + "name": "AWS Secret Key", + "shortDescription": { + "text": "(?i)aws_(.{0,20})?=?.[\\'\\\"0-9a-zA-Z\\/+]{40}" + } + }, + { + "id": "aws-mws-key", + "name": "AWS MWS key", + "shortDescription": { + "text": "amzn\\.mws\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + } + }, + { + "id": "facebook-secret-key", + "name": "Facebook Secret Key", + "shortDescription": { + "text": "(?i)(facebook|fb)(.{0,20})?(?-i)['\\\"][0-9a-f]{32}['\\\"]" + } + }, + { + "id": "facebook-client-id", + "name": "Facebook Client ID", + "shortDescription": { + "text": "(?i)(facebook|fb)(.{0,20})?['\\\"][0-9]{13,17}['\\\"]" + } + }, + { + "id": "twitter-secret-key", + "name": "Twitter Secret Key", + "shortDescription": { + "text": "(?i)twitter(.{0,20})?['\\\"][0-9a-z]{35,44}['\\\"]" + } + }, + { + "id": "twitter-client-id", + "name": "Twitter Client ID", + "shortDescription": { + "text": "(?i)twitter(.{0,20})?['\\\"][0-9a-z]{18,25}['\\\"]" + } + }, + { + "id": "github-pat", + "name": "Github Personal Access Token", + "shortDescription": { + "text": "ghp_[0-9a-zA-Z]{36}" + } + }, + { + "id": "github-oauth", + "name": "Github OAuth Access Token", + "shortDescription": { + "text": "gho_[0-9a-zA-Z]{36}" + } + }, + { + "id": "github-app", + "name": "Github App Token", + "shortDescription": { + "text": "(ghu|ghs)_[0-9a-zA-Z]{36}" + } + }, + { + "id": "github-refresh", + "name": "Github Refresh Token", + "shortDescription": { + "text": "ghr_[0-9a-zA-Z]{76}" + } + }, + { + "id": "linkedin-client", + "name": "LinkedIn Client ID", + "shortDescription": { + "text": "(?i)linkedin(.{0,20})?(?-i)[0-9a-z]{12}" + } + }, + { + "id": "linkedin-secret", + "name": "LinkedIn Secret Key", + "shortDescription": { + "text": "(?i)linkedin(.{0,20})?[0-9a-z]{16}" + } + }, + { + "id": "slack", + "name": "Slack", + "shortDescription": { + "text": "xox[baprs]-([0-9a-zA-Z]{10,48})?" + } + }, + { + "id": "apkey", + "name": "Asymmetric Private Key", + "shortDescription": { + "text": "-----BEGIN ((EC|PGP|DSA|RSA|OPENSSH) )?PRIVATE KEY( BLOCK)?-----" + } + }, + { + "id": "google", + "name": "Google (GCP) Service Account", + "shortDescription": { + "text": "\"type\": \"service_account\"" + } + }, + { + "id": "google", + "name": "Google (GCP) Service Account", + "shortDescription": { + "text": "\"type\": \"service_account\"" + } + }, + { + "id": "heroku", + "name": "Heroku API key", + "shortDescription": { + "text": "(?i)heroku(.{0,20})?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + } + }, + { + "id": "mailchimp", + "name": "MailChimp API key", + "shortDescription": { + "text": "(?i)(mailchimp|mc)(.{0,20})?[0-9a-f]{32}-us[0-9]{1,2}" + } + }, + { + "id": "mailgun", + "name": "Mailgun API key", + "shortDescription": { + "text": "((?i)(mailgun|mg)(.{0,20})?)?key-[0-9a-z]{32}" + } + }, + { + "id": "paypal", + "name": "PayPal Braintree access token", + "shortDescription": { + "text": "access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}" + } + }, + { + "id": "piacatic", + "name": "Picatic API key", + "shortDescription": { + "text": "sk_live_[0-9a-z]{32}" + } + }, + { + "id": "sendgrid", + "name": "SendGrid API Key", + "shortDescription": { + "text": "SG\\.[\\w_]{16,32}\\.[\\w_]{16,64}" + } + }, + { + "id": "sidekiq-secret", + "name": "Sidekiq Secret", + "shortDescription": { + "text": "(?i)(?:BUNDLE_ENTERPRISE__CONTRIBSYS__COM|BUNDLE_GEMS__CONTRIBSYS__COM)(?:[0-9a-z\\-_\\t .]{0,20})(?:[\\s|']|[\\s|\"]){0,3}(?:=|\u003e|:=|\\|\\|:|\u003c=|=\u003e|:)(?:'|\\\"|\\s|=|\\x60){0,5}([a-f0-9]{8}:[a-f0-9]{8})(?:['|\\\"|\\n|\\r|\\s|\\x60|;]|$)" + } + }, + { + "id": "sidekiq-sensitive-url", + "name": "Sidekiq Sensitive URL", + "shortDescription": { + "text": "(?i)\\b(http(?:s??):\\/\\/)([a-f0-9]{8}:[a-f0-9]{8})@(?:gems.contribsys.com|enterprise.contribsys.com)(?:[\\/|\\#|\\?|:]|$)" + } + }, + { + "id": "slack-webhook", + "name": "Slack Webhook", + "shortDescription": { + "text": "https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8,12}/[a-zA-Z0-9_]{24}" + } + }, + { + "id": "stripe", + "name": "Stripe API key", + "shortDescription": { + "text": "(?i)stripe(.{0,20})?[sr]k_live_[0-9a-zA-Z]{24}" + } + }, + { + "id": "square", + "name": "Square access token", + "shortDescription": { + "text": "sq0atp-[0-9A-Za-z\\-_]{22}" + } + }, + { + "id": "square-oauth", + "name": "Square OAuth secret", + "shortDescription": { + "text": "sq0csp-[0-9A-Za-z\\-_]{43}" + } + }, + { + "id": "twilio", + "name": "Twilio API key", + "shortDescription": { + "text": "(?i)twilio(.{0,20})?SK[0-9a-f]{32}" + } + }, + { + "id": "dynatrace", + "name": "Dynatrace ttoken", + "shortDescription": { + "text": "dt0[a-zA-Z]{1}[0-9]{2}\\.[A-Z0-9]{24}\\.[A-Z0-9]{64}" + } + }, + { + "id": "shopify", + "name": "Shopify shared secret", + "shortDescription": { + "text": "shpss_[a-fA-F0-9]{32}" + } + }, + { + "id": "shopify-access", + "name": "Shopify access token", + "shortDescription": { + "text": "shpat_[a-fA-F0-9]{32}" + } + }, + { + "id": "shopify-custom", + "name": "Shopify custom app access token", + "shortDescription": { + "text": "shpca_[a-fA-F0-9]{32}" + } + }, + { + "id": "shopify-private", + "name": "Shopify private app access token", + "shortDescription": { + "text": "shppa_[a-fA-F0-9]{32}" + } + }, + { + "id": "pypi", + "name": "PyPI upload token", + "shortDescription": { + "text": "pypi-AgEIcHlwaS5vcmc[A-Za-z0-9-_]{50,1000}" + } + } + ] + } + }, + "results": [ + { + "message": { + "text": "test-rule has detected secret for file auth.py at commit 0000000000000000." + }, + "ruleId": "test-rule", + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "auth.py" + }, + "region": { + "startLine": 1, + "startColumn": 1, + "endLine": 2, + "endColumn": 2, + "snippet": { + "text": "a secret" + } + } + } + } + ], + "partialFingerprints": { + "commitSha": "0000000000000000", + "email": "johndoe@gmail.com", + "author": "John Doe", + "date": "10-19-2003", + "commitMessage": "opps" + } + } + ] + } + ] +} diff --git a/cli/testdata/expected/report/sarif_simple.sarif b/cli/testdata/expected/report/sarif_simple.sarif new file mode 100644 index 000000000..0b1b15f70 --- /dev/null +++ b/cli/testdata/expected/report/sarif_simple.sarif @@ -0,0 +1,302 @@ +{ + "$schema": "https://json.schemastore.org/sarif-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "gitleaks", + "semanticVersion": "v8.0.0", + "informationUri": "https://github.com/gitleaks/gitleaks", + "rules": [ + { + "id": "aws-access-key", + "name": "AWS Access Key", + "shortDescription": { + "text": "(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}" + } + }, + { + "id": "aws-secret-key", + "name": "AWS Secret Key", + "shortDescription": { + "text": "(?i)aws_(.{0,20})?=?.[\\'\\\"0-9a-zA-Z\\/+]{40}" + } + }, + { + "id": "aws-mws-key", + "name": "AWS MWS key", + "shortDescription": { + "text": "amzn\\.mws\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + } + }, + { + "id": "facebook-secret-key", + "name": "Facebook Secret Key", + "shortDescription": { + "text": "(?i)(facebook|fb)(.{0,20})?(?-i)['\\\"][0-9a-f]{32}['\\\"]" + } + }, + { + "id": "facebook-client-id", + "name": "Facebook Client ID", + "shortDescription": { + "text": "(?i)(facebook|fb)(.{0,20})?['\\\"][0-9]{13,17}['\\\"]" + } + }, + { + "id": "twitter-secret-key", + "name": "Twitter Secret Key", + "shortDescription": { + "text": "(?i)twitter(.{0,20})?['\\\"][0-9a-z]{35,44}['\\\"]" + } + }, + { + "id": "twitter-client-id", + "name": "Twitter Client ID", + "shortDescription": { + "text": "(?i)twitter(.{0,20})?['\\\"][0-9a-z]{18,25}['\\\"]" + } + }, + { + "id": "github-pat", + "name": "Github Personal Access Token", + "shortDescription": { + "text": "ghp_[0-9a-zA-Z]{36}" + } + }, + { + "id": "github-oauth", + "name": "Github OAuth Access Token", + "shortDescription": { + "text": "gho_[0-9a-zA-Z]{36}" + } + }, + { + "id": "github-app", + "name": "Github App Token", + "shortDescription": { + "text": "(ghu|ghs)_[0-9a-zA-Z]{36}" + } + }, + { + "id": "github-refresh", + "name": "Github Refresh Token", + "shortDescription": { + "text": "ghr_[0-9a-zA-Z]{76}" + } + }, + { + "id": "linkedin-client", + "name": "LinkedIn Client ID", + "shortDescription": { + "text": "(?i)linkedin(.{0,20})?(?-i)[0-9a-z]{12}" + } + }, + { + "id": "linkedin-secret", + "name": "LinkedIn Secret Key", + "shortDescription": { + "text": "(?i)linkedin(.{0,20})?[0-9a-z]{16}" + } + }, + { + "id": "slack", + "name": "Slack", + "shortDescription": { + "text": "xox[baprs]-([0-9a-zA-Z]{10,48})?" + } + }, + { + "id": "apkey", + "name": "Asymmetric Private Key", + "shortDescription": { + "text": "-----BEGIN ((EC|PGP|DSA|RSA|OPENSSH) )?PRIVATE KEY( BLOCK)?-----" + } + }, + { + "id": "google", + "name": "Google (GCP) Service Account", + "shortDescription": { + "text": "\"type\": \"service_account\"" + } + }, + { + "id": "google", + "name": "Google (GCP) Service Account", + "shortDescription": { + "text": "\"type\": \"service_account\"" + } + }, + { + "id": "heroku", + "name": "Heroku API key", + "shortDescription": { + "text": "(?i)heroku(.{0,20})?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + } + }, + { + "id": "mailchimp", + "name": "MailChimp API key", + "shortDescription": { + "text": "(?i)(mailchimp|mc)(.{0,20})?[0-9a-f]{32}-us[0-9]{1,2}" + } + }, + { + "id": "mailgun", + "name": "Mailgun API key", + "shortDescription": { + "text": "((?i)(mailgun|mg)(.{0,20})?)?key-[0-9a-z]{32}" + } + }, + { + "id": "paypal", + "name": "PayPal Braintree access token", + "shortDescription": { + "text": "access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}" + } + }, + { + "id": "piacatic", + "name": "Picatic API key", + "shortDescription": { + "text": "sk_live_[0-9a-z]{32}" + } + }, + { + "id": "sendgrid", + "name": "SendGrid API Key", + "shortDescription": { + "text": "SG\\.[\\w_]{16,32}\\.[\\w_]{16,64}" + } + }, + { + "id": "sidekiq-secret", + "name": "Sidekiq Secret", + "shortDescription": { + "text": "(?i)(?:BUNDLE_ENTERPRISE__CONTRIBSYS__COM|BUNDLE_GEMS__CONTRIBSYS__COM)(?:[0-9a-z\\-_\\t .]{0,20})(?:[\\s|']|[\\s|\"]){0,3}(?:=|\u003e|:=|\\|\\|:|\u003c=|=\u003e|:)(?:'|\\\"|\\s|=|\\x60){0,5}([a-f0-9]{8}:[a-f0-9]{8})(?:['|\\\"|\\n|\\r|\\s|\\x60|;]|$)" + } + }, + { + "id": "sidekiq-sensitive-url", + "name": "Sidekiq Sensitive URL", + "shortDescription": { + "text": "(?i)\\b(http(?:s??):\\/\\/)([a-f0-9]{8}:[a-f0-9]{8})@(?:gems.contribsys.com|enterprise.contribsys.com)(?:[\\/|\\#|\\?|:]|$)" + } + }, + { + "id": "slack-webhook", + "name": "Slack Webhook", + "shortDescription": { + "text": "https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8,12}/[a-zA-Z0-9_]{24}" + } + }, + { + "id": "stripe", + "name": "Stripe API key", + "shortDescription": { + "text": "(?i)stripe(.{0,20})?[sr]k_live_[0-9a-zA-Z]{24}" + } + }, + { + "id": "square", + "name": "Square access token", + "shortDescription": { + "text": "sq0atp-[0-9A-Za-z\\-_]{22}" + } + }, + { + "id": "square-oauth", + "name": "Square OAuth secret", + "shortDescription": { + "text": "sq0csp-[0-9A-Za-z\\-_]{43}" + } + }, + { + "id": "twilio", + "name": "Twilio API key", + "shortDescription": { + "text": "(?i)twilio(.{0,20})?SK[0-9a-f]{32}" + } + }, + { + "id": "dynatrace", + "name": "Dynatrace ttoken", + "shortDescription": { + "text": "dt0[a-zA-Z]{1}[0-9]{2}\\.[A-Z0-9]{24}\\.[A-Z0-9]{64}" + } + }, + { + "id": "shopify", + "name": "Shopify shared secret", + "shortDescription": { + "text": "shpss_[a-fA-F0-9]{32}" + } + }, + { + "id": "shopify-access", + "name": "Shopify access token", + "shortDescription": { + "text": "shpat_[a-fA-F0-9]{32}" + } + }, + { + "id": "shopify-custom", + "name": "Shopify custom app access token", + "shortDescription": { + "text": "shpca_[a-fA-F0-9]{32}" + } + }, + { + "id": "shopify-private", + "name": "Shopify private app access token", + "shortDescription": { + "text": "shppa_[a-fA-F0-9]{32}" + } + }, + { + "id": "pypi", + "name": "PyPI upload token", + "shortDescription": { + "text": "pypi-AgEIcHlwaS5vcmc[A-Za-z0-9-_]{50,1000}" + } + } + ] + } + }, + "results": [ + { + "message": { + "text": "test-rule has detected secret for file auth.py at commit 0000000000000000." + }, + "ruleId": "test-rule", + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "auth.py" + }, + "region": { + "startLine": 1, + "startColumn": 1, + "endLine": 2, + "endColumn": 2, + "snippet": { + "text": "a secret" + } + } + } + } + ], + "partialFingerprints": { + "commitSha": "0000000000000000", + "email": "johndoe@gmail.com", + "author": "John Doe", + "date": "10-19-2003", + "commitMessage": "opps" + } + } + ] + } + ] +} diff --git a/cli/testdata/repos/nogit/main.go b/cli/testdata/repos/nogit/main.go new file mode 100644 index 000000000..acbef43fd --- /dev/null +++ b/cli/testdata/repos/nogit/main.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +func main() { + + var a = "initial" + fmt.Println(a) + + var b, c int = 1, 2 + fmt.Println(b, c) + + var d = true + fmt.Println(d) + + var e int + fmt.Println(e) + + // opps I added a secret at line 20 + awsToken := "AKIALALEMEL33243OLIA" + + f := "apple" + fmt.Println(f) +} diff --git a/cli/testdata/repos/small/README.md b/cli/testdata/repos/small/README.md new file mode 100644 index 000000000..5cc9baf4d --- /dev/null +++ b/cli/testdata/repos/small/README.md @@ -0,0 +1,2 @@ +# test +This is a repo used for testing gitleaks diff --git a/cli/testdata/repos/small/api/api.go b/cli/testdata/repos/small/api/api.go new file mode 100644 index 000000000..d83247911 --- /dev/null +++ b/cli/testdata/repos/small/api/api.go @@ -0,0 +1,7 @@ +package api + +import "fmt" + +func PrintHello() { + fmt.Println("hello") +} diff --git a/cli/testdata/repos/small/dotGit/COMMIT_EDITMSG b/cli/testdata/repos/small/dotGit/COMMIT_EDITMSG new file mode 100644 index 000000000..0ba1543fd --- /dev/null +++ b/cli/testdata/repos/small/dotGit/COMMIT_EDITMSG @@ -0,0 +1 @@ +removing secret from foo package diff --git a/cli/testdata/repos/small/dotGit/FETCH_HEAD b/cli/testdata/repos/small/dotGit/FETCH_HEAD new file mode 100644 index 000000000..66c1c77ce --- /dev/null +++ b/cli/testdata/repos/small/dotGit/FETCH_HEAD @@ -0,0 +1 @@ +2e1db472eeba53f06c4026ae4566ea022e36598e branch 'main' of github.com:gitleaks/test diff --git a/cli/testdata/repos/small/dotGit/HEAD b/cli/testdata/repos/small/dotGit/HEAD new file mode 100644 index 000000000..b870d8262 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/cli/testdata/repos/small/dotGit/ORIG_HEAD b/cli/testdata/repos/small/dotGit/ORIG_HEAD new file mode 100644 index 000000000..96321ccd4 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/ORIG_HEAD @@ -0,0 +1 @@ +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 diff --git a/cli/testdata/repos/small/dotGit/config b/cli/testdata/repos/small/dotGit/config new file mode 100644 index 000000000..374df60b1 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/config @@ -0,0 +1,13 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = git@github.com:gitleaks/test.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "main"] + remote = origin + merge = refs/heads/main diff --git a/cli/testdata/repos/small/dotGit/description b/cli/testdata/repos/small/dotGit/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/cli/testdata/repos/small/dotGit/index b/cli/testdata/repos/small/dotGit/index new file mode 100644 index 000000000..fec9889ae Binary files /dev/null and b/cli/testdata/repos/small/dotGit/index differ diff --git a/cli/testdata/repos/small/dotGit/info/exclude b/cli/testdata/repos/small/dotGit/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/cli/testdata/repos/small/dotGit/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/cli/testdata/repos/small/dotGit/logs/HEAD b/cli/testdata/repos/small/dotGit/logs/HEAD new file mode 100644 index 000000000..8fc59bb3b --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/HEAD @@ -0,0 +1,13 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 checkout: moving from main to remove-secrets +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var +906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package +a122b33c6bad3ee54724f52f2caad385ab1982ab a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 checkout: moving from remove-secrets to api-pkg +a122b33c6bad3ee54724f52f2caad385ab1982ab 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896644 -0500 checkout: moving from api-pkg to main +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward +2e1db472eeba53f06c4026ae4566ea022e36598e 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 checkout: moving from main to foo +2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret +491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package +f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897009 -0500 checkout: moving from foo to main +2e1db472eeba53f06c4026ae4566ea022e36598e f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635897062 -0500 checkout: moving from main to foo +f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897508 -0500 checkout: moving from foo to main diff --git a/cli/testdata/repos/small/dotGit/logs/refs/heads/api-pkg b/cli/testdata/repos/small/dotGit/logs/refs/heads/api-pkg new file mode 100644 index 000000000..18e1cff1a --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/heads/api-pkg @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 branch: Created from HEAD diff --git a/cli/testdata/repos/small/dotGit/logs/refs/heads/foo b/cli/testdata/repos/small/dotGit/logs/refs/heads/foo new file mode 100644 index 000000000..0588ad530 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/heads/foo @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 branch: Created from HEAD +2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret +491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package diff --git a/cli/testdata/repos/small/dotGit/logs/refs/heads/main b/cli/testdata/repos/small/dotGit/logs/refs/heads/main new file mode 100644 index 000000000..50148f0e8 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/heads/main @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward diff --git a/cli/testdata/repos/small/dotGit/logs/refs/heads/remove-secrets b/cli/testdata/repos/small/dotGit/logs/refs/heads/remove-secrets new file mode 100644 index 000000000..58344a340 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/heads/remove-secrets @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 branch: Created from HEAD +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var +906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package diff --git a/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/HEAD b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/HEAD new file mode 100644 index 000000000..a2076e59a --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git diff --git a/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/api-pkg b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/api-pkg new file mode 100644 index 000000000..9c8e059cf --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/api-pkg @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896552 -0500 update by push diff --git a/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/foo b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/foo new file mode 100644 index 000000000..f6aed264f --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/foo @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896935 -0500 update by push diff --git a/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/main b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/main new file mode 100644 index 000000000..530a7894d --- /dev/null +++ b/cli/testdata/repos/small/dotGit/logs/refs/remotes/origin/main @@ -0,0 +1 @@ +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: fast-forward diff --git a/cli/testdata/repos/small/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760 b/cli/testdata/repos/small/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760 new file mode 100644 index 000000000..dab89999a --- /dev/null +++ b/cli/testdata/repos/small/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760 @@ -0,0 +1 @@ +xUÌ1 Â0`×ܯ8nJ––.‚ƒƒ:*(8–´\¤´ɕ$ê þw3 Noxï{Ý$6Ëf1Û~´wF'0øYbF ŠœÏTB�p�ÐãND|ƒ*]uŽCÈSÐT •…ªkLÌ>a²Ž#(ûJm–‘®Ö(©ÚsæðԴ¹]Úëé°=õ÷ô>ð°ú03 \ No newline at end of file diff --git a/cli/testdata/repos/small/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738 b/cli/testdata/repos/small/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738 new file mode 100644 index 000000000..f9ada0721 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738 differ diff --git a/cli/testdata/repos/small/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e b/cli/testdata/repos/small/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e new file mode 100644 index 000000000..5dd33dfc9 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e differ diff --git a/cli/testdata/repos/small/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca b/cli/testdata/repos/small/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca new file mode 100644 index 000000000..754d7397e Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca differ diff --git a/cli/testdata/repos/small/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112 b/cli/testdata/repos/small/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112 new file mode 100644 index 000000000..5bddb82e2 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112 differ diff --git a/cli/testdata/repos/small/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a b/cli/testdata/repos/small/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a new file mode 100644 index 000000000..93acde0f5 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a differ diff --git a/cli/testdata/repos/small/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73 b/cli/testdata/repos/small/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73 new file mode 100644 index 000000000..ce4a269d3 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73 @@ -0,0 +1,3 @@ +x�ŽM +Â0F]çs%™üt +"žÁ¥»I2¡E۔»ðôö ®>x¼_ªË2w@;œz㑈ءCŒXЧ@‘²Ö6 5�)–ÔÆMÖ&†ÌÎF:l'ÌFÇTHďFFÃ1–äiPüéSmðä4ÁcN×o;¦ݷV{]žߗT—˜`=�Áa€³öZ«ƒ»ü«wå ½¾d…}f�u‡�›úKKœ \ No newline at end of file diff --git a/cli/testdata/repos/small/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad b/cli/testdata/repos/small/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad new file mode 100644 index 000000000..5e51e39d4 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad differ diff --git a/cli/testdata/repos/small/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab b/cli/testdata/repos/small/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab new file mode 100644 index 000000000..fbcf357cc Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab differ diff --git a/cli/testdata/repos/small/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5 b/cli/testdata/repos/small/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5 new file mode 100644 index 000000000..8be258a32 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5 differ diff --git a/cli/testdata/repos/small/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a b/cli/testdata/repos/small/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a new file mode 100644 index 000000000..9221b3c0a Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a differ diff --git a/cli/testdata/repos/small/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886 b/cli/testdata/repos/small/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886 new file mode 100644 index 000000000..ec618b7a9 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886 differ diff --git a/cli/testdata/repos/small/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161 b/cli/testdata/repos/small/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161 new file mode 100644 index 000000000..0bd9a371a Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161 differ diff --git a/cli/testdata/repos/small/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78 b/cli/testdata/repos/small/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78 new file mode 100644 index 000000000..d4a8c3de9 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78 differ diff --git a/cli/testdata/repos/small/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb b/cli/testdata/repos/small/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb new file mode 100644 index 000000000..53b83ef00 Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb differ diff --git a/cli/testdata/repos/small/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901 b/cli/testdata/repos/small/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901 new file mode 100644 index 000000000..a7bf9018e Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901 differ diff --git a/cli/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx b/cli/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx new file mode 100644 index 000000000..3cdb2bd0f Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx differ diff --git a/cli/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack b/cli/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack new file mode 100644 index 000000000..975d3711a Binary files /dev/null and b/cli/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack differ diff --git a/cli/testdata/repos/small/dotGit/packed-refs b/cli/testdata/repos/small/dotGit/packed-refs new file mode 100644 index 000000000..859b8c5a8 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled sorted +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 refs/remotes/origin/main diff --git a/cli/testdata/repos/small/dotGit/refs/heads/api-pkg b/cli/testdata/repos/small/dotGit/refs/heads/api-pkg new file mode 100644 index 000000000..31b6c7893 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/heads/api-pkg @@ -0,0 +1 @@ +a122b33c6bad3ee54724f52f2caad385ab1982ab diff --git a/cli/testdata/repos/small/dotGit/refs/heads/foo b/cli/testdata/repos/small/dotGit/refs/heads/foo new file mode 100644 index 000000000..57d584841 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/heads/foo @@ -0,0 +1 @@ +f1b58b97808f8e744f6a23c693859df5b5968901 diff --git a/cli/testdata/repos/small/dotGit/refs/heads/main b/cli/testdata/repos/small/dotGit/refs/heads/main new file mode 100644 index 000000000..98f12e928 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/heads/main @@ -0,0 +1 @@ +2e1db472eeba53f06c4026ae4566ea022e36598e diff --git a/cli/testdata/repos/small/dotGit/refs/heads/remove-secrets b/cli/testdata/repos/small/dotGit/refs/heads/remove-secrets new file mode 100644 index 000000000..31b6c7893 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/heads/remove-secrets @@ -0,0 +1 @@ +a122b33c6bad3ee54724f52f2caad385ab1982ab diff --git a/cli/testdata/repos/small/dotGit/refs/remotes/origin/HEAD b/cli/testdata/repos/small/dotGit/refs/remotes/origin/HEAD new file mode 100644 index 000000000..4b0a87595 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/main diff --git a/cli/testdata/repos/small/dotGit/refs/remotes/origin/api-pkg b/cli/testdata/repos/small/dotGit/refs/remotes/origin/api-pkg new file mode 100644 index 000000000..31b6c7893 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/remotes/origin/api-pkg @@ -0,0 +1 @@ +a122b33c6bad3ee54724f52f2caad385ab1982ab diff --git a/cli/testdata/repos/small/dotGit/refs/remotes/origin/foo b/cli/testdata/repos/small/dotGit/refs/remotes/origin/foo new file mode 100644 index 000000000..57d584841 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/remotes/origin/foo @@ -0,0 +1 @@ +f1b58b97808f8e744f6a23c693859df5b5968901 diff --git a/cli/testdata/repos/small/dotGit/refs/remotes/origin/main b/cli/testdata/repos/small/dotGit/refs/remotes/origin/main new file mode 100644 index 000000000..98f12e928 --- /dev/null +++ b/cli/testdata/repos/small/dotGit/refs/remotes/origin/main @@ -0,0 +1 @@ +2e1db472eeba53f06c4026ae4566ea022e36598e diff --git a/cli/testdata/repos/small/main.go b/cli/testdata/repos/small/main.go new file mode 100644 index 000000000..9a932e37e --- /dev/null +++ b/cli/testdata/repos/small/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + + var a = "initial" + fmt.Println(a) + + var b, c int = 1, 2 + fmt.Println(b, c) + + var d = true + fmt.Println(d) + + var e int + fmt.Println(e) + + // load secret via env + awsToken := os.Getenv("AWS_TOKEN") + + f := "apple" + fmt.Println(f) +} diff --git a/cli/testdata/repos/staged/.gitleaksignore b/cli/testdata/repos/staged/.gitleaksignore new file mode 100644 index 000000000..770453ca4 --- /dev/null +++ b/cli/testdata/repos/staged/.gitleaksignore @@ -0,0 +1 @@ +api/api.go:aws-access-key:6 \ No newline at end of file diff --git a/cli/testdata/repos/staged/README.md b/cli/testdata/repos/staged/README.md new file mode 100644 index 000000000..5cc9baf4d --- /dev/null +++ b/cli/testdata/repos/staged/README.md @@ -0,0 +1,2 @@ +# test +This is a repo used for testing gitleaks diff --git a/cli/testdata/repos/staged/api/api.go b/cli/testdata/repos/staged/api/api.go new file mode 100644 index 000000000..b16d768dd --- /dev/null +++ b/cli/testdata/repos/staged/api/api.go @@ -0,0 +1,10 @@ +package api + +import "fmt" + +func PrintHello() { + aws_token := "AKIALALEMEL33243OLIA" // fingerprint of that secret is added to .gitleaksignore + aws_token2 := "AKIALALEMEL33243OLIA" // this one is not + fmt.Println(aws_token) + fmt.Println(aws_token2) +} diff --git a/cli/testdata/repos/staged/dotGit/COMMIT_EDITMSG b/cli/testdata/repos/staged/dotGit/COMMIT_EDITMSG new file mode 100644 index 000000000..b83ad5393 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/COMMIT_EDITMSG @@ -0,0 +1 @@ +add .gitleaksignore file diff --git a/cli/testdata/repos/staged/dotGit/FETCH_HEAD b/cli/testdata/repos/staged/dotGit/FETCH_HEAD new file mode 100644 index 000000000..66c1c77ce --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/FETCH_HEAD @@ -0,0 +1 @@ +2e1db472eeba53f06c4026ae4566ea022e36598e branch 'main' of github.com:gitleaks/test diff --git a/cli/testdata/repos/staged/dotGit/HEAD b/cli/testdata/repos/staged/dotGit/HEAD new file mode 100644 index 000000000..b870d8262 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/cli/testdata/repos/staged/dotGit/ORIG_HEAD b/cli/testdata/repos/staged/dotGit/ORIG_HEAD new file mode 100644 index 000000000..96321ccd4 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/ORIG_HEAD @@ -0,0 +1 @@ +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 diff --git a/cli/testdata/repos/staged/dotGit/config b/cli/testdata/repos/staged/dotGit/config new file mode 100644 index 000000000..374df60b1 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/config @@ -0,0 +1,13 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = git@github.com:gitleaks/test.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "main"] + remote = origin + merge = refs/heads/main diff --git a/cli/testdata/repos/staged/dotGit/description b/cli/testdata/repos/staged/dotGit/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/cli/testdata/repos/staged/dotGit/index b/cli/testdata/repos/staged/dotGit/index new file mode 100644 index 000000000..42a3c4433 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/index differ diff --git a/cli/testdata/repos/staged/dotGit/info/exclude b/cli/testdata/repos/staged/dotGit/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/cli/testdata/repos/staged/dotGit/logs/HEAD b/cli/testdata/repos/staged/dotGit/logs/HEAD new file mode 100644 index 000000000..928095a13 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/HEAD @@ -0,0 +1,14 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 checkout: moving from main to remove-secrets +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var +906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package +a122b33c6bad3ee54724f52f2caad385ab1982ab a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 checkout: moving from remove-secrets to api-pkg +a122b33c6bad3ee54724f52f2caad385ab1982ab 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896644 -0500 checkout: moving from api-pkg to main +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward +2e1db472eeba53f06c4026ae4566ea022e36598e 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 checkout: moving from main to foo +2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret +491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package +f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897009 -0500 checkout: moving from foo to main +2e1db472eeba53f06c4026ae4566ea022e36598e f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635897062 -0500 checkout: moving from main to foo +f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897508 -0500 checkout: moving from foo to main +2e1db472eeba53f06c4026ae4566ea022e36598e bf3f24164d7256b4021575cbdb2f97b98e6f057e Rafael Figueiredo 1679239434 -0300 commit: add .gitleaksignore file diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/heads/api-pkg b/cli/testdata/repos/staged/dotGit/logs/refs/heads/api-pkg new file mode 100644 index 000000000..18e1cff1a --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/heads/api-pkg @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 branch: Created from HEAD diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/heads/foo b/cli/testdata/repos/staged/dotGit/logs/refs/heads/foo new file mode 100644 index 000000000..0588ad530 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/heads/foo @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 branch: Created from HEAD +2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret +491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/heads/main b/cli/testdata/repos/staged/dotGit/logs/refs/heads/main new file mode 100644 index 000000000..c4bd6cb68 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/heads/main @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward +2e1db472eeba53f06c4026ae4566ea022e36598e bf3f24164d7256b4021575cbdb2f97b98e6f057e Rafael Figueiredo 1679239434 -0300 commit: add .gitleaksignore file diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/heads/remove-secrets b/cli/testdata/repos/staged/dotGit/logs/refs/heads/remove-secrets new file mode 100644 index 000000000..58344a340 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/heads/remove-secrets @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 branch: Created from HEAD +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var +906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/HEAD b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/HEAD new file mode 100644 index 000000000..a2076e59a --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/api-pkg b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/api-pkg new file mode 100644 index 000000000..9c8e059cf --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/api-pkg @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896552 -0500 update by push diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/foo b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/foo new file mode 100644 index 000000000..f6aed264f --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/foo @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896935 -0500 update by push diff --git a/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/main b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/main new file mode 100644 index 000000000..530a7894d --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/logs/refs/remotes/origin/main @@ -0,0 +1 @@ +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: fast-forward diff --git a/cli/testdata/repos/staged/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760 b/cli/testdata/repos/staged/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760 new file mode 100644 index 000000000..dab89999a --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760 @@ -0,0 +1 @@ +xUÌ1 Â0`×ܯ8nJ––.‚ƒƒ:*(8–´\¤´ɕ$ê þw3 Noxï{Ý$6Ëf1Û~´wF'0øYbF ŠœÏTB�p�ÐãND|ƒ*]uŽCÈSÐT •…ªkLÌ>a²Ž#(ûJm–‘®Ö(©ÚsæðԴ¹]Úëé°=õ÷ô>ð°ú03 \ No newline at end of file diff --git a/cli/testdata/repos/staged/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738 b/cli/testdata/repos/staged/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738 new file mode 100644 index 000000000..f9ada0721 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e b/cli/testdata/repos/staged/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e new file mode 100644 index 000000000..5dd33dfc9 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e differ diff --git a/cli/testdata/repos/staged/dotGit/objects/46/18d7e4512b6b0b1dab85cf846d9f43474ec8be b/cli/testdata/repos/staged/dotGit/objects/46/18d7e4512b6b0b1dab85cf846d9f43474ec8be new file mode 100644 index 000000000..92ce09d28 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/46/18d7e4512b6b0b1dab85cf846d9f43474ec8be differ diff --git a/cli/testdata/repos/staged/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca b/cli/testdata/repos/staged/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca new file mode 100644 index 000000000..754d7397e Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca differ diff --git a/cli/testdata/repos/staged/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112 b/cli/testdata/repos/staged/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112 new file mode 100644 index 000000000..5bddb82e2 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/65/83d6db4a57bbeda62d50fc91649036d499418d b/cli/testdata/repos/staged/dotGit/objects/65/83d6db4a57bbeda62d50fc91649036d499418d new file mode 100644 index 000000000..b6fec1e0b Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/65/83d6db4a57bbeda62d50fc91649036d499418d differ diff --git a/cli/testdata/repos/staged/dotGit/objects/66/bc70d0c0bfbb6468b3f90c3f1e9f2ddba02b43 b/cli/testdata/repos/staged/dotGit/objects/66/bc70d0c0bfbb6468b3f90c3f1e9f2ddba02b43 new file mode 100644 index 000000000..f6622df7e Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/66/bc70d0c0bfbb6468b3f90c3f1e9f2ddba02b43 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a b/cli/testdata/repos/staged/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a new file mode 100644 index 000000000..93acde0f5 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a differ diff --git a/cli/testdata/repos/staged/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73 b/cli/testdata/repos/staged/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73 new file mode 100644 index 000000000..ce4a269d3 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73 @@ -0,0 +1,3 @@ +x�ŽM +Â0F]çs%™üt +"žÁ¥»I2¡E۔»ðôö ®>x¼_ªË2w@;œz㑈ءCŒXЧ@‘²Ö6 5�)–ÔÆMÖ&†ÌÎF:l'ÌFÇTHďFFÃ1–äiPüéSmðä4ÁcN×o;¦ݷV{]žߗT—˜`=�Áa€³öZ«ƒ»ü«wå ½¾d…}f�u‡�›úKKœ \ No newline at end of file diff --git a/cli/testdata/repos/staged/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad b/cli/testdata/repos/staged/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad new file mode 100644 index 000000000..5e51e39d4 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad differ diff --git a/cli/testdata/repos/staged/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab b/cli/testdata/repos/staged/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab new file mode 100644 index 000000000..fbcf357cc Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab differ diff --git a/cli/testdata/repos/staged/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5 b/cli/testdata/repos/staged/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5 new file mode 100644 index 000000000..8be258a32 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a b/cli/testdata/repos/staged/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a new file mode 100644 index 000000000..9221b3c0a Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a differ diff --git a/cli/testdata/repos/staged/dotGit/objects/b1/6d768dd595a59f947abe087901183d219d7e54 b/cli/testdata/repos/staged/dotGit/objects/b1/6d768dd595a59f947abe087901183d219d7e54 new file mode 100644 index 000000000..6ba6deaf0 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/b1/6d768dd595a59f947abe087901183d219d7e54 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886 b/cli/testdata/repos/staged/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886 new file mode 100644 index 000000000..ec618b7a9 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/bf/3f24164d7256b4021575cbdb2f97b98e6f057e b/cli/testdata/repos/staged/dotGit/objects/bf/3f24164d7256b4021575cbdb2f97b98e6f057e new file mode 100644 index 000000000..897417b68 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/objects/bf/3f24164d7256b4021575cbdb2f97b98e6f057e @@ -0,0 +1,2 @@ +x¥ŽAn!sæó�X³ÀÎɲ|Êòƒš5ÊÚX˜ý¬ò[ª*uj·[dçð1:@"1-œ9q,1Š—ct%preB(6ç¨l£wæ¡÷—ˆ)G¿X êì +KòlEág¼P 's8Âè>®­ӷÅF_uÝQ;r£S/ÿã²jozH[Ûó™&Y‚uÁ;OŸì˜Mú;;ðfÆhÎtXëؠ?ϺÞ[•ºÁü_]U \ No newline at end of file diff --git a/cli/testdata/repos/staged/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161 b/cli/testdata/repos/staged/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161 new file mode 100644 index 000000000..0bd9a371a Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78 b/cli/testdata/repos/staged/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78 new file mode 100644 index 000000000..d4a8c3de9 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb b/cli/testdata/repos/staged/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb new file mode 100644 index 000000000..53b83ef00 Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb differ diff --git a/cli/testdata/repos/staged/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901 b/cli/testdata/repos/staged/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901 new file mode 100644 index 000000000..a7bf9018e Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901 differ diff --git a/cli/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx b/cli/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx new file mode 100644 index 000000000..3cdb2bd0f Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx differ diff --git a/cli/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack b/cli/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack new file mode 100644 index 000000000..975d3711a Binary files /dev/null and b/cli/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack differ diff --git a/cli/testdata/repos/staged/dotGit/packed-refs b/cli/testdata/repos/staged/dotGit/packed-refs new file mode 100644 index 000000000..859b8c5a8 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled sorted +1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 refs/remotes/origin/main diff --git a/cli/testdata/repos/staged/dotGit/refs/heads/api-pkg b/cli/testdata/repos/staged/dotGit/refs/heads/api-pkg new file mode 100644 index 000000000..31b6c7893 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/heads/api-pkg @@ -0,0 +1 @@ +a122b33c6bad3ee54724f52f2caad385ab1982ab diff --git a/cli/testdata/repos/staged/dotGit/refs/heads/foo b/cli/testdata/repos/staged/dotGit/refs/heads/foo new file mode 100644 index 000000000..57d584841 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/heads/foo @@ -0,0 +1 @@ +f1b58b97808f8e744f6a23c693859df5b5968901 diff --git a/cli/testdata/repos/staged/dotGit/refs/heads/main b/cli/testdata/repos/staged/dotGit/refs/heads/main new file mode 100644 index 000000000..a06d4d30f --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/heads/main @@ -0,0 +1 @@ +bf3f24164d7256b4021575cbdb2f97b98e6f057e diff --git a/cli/testdata/repos/staged/dotGit/refs/heads/remove-secrets b/cli/testdata/repos/staged/dotGit/refs/heads/remove-secrets new file mode 100644 index 000000000..31b6c7893 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/heads/remove-secrets @@ -0,0 +1 @@ +a122b33c6bad3ee54724f52f2caad385ab1982ab diff --git a/cli/testdata/repos/staged/dotGit/refs/remotes/origin/HEAD b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/HEAD new file mode 100644 index 000000000..4b0a87595 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/main diff --git a/cli/testdata/repos/staged/dotGit/refs/remotes/origin/api-pkg b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/api-pkg new file mode 100644 index 000000000..31b6c7893 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/api-pkg @@ -0,0 +1 @@ +a122b33c6bad3ee54724f52f2caad385ab1982ab diff --git a/cli/testdata/repos/staged/dotGit/refs/remotes/origin/foo b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/foo new file mode 100644 index 000000000..57d584841 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/foo @@ -0,0 +1 @@ +f1b58b97808f8e744f6a23c693859df5b5968901 diff --git a/cli/testdata/repos/staged/dotGit/refs/remotes/origin/main b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/main new file mode 100644 index 000000000..98f12e928 --- /dev/null +++ b/cli/testdata/repos/staged/dotGit/refs/remotes/origin/main @@ -0,0 +1 @@ +2e1db472eeba53f06c4026ae4566ea022e36598e diff --git a/cli/testdata/repos/staged/main.go b/cli/testdata/repos/staged/main.go new file mode 100644 index 000000000..9a932e37e --- /dev/null +++ b/cli/testdata/repos/staged/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + + var a = "initial" + fmt.Println(a) + + var b, c int = 1, 2 + fmt.Println(b, c) + + var d = true + fmt.Println(d) + + var e int + fmt.Println(e) + + // load secret via env + awsToken := os.Getenv("AWS_TOKEN") + + f := "apple" + fmt.Println(f) +} diff --git a/cli/testdata/repos/symlinks/file_symlink/symlinked_id_ed25519 b/cli/testdata/repos/symlinks/file_symlink/symlinked_id_ed25519 new file mode 120000 index 000000000..fd0203d88 --- /dev/null +++ b/cli/testdata/repos/symlinks/file_symlink/symlinked_id_ed25519 @@ -0,0 +1 @@ +../source_file/id_ed25519 \ No newline at end of file diff --git a/cli/testdata/repos/symlinks/source_file/id_ed25519 b/cli/testdata/repos/symlinks/source_file/id_ed25519 new file mode 100644 index 000000000..9f4ff614b --- /dev/null +++ b/cli/testdata/repos/symlinks/source_file/id_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACA8YWKYztuuvxUIMomc3zv0OdXCT57Cc2cRYu3TMbX9XAAAAJDiKO3C4ijt +wgAAAAtzc2gtZWQyNTUxOQAAACA8YWKYztuuvxUIMomc3zv0OdXCT57Cc2cRYu3TMbX9XA +AAAECzmj8DGxg5YHtBK4AmBttMXDQHsPAaCyYHQjJ4YujRBTxhYpjO266/FQgyiZzfO/Q5 +1cJPnsJzZxFi7dMxtf1cAAAADHJvb3RAZGV2aG9zdAE= +-----END OPENSSH PRIVATE KEY----- diff --git a/cli/testdata/tmp/note.txt b/cli/testdata/tmp/note.txt new file mode 100644 index 000000000..429d60380 --- /dev/null +++ b/cli/testdata/tmp/note.txt @@ -0,0 +1 @@ +nothing should be saved here diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 287e80945..ad5a3ce02 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -37,6 +37,8 @@ services: - MONGO_URL=mongodb://root:example@mongo:27017/?authSource=admin networks: - infisical-dev + extra_hosts: + - "host.docker.internal:host-gateway" frontend: container_name: infisical-dev-frontend @@ -49,7 +51,6 @@ services: volumes: - ./frontend/src:/app/src/ # mounted whole src to avoid missing reload on new files - ./frontend/public:/app/public - - ./frontend/next-i18next.config.js:/app/next-i18next.config.js env_file: .env environment: - NEXT_PUBLIC_ENV=development diff --git a/docs/cli/commands/scan-git-changes.mdx b/docs/cli/commands/scan-git-changes.mdx new file mode 100644 index 000000000..d2a6c452c --- /dev/null +++ b/docs/cli/commands/scan-git-changes.mdx @@ -0,0 +1,104 @@ +--- +title: "scan git-changes" +description: "Scan for secrets in your uncommitted code" +--- + +```bash +infisical scan git-changes + +# Display the full secret findings +infisical scan git-changes --verbose +``` + +## Description +Scanning for secrets before you commit your changes is great way to prevent leaks. Infisical makes this easy with the sub command `git-changes`. + +The `git-changes` scans for uncommitted changes in a Git repository, and is especially designed for use on developer machines, aligning with the ['shift left'](https://cloud.google.com/architecture/devops/devops-tech-shifting-left-on-security) security approach. +When `git-changes` is run on a Git repository, Infisical parses the output from a `git diff` command. + +To scan changes in commits that have been staged via `git add`, you can add the `--staged` flag to the sub command. This flag is particularly useful when using Infisical CLI as a pre-commit tool. + +### Flags + + **Description** + + detect secrets in a --staged state + + Default value: `false` + + + + **Description** + + git log options + + + + Short hand: `-b` + + **Description** + + path to baseline with issues that can be ignored + + + + Short hand: `-c` + + **Description** + + config file path + + order of precedence: + 1. --config flag + 2. env var INFISICAL_SCAN_CONFIG + 3. (--source/-s)/.infisical-scan.toml + If none of the three options are used, then Infisical will use the default config + + + + **Description** + + exit code when leaks have been encountered (default 1) + + + + **Description** + + files larger than this will be skipped + + + + **Description** + + turn off color for verbose output + + + + **Description** + + redact secrets from logs and stdout + + + + **Description** + + output format (json, csv, sarif) (default "json") + + + + **Description** + + report file + + + + **Description** + + path to source (default ".") + + + + **Description** + + show verbose output from scan + diff --git a/docs/cli/commands/scan-install.mdx b/docs/cli/commands/scan-install.mdx new file mode 100644 index 000000000..a0128ef18 --- /dev/null +++ b/docs/cli/commands/scan-install.mdx @@ -0,0 +1,23 @@ +--- +title: "scan install" +description: "Add various scanning tools seamlessly into your development lifecycle" +--- + +```bash +infisical scan install --pre-commit-hook +``` + +## Description +The command `infisical scan install` is designed to incorporate various scanning tools seamlessly into your development lifecycle. +Initially, we are offering users the ability to install a pre-commit hook. This hook conducts an automatic scan for any exposed secrets in your commits before they are pushed. + +### Flags + + ```bash + infisical scan install --pre-commit-hook + ``` + + **Description** + Installs a git pre-commit hook that triggers Infisical to scan your staged changes for any exposed secrets prior to pushing. + + \ No newline at end of file diff --git a/docs/cli/commands/scan.mdx b/docs/cli/commands/scan.mdx new file mode 100644 index 000000000..3de69dd58 --- /dev/null +++ b/docs/cli/commands/scan.mdx @@ -0,0 +1,126 @@ +--- +title: "scan" +description: "Scan git history, directories, and files for secrets" +--- + +```bash +infisical scan + +# Display the full secret findings +infisical scan --verbose +``` + +## Description +The `infisical scan` command serves to scan repositories, directories, and files. It's compatible with both individual developer machines and Continuous Integration (CI) environments. + +When you run `infisical scan` on a Git repository, Infisical will parses the output of a `git log -p` command. This command generates [patches](https://stackoverflow.com/questions/8279602/what-is-a-patch-in-git-version-control) that Infisical uses to identify secrets in your code. +You can configure the range of commits that `git log` will cover using the `--log-opts` flag. +Any options you can use with `git log -p` are valid for `--log-opts`. + +For instance, to instruct Infisical to scan a specific range of commits, use the following command: `infisical scan --log-opts="--all commitA..commitB"`. For more details, refer to the [Git log documentation](https://git-scm.com/docs/git-log). + +To scan individual files and directories, use the `--no-git` flag. + +### Flags + + **Description** + + git log options + + + + **Description** + + treat git repo as a regular directory and scan those files, --log-opts has no effect on the scan when --no-git is set + + Default value: `false` + + + + Short hand: `-b` + + **Description** + + scan input from stdin, ex: `cat some_file | infisical scan --pipe` + + Default value: `false` + + + + Short hand: `-b` + + **Description** + scan files that are symlinks to other files + + Default value: `false` + + + + Short hand: `-b` + + **Description** + + path to baseline with issues that can be ignored + + + + Short hand: `-c` + + **Description** + + config file path + + order of precedence: + 1. --config flag + 2. env var INFISICAL_SCAN_CONFIG + 3. (--source/-s)/.infisical-scan.toml + If none of the three options are used, then Infisical will use the default config + + + + **Description** + + exit code when leaks have been encountered (default 1) + + + + **Description** + + files larger than this will be skipped + + + + **Description** + + turn off color for verbose output + + + + **Description** + + redact secrets from logs and stdout + + + + **Description** + + output format (json, csv, sarif) (default "json") + + + + **Description** + + report file + + + + **Description** + + path to source (default ".") + + + + **Description** + + show verbose output from scan + diff --git a/docs/cli/scanning-overview.mdx b/docs/cli/scanning-overview.mdx new file mode 100644 index 000000000..5fb65a54b --- /dev/null +++ b/docs/cli/scanning-overview.mdx @@ -0,0 +1,245 @@ +--- +title: 'Secret scanning' +description: "Scan and prevent secret leaks in your code base" +--- + +Building upon its core functionality of fetching and injecting secrets into your applications, Infisical now takes a significant step forward in bolstering your code security. +We've enhanced our CLI tool to include a powerful scanning feature, capable of identifying more than 140 different types of secret leaks in your codebase. +In addition to scanning for past leaks, this new addition also actively aids in preventing future leaks. + +# Scanning + + + ```bash + infisical scan + + # Display the full secret findings + infisical scan --verbose + ``` + + The `infisical scan` command serves to scan repositories, directories, and files. It's compatible with both individual developer machines and Continuous Integration (CI) environments. + + When you run `infisical scan` on a Git repository, Infisical will parses the output of a `git log -p` command. This command generates [patches](https://stackoverflow.com/questions/8279602/what-is-a-patch-in-git-version-control) that Infisical uses to identify secrets in your code. + You can configure the range of commits that `git log` will cover using the `--log-opts` flag. + Any options you can use with `git log -p` are valid for `--log-opts`. + + For instance, to instruct Infisical to scan a specific range of commits, use the following command: `infisical scan --log-opts="--all commitA..commitB"`. For more details, refer to the [Git log documentation](https://git-scm.com/docs/git-log). + + To scan individual files and directories, use the `--no-git` flag. + + **View [full details for this command](./commands/scan)** + + + ```bash + infisical scan git-changes + + # Display the full secret findings + infisical git-changes --verbose + ``` + + Scanning for secrets before you commit your changes is great way to prevent leaks. Infisical makes this easy with the sub command `git-changes`. + + The `git-changes` scans for uncommitted changes in a Git repository, and is especially designed for use on developer machines, aligning with the ['shift left'](https://cloud.google.com/architecture/devops/devops-tech-shifting-left-on-security) security approach. + When `git-changes` is run on a Git repository, Infisical parses the output from a `git diff` command. + + To scan changes in commits that have been staged via `git add`, you can add the `--staged` flag to the sub command. This flag is particularly useful when using Infisical CLI as a pre-commit tool. + + **View [full details for this command](./commands/scan-git-changes)** + ​ + + `git-changes` command is only for Git repositories; using it on files or directories will result in an error. + + + + +# +# +# Automatically scan changes before you commit + +To lower the risk of committing hardcoded secrets to your code repository, we have designed a custom git pre-commit hook. +This hook scans the changes you're about to commit for any exposed secrets. If any hardcoded secrets are detected, it will block your commit. + +### Install pre-commit hook + +To install this git hook, go into your local git repository and run the following command. + +```bash +infisical scan install --pre-commit-hook +``` + +To disable this hook after installing it, run the command `git config --bool hooks.infisical-scan false` + +### Third party hooks management +If you would rather handle your pre-commit hook outside of the standard `.git/hooks` directory, you can quickly achieve this by adding the following command into your pre-commit script. +For instance, if you utilize [Husky](https://typicode.github.io/husky/) for managing your Git hooks, you can insert the command provided below into your `.husky/pre-commit` file. + +```bash +infisical scan git-changes --staged --verbose +``` + +# +# +# Creating a baseline + +When scanning large repositories or repositories with a long history, it can be helpful to use a baseline. + +A baseline allows Infisical to ignore any old findings that are already present in the baseline findings. You can create a infisical scan report by running `infisical scan` with the `--report-path` flag. + +To create a Infisical scan report and save it in a file called leaks-report.json, use the following command: + +``` +infisical scan --report-path leaks-report.json +``` + +Once a baseline is created, you can apply it when running the `infisical scan` command again. Use the following command: + +``` +infisical scan --baseline-path leaks-report.json --report-path findings.json +``` + +After running the `scan` command with the `--baseline-path` flag, the report output in findings.json will only contain new issues. + +# +# +# Configuration file + +To customize the scan, such as specifying your own rules or establishing exceptions for certain files or paths that should not be flagged as risks, you can define these specifications in the configuration file. + + +```toml infisical-scan.toml +# Title for the configuration file +title = "Some title" + + +# This configuration is the foundation that can be expanded. If there are any overlapping rules +# between this base and the expanded configuration, the rules in this base will take priority. +# Another aspect of extending configurations is the ability to link multiple files, up to a depth of 2. +# "Allowlist" arrays get appended and may have repeated elements. +# "useDefault" and "path" cannot be used simultaneously. Please choose one. +[extend] +# useDefault will extend the base configuration with the default config: +# https://raw.githubusercontent.com/Infisical/infisical/main/cli/config/infisical-scan.toml +useDefault = true +# or you can supply a path to a configuration. Path is relative to where infisical cli +# was invoked, not the location of the base config. +path = "common_config.toml" + +# An array of tables that contain information that define instructions +# on how to detect secrets +[[rules]] + +# Unique identifier for this rule +id = "some-identifier-for-rule" + +# Short human readable description of the rule. +description = "awesome rule 1" + +# Golang regular expression used to detect secrets. Note Golang's regex engine +# does not support lookaheads. +regex = '''one-go-style-regex-for-this-rule''' + +# Golang regular expression used to match paths. This can be used as a standalone rule or it can be used +# in conjunction with a valid `regex` entry. +path = '''a-file-path-regex''' + +# Array of strings used for metadata and reporting purposes. +tags = ["tag","another tag"] + +# A regex match may have many groups, this allows you to specify the group that should be used as (which group the secret is contained in) +# its entropy checked if `entropy` is set. +secretGroup = 3 + +# Float representing the minimum shannon entropy a regex group must have to be considered a secret. +# Shannon entropy measures how random a data is. Since secrets are usually composed of many random characters, they typically have high entropy +entropy = 3.5 + +# Keywords are used for pre-regex check filtering. +# If rule has keywords but the text fragment being scanned doesn't have at least one of it's keywords, it will be skipped for processing further. +# Ideally these values should either be part of the idenitifer or unique strings specific to the rule's regex +# (introduced in v8.6.0) +keywords = [ + "auth", + "password", + "token", +] + +# You can include an allowlist table for a single rule to reduce false positives or ignore commits +# with known/rotated secrets +[rules.allowlist] +description = "ignore commit A" +commits = [ "commit-A", "commit-B"] +paths = [ + '''go\.mod''', + '''go\.sum''' +] +# note: (rule) regexTarget defaults to check the _Secret_ in the finding. +# if regexTarget is not specified then _Secret_ will be used. +# Acceptable values for regexTarget are "match" and "line" +regexTarget = "match" +regexes = [ + '''process''', + '''getenv''', +] +# note: stopwords targets the extracted secret, not the entire regex match +# if the extracted secret is found in the stopwords list, the finding will be skipped (i.e not included in report) +stopwords = [ + '''client''', + '''endpoint''', +] + + +# This is a global allowlist which has a higher order of precedence than rule-specific allowlists. +# If a commit listed in the `commits` field below is encountered then that commit will be skipped and no +# secrets will be detected for said commit. The same logic applies for regexes and paths. +[allowlist] +description = "global allow list" +commits = [ "commit-A", "commit-B", "commit-C"] +paths = [ + '''gitleaks\.toml''', + '''(.*?)(jpg|gif|doc)''' +] + +# note: (global) regexTarget defaults to check the _Secret_ in the finding. +# if regexTarget is not specified then _Secret_ will be used. +# Acceptable values for regexTarget are "match" and "line" +regexTarget = "match" + +regexes = [ + '''219-09-9999''', + '''078-05-1120''', + '''(9[0-9]{2}|666)-\d{2}-\d{4}''', +] +# note: stopwords targets the extracted secret, not the entire regex match +# if the extracted secret is found in the stopwords list, the finding will be skipped (i.e not included in report) +stopwords = [ + '''client''', + '''endpoint''', +] +``` + + +# +# +# Ignoring Known Secrets +If you're intentionally committing a test secret that `infisical scan` might flag, you can instruct Infisical to overlook that secret with the methods listed below. + +### infisical-scan:ignore + +To ignore a secret contained in line of code, simply add `infisical-scan:ignore ` at the end of the line as comment in the given programming. + +```js example.js +function helloWorld() { + console.log("8dyfuiRyq=vVc3RRr_edRk-fK__JItpZ"); // infisical-scan:ignore +} +``` + +### .infisicalignore +An alternative method to exclude specific findings involves creating a .infisicalignore file at your repository's root. +You can then add the fingerprints of the findings you wish to exclude. The Infisical scan report provides a unique Fingerprint for each secret found. +By incorporating these Fingerprints into the .infisicalignore file, Infisical will skip the corresponding secret findings in subsequent scans. + +```.ignore .infisicalignore +bea0ff6e05a4de73a5db625d4ae181a015b50855:frontend/components/utilities/attemptLogin.js:stripe-access-token:147 +bea0ff6e05a4de73a5db625d4ae181a015b50855:backend/src/json/integrations.json:generic-api-key:5 +1961b92340e5d2613acae528b886c842427ce5d0:frontend/components/utilities/attemptLogin.js:stripe-access-token:148 +``` \ No newline at end of file diff --git a/docs/cli/usage.mdx b/docs/cli/usage.mdx index 0e8c5fce9..f6e06c966 100644 --- a/docs/cli/usage.mdx +++ b/docs/cli/usage.mdx @@ -34,10 +34,29 @@ infisical init ## Inject environment variables -```bash -# inject environment variables into app -infisical run -- [your application start command] -``` + + ```bash + # inject environment variables into app + infisical run -- [your application start command] + ``` + + + + Custom aliases can utilize secrets from Infisical. Suppose there is a custom alias `yd` in `custom.sh` that runs `yarn dev` and needs the secrets provided by Infisical. + ```bash + #!/bin/sh + + yd() { + yarn dev + } + ``` + + To make the secrets available from Infisical to `yd`, you can run the following command: + + ```bash + infisical run --command="source custom.sh && yd" + ``` + View all available options for `run` command [here](./commands/run) diff --git a/docs/documentation/getting-started/introduction.mdx b/docs/documentation/getting-started/introduction.mdx index 92e773fcd..37bd5bd63 100644 --- a/docs/documentation/getting-started/introduction.mdx +++ b/docs/documentation/getting-started/introduction.mdx @@ -79,6 +79,13 @@ Start syncing environment variables with [Infisical Cloud](https://app.infisical > Explore integrations for Next.js, Express, Django, and more + + Scan and prevent 140+ secret type leaks in your codebase + + +**Step 2:** Click the plus icon + + + +**Step 3:** Select Shell Script + + + +**Step 4:** Choose Script Text and then paste in the command below. + + + +``` +infisical run -- ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005" +``` + +**Step 5:** When you need to run a block of code in debug mode, select the Infisical script + + + + + + + diff --git a/docs/mint.json b/docs/mint.json index 9e982881f..a0612889d 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -123,9 +123,9 @@ "self-hosting/deployment-options/kubernetes-helm", "self-hosting/deployment-options/aws-ec2", "self-hosting/deployment-options/docker-compose", + "self-hosting/deployment-options/standalone-infisical", "self-hosting/deployment-options/fly.io", "self-hosting/deployment-options/render", - "self-hosting/deployment-options/standalone-infisical", "self-hosting/deployment-options/digital-ocean-marketplace" ] }, @@ -140,7 +140,7 @@ "cli/overview", "cli/usage", { - "group": "Commands", + "group": "Core commands", "pages": [ "cli/commands/login", "cli/commands/init", @@ -149,9 +149,18 @@ "cli/commands/export", "cli/commands/vault", "cli/commands/user", - "cli/commands/reset" + "cli/commands/reset", + { + "group": "infisical scan", + "pages": [ + "cli/commands/scan", + "cli/commands/scan-git-changes", + "cli/commands/scan-install" + ] + } ] }, + "cli/scanning-overview", "cli/project-config", "cli/faq" ] @@ -188,6 +197,7 @@ "integrations/cicd/gitlab", "integrations/cicd/circleci", "integrations/cicd/travisci", + "integrations/frameworks/spring-boot-maven", "integrations/frameworks/react", "integrations/frameworks/vue", "integrations/frameworks/express", diff --git a/docs/self-hosting/deployment-options/docker-compose.mdx b/docs/self-hosting/deployment-options/docker-compose.mdx index ca2219344..979c1ec47 100644 --- a/docs/self-hosting/deployment-options/docker-compose.mdx +++ b/docs/self-hosting/deployment-options/docker-compose.mdx @@ -3,7 +3,7 @@ title: "Docker Compose" description: "Learn to install Infisical using our Docker Compose template" --- -1. Install Docker on your VM +## Install Docker on your VM ```bash # Example in ubuntu @@ -12,7 +12,7 @@ apt-get upgrade apt install docker-compose ``` -2. Download the required files +## Download the required files ```bash # Download env file template @@ -25,18 +25,23 @@ wget -O docker-compose.yml https://raw.githubusercontent.com/Infisical/infisical mkdir nginx && wget -O ./nginx/default.conf https://raw.githubusercontent.com/Infisical/infisical/main/nginx/default.dev.conf ``` -3. Tweak the `.env` according to your preferences. Refer to the available [environment variables](/self-hosting/configuration/envars) +## Update .env file +Tweak the `.env` according to your preferences. Refer to the available [environment variables](/self-hosting/configuration/envars) ```bash # update environment variables like mongo login nano .env ``` -4. Get the service up and running. + + Infisical assumes that you have configured HTTPS. If you didn't configure HTTPS, set `HTTPS_ENABLED` to `false` in the .env file to avoid frequent logouts. + + +## Get the service up and running. ```bash # Start up services in detached mode docker-compose -f docker-compose.yml up -d ``` -5. Your Infisical installation is complete and should be running on [http://localhost:80](http://localhost:80). Please note that the containers are not exposed to the internet and only bind to the localhost. It's up to you to configure a firewall, SSL certificates, and implement any additional security measures. +Your Infisical installation is complete and should be running on [http://localhost:80](http://localhost:80). Please note that the containers are not exposed to the internet and only bind to the localhost. It's up to you to configure a firewall, SSL certificates, and implement any additional security measures. diff --git a/docs/self-hosting/deployment-options/kubernetes-helm.mdx b/docs/self-hosting/deployment-options/kubernetes-helm.mdx index 30e637807..f523ec6a4 100644 --- a/docs/self-hosting/deployment-options/kubernetes-helm.mdx +++ b/docs/self-hosting/deployment-options/kubernetes-helm.mdx @@ -1,16 +1,22 @@ --- title: "Kubernetes via Helm Chart" description: "Use our Helm chart to Install Infisical on your Kubernetes cluster" ---- - - +--- **Prerequisites** - You have understanding of [Kubernetes](https://kubernetes.io/) - Installed [Helm package manager](https://helm.sh/) version v3.11.3 or greater - You have [kubectl](https://kubernetes.io/docs/reference/kubectl/kubectl/) installed and connected to your kubernetes cluster + + -#### 1. Install Infisical Helm repository +By deploying Infisical on Kubernetes, you can take advantage of its features to ensure that the application is fault-tolerant, highly available, and scalable. +To make the installation process easier and more streamlined, we have created a Helm chart that you can use to install Infisical on Kubernetes. + +Helm is a package manager for Kubernetes that simplifies the installation and management of Kubernetes applications. +With our Helm chart, you can easily install Infisical on Kubernetes, configure it to your liking, and scale it up or down as needed. + +## Install Infisical Helm repository ```bash helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/' @@ -18,18 +24,193 @@ helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/h helm repo update ``` -#### 2. Install the Helm chart +## Add Helm values + +Create a values.yaml file to configure various installation settings, such as the docker image tags and environment variables for both the frontend and backend. To explore all configurable properties for your values file, [visit this page](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical). + +#### Set image tags + +By default, the application will use the latest tag to retrieve the required Docker images, which may be appropriate for most cases. +However, it's important to specify a particular version of Infisical during installation to prevent any significant updates from disrupting your deployment. +View [properties for frontend and backend](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical#parameters). + + +To determine the appropriate versions to use for the docker images, follow the links bellow +- [frontend Docker image](https://hub.docker.com/r/infisical/frontend/tags) +- [backend Docker image](https://hub.docker.com/r/infisical/backend/tags) + +```yaml simple-values-example.yaml +frontend: + name: frontend + replicaCount: 2 + image: + repository: infisical/frontend + tag: "v0.1.3" + pullPolicy: Always + +backend: + replicaCount: 2 + image: + repository: infisical/backend + tag: "v0.1.3" + pullPolicy: Always +``` + +#### Configure environment variables + +You can configure environment variables for the frontend and backend in your Helm values file under the property `frontendEnvironmentVariables` and `backendEnvironmentVariables` respectively. View configurable [environment variables](../configuration/envars). + +Infisical requires the following backend environment variables to be defined: _`ENCRYPTION_KEY`_, _`JWT_SIGNUP_SECRET`_, _`JWT_REFRESH_SECRET`_, _`JWT_AUTH_SECRET`_, _`JWT_MFA_SECRET`_ and _`JWT_SERVICE_SECRET`_. + + +Each of the above environment variables can be generated by running the command `openssl rand -hex 16` in your terminal. + + +However, when the above environment variables are not defined, the Helm chart +will automatically generate these environment variables for you. The generated environment variables will be saved to a Kubernetes secret and will be preserved between upgrades or uninstalls. + +```yaml simple-values-example.yaml +... +backendEnvironmentVariables: + HTTPS_ENABLED: true + INVITE_ONLY_SIGNUP: false + ... +``` + + + Infisical assumes that you have configured HTTPS. If you didn't configure HTTPS, set `HTTPS_ENABLED` to `false` in the backend environment variable to avoid frequent logouts. + + +#### Routing external traffic +By default, Infisical takes all traffic coming to your external load balancer's IP address and routes them Infisical's services. +Infisical uses Nginx to route external traffic. You can install Nginx along with Infisical by setting `ingress.enabled` to `true` in the Helm values file. View all [properties for ingress](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical). + +```yaml simple-values-example.yaml +... +ingress: + nginx: + enabled: false #<-- if you would like to install nginx along with Infisical +``` + +#### Database +Infisical uses a document database as its persistence layer. With this Helm chart, you spin up a MongoDB instance power by Bitnami along side other Infisical services in your cluster. +When persistence is enabled, the data will be stored a Kubernetes Persistence Volume. View all [properties for mongodb](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical). + +```yaml simple-values-example.yaml +mongodb: + enabled: false + persistence: + enabled: false +``` + +To increase data redundancy, we recommend that you use a managed document database service such as AWS Document DB, MongoDB or similar services instead. +Managed database connection string can be set in the `backendEnvironmentVariables`. + +#### Example helm values +```yaml simple-values-example.yaml +frontend: + name: frontend + replicaCount: 2 + image: + repository: infisical/frontend + tag: "v0.1.3" + pullPolicy: Always + +backend: + replicaCount: 2 + image: + repository: infisical/backend + tag: "v0.1.3" + pullPolicy: Always + +backendEnvironmentVariables: + HTTPS_ENABLED: true + +ingress: + nginx: + enabled: false #<-- if you would like to install nginx along with Infisical + +``` + + + ```yaml values.yaml + ingress: + nginx: + enabled: true + + frontend: + enabled: true + name: frontend + podAnnotations: {} + deploymentAnnotations: {} + replicaCount: 4 + image: + repository: infisical/frontend + tag: "v0.1.3" + pullPolicy: IfNotPresent + kubeSecretRef: null + service: + annotations: {} + type: ClusterIP + nodePort: "" + + backend: + enabled: true + name: backend + podAnnotations: {} + deploymentAnnotations: {} + replicaCount: 4 + image: + repository: infisical/backend + tag: "v0.1.3" + pullPolicy: IfNotPresent + kubeSecretRef: null + service: + annotations: {} + type: ClusterIP + nodePort: "" + + # View all environment variables https://infisical.com/docs/self-hosting/configuration/envars + backendEnvironmentVariables: + MONGO_URL: <> + HTTPS_ENABLED: <> + + + ## Mongo DB persistence + mongodb: + enabled: false + persistence: + enabled: false + + ingress: + enabled: true + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" # <-- if you are setting up HTTPS + hostName: app.infisical.com ## <- Replace with your own domain + frontend: + path: / + pathType: Prefix + backend: + path: /api + pathType: Prefix + tls: # <-- if you are setting up HTTPS + - secretName: echo-tls + hosts: + - app.infisical.com + + ``` + + +## Install the Helm chart By default, the helm chart will be installed on your default namespace. If you wish to install the Chart on a different namespace, you may specify that by adding the `--namespace ` to your `helm install` command. ```bash ## Installs to default namespace -helm install infisical-helm-charts/infisical --generate-name +helm install infisical-helm-charts/infisical --generate-name --values /path/to/values.yaml ``` -#### 3. Access Infisical +## Access Infisical Allow 3-5 minutes for the deployment to complete. Once done, you should now be able to access Infisical on the IP address exposed via Ingress on your load balancer. If you are not sure what the IP address is run `kubectl get ingress` to view the external IP address exposing Infisical. - -#### Custom configuration -To configure environment variables, database and deployments, you'll need to set the parameters in a `values.yaml` file. To view all available parameters [visit here](https://github.com/Infisical/infisical/tree/main/helm-charts/infisical#parameters) + \ No newline at end of file diff --git a/docs/self-hosting/deployment-options/standalone-infisical.mdx b/docs/self-hosting/deployment-options/standalone-infisical.mdx index b338c708a..8974ae4e6 100644 --- a/docs/self-hosting/deployment-options/standalone-infisical.mdx +++ b/docs/self-hosting/deployment-options/standalone-infisical.mdx @@ -3,4 +3,76 @@ title: "Docker" description: "Learn to install Infisical purely on docker" --- -Documentation coming soon \ No newline at end of file +The Infisical standalone version combines all the essential components of the application into a single container, making deployment and management more straightforward than using Kubernetes or Docker Compose. + +Since all the components are bundled into one image, running this version of Infisical requires a minimum of **230MB of memory**. + +This guide assumes you have basic knowledge of Docker and have it installed on your system. If you don't have Docker installed, please follow the official installation guide: https://docs.docker.com/get-docker/ + +## Pull the Infisical Docker image + +Open your terminal or command prompt and enter the following command to pull the Infisical Docker image: + +``` +docker pull infisical/infisical:latest +``` + +## Create a .env file +The Infisical Docker image requires a .env file to manage environment variables. +Create a new file called .env in your preferred location. Add the required environment variables listed below. View [all configurable environment variables](../configuration/envars) + + + + Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` + + + + Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` + + + + Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` + + + + Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` + + + + Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` + + + + Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` + + + + *TLS based connection string is not yet supported + + + +```env .example-env +ENCRYPTION_KEY=f40c9178624764ad85a6830b37ce239a +JWT_SIGNUP_SECRET=38ea90fb7998b92176080f457d890392 +JWT_REFRESH_SECRET=7764c7bbf3928ad501591a3e005eb364 +JWT_AUTH_SECRET=5239fea3a4720c0e524f814a540e14a2 +JWT_SERVICE_SECRET=8509fb8b90c9b53e9e61d1e35826dcb5 +MONGO_URL=<> +``` + + + The sample environment variables listed above are only to be used as an example and should not be used in production + + +## Run the Infisical Docker container: + +In the terminal or command prompt, navigate to the directory containing the .env file you created. Run the following command to start the Infisical Docker container: + +``` +docker run --name infisical-app --env-file ./.env -p 80:80 infisical/infisical:latest +``` + +This command will create a new container named infisical-app using the Infisical Docker image. It will also load the environment variables from the .env file and map the container's port 80 to the host's port 80. + +## Verify the installation: +Once the container is running, open a web browser and navigate to http://localhost:80. That's it! You have successfully installed the Infisical application using a single Docker image. \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md index d97bb4bef..a0bcd1ef0 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -8,7 +8,7 @@ Please ensure you have Docker and Docker Compose installed for your OS. - `CD` into the repo - run command `docker-compose -f docker-compose.dev.yml up --build --force-recreate` -- Visit localhost:3000 and the website should be live +- Visit localhost:8080 and the website should be live ### Steps to shutdown this Docker compose diff --git a/frontend/next-i18next.config.js b/frontend/next-i18next.config.js deleted file mode 100644 index e8046b755..000000000 --- a/frontend/next-i18next.config.js +++ /dev/null @@ -1,26 +0,0 @@ -// @ts-check - -/** - * @type {import('next-i18next').UserConfig} - */ -module.exports = { - // https://www.i18next.com/overview/configuration-options#logging - debug: false, - i18n: { - defaultLocale: "en", - locales: ["en", "ko", "fr", "pt-BR", "pt-PT", "es"], - }, - fallbackLng: { - default: ["en"], - }, - - reloadOnPrerender: process.env.NODE_ENV === "development", - - /** - * @link https://github.com/i18next/next-i18next#6-advanced-configuration - */ - // saveMissing: false, - // strictMode: true, - // serializeConfig: false, - // react: { useSuspense: false } -}; \ No newline at end of file diff --git a/frontend/next.config.js b/frontend/next.config.js index 5e7c81270..dbe69eb1d 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -1,10 +1,8 @@ - // @ts-check /** * @type {import('next').NextConfig} **/ -const { i18n } = require("./next-i18next.config.js"); const path = require('path'); const ContentSecurityPolicy = ` @@ -23,62 +21,67 @@ const ContentSecurityPolicy = ` // after learning more below. const securityHeaders = [ { - key: "X-DNS-Prefetch-Control", - value: "on", + key: 'X-DNS-Prefetch-Control', + value: 'on' }, { - key: "Strict-Transport-Security", - value: "max-age=63072000; includeSubDomains; preload", + key: 'Strict-Transport-Security', + value: 'max-age=63072000; includeSubDomains; preload' }, { - key: "X-XSS-Protection", - value: "1; mode=block", + key: 'X-XSS-Protection', + value: '1; mode=block' }, { - key: "X-Frame-Options", - value: "SAMEORIGIN", + key: 'X-Frame-Options', + value: 'SAMEORIGIN' }, { - key: "Permissions-Policy", - value: "camera=(), microphone=()", + key: 'Permissions-Policy', + value: 'camera=(), microphone=()' }, { - key: "X-Content-Type-Options", - value: "nosniff", + key: 'X-Content-Type-Options', + value: 'nosniff' }, { - key: "Referrer-Policy", - value: "strict-origin-when-cross-origin", + key: 'Referrer-Policy', + value: 'strict-origin-when-cross-origin' }, { - key: "Content-Security-Policy", - value: ContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(), - }, + key: 'Content-Security-Policy', + value: ContentSecurityPolicy.replace(/\s{2,}/g, ' ').trim() + } ]; module.exports = { - output: "standalone", + output: 'standalone', + i18n: { + locales: ['en', 'ko', 'fr', 'pt-BR', 'pt-PT', 'es'], + defaultLocale: 'en' + }, async headers() { return [ { // Apply these headers to all routes in your application. - source: "/:path*", - headers: securityHeaders, - }, + source: '/:path*', + headers: securityHeaders + } ]; }, - webpack: (config, { isServer, webpack }) => { // config + webpack: (config, { isServer, webpack }) => { + // config config.module.rules.push({ test: /\.wasm$/, - loader: "base64-loader", - type: "javascript/auto", + loader: 'base64-loader', + type: 'javascript/auto' }); config.module.noParse = /\.wasm$/; config.module.rules.forEach((rule) => { (rule.oneOf || []).forEach((oneOf) => { - if (oneOf.loader && oneOf.loader.indexOf("file-loader") >= 0) { + if (oneOf.loader && oneOf.loader.indexOf('file-loader') >= 0) { oneOf.exclude.push(/\.wasm$/); } }); @@ -89,12 +92,9 @@ module.exports = { } // Perform customizations to webpack config - config.plugins.push( - new webpack.IgnorePlugin({ resourceRegExp: /\/__tests__\// }) - ); + config.plugins.push(new webpack.IgnorePlugin({ resourceRegExp: /\/__tests__\// })); // Important: return the modified config return config; - }, - i18n, + } }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e53e988df..3a04a38a5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,5 +1,5 @@ { - "name": "npm-proj-1682714499482-0.7355675708334568i1ac8K", + "name": "npm-proj-1684411062139-0.5362546945149991xa7WAK", "lockfileVersion": 2, "requires": true, "packages": { @@ -12,7 +12,7 @@ "@fortawesome/free-brands-svg-icons": "^6.1.2", "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.2", - "@fortawesome/react-fontawesome": "^0.1.19", + "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^1.7.7", "@hookform/resolvers": "^2.9.10", "@octokit/rest": "^19.0.7", @@ -45,18 +45,19 @@ "cookies": "^0.8.0", "cva": "npm:class-variance-authority@^0.4.0", "framer-motion": "^6.2.3", - "fs": "^0.0.1-security", + "fs": "^0.0.2", "gray-matter": "^4.0.3", "http-proxy": "^1.18.1", - "i18next": "^22.4.9", + "i18next": "^22.4.15", + "i18next-browser-languagedetector": "^7.0.1", + "i18next-http-backend": "^2.2.0", "infisical-node": "^1.0.37", "jspdf": "^2.5.1", "jsrp": "^0.2.4", "lottie-react": "^2.4.0", "markdown-it": "^13.0.1", "next": "^12.3.4", - "next-i18next": "^13.0.2", - "posthog-js": "^1.39.4", + "posthog-js": "^1.54.0", "query-string": "^7.1.3", "react": "^17.0.2", "react-beautiful-dnd": "^13.1.1", @@ -64,7 +65,7 @@ "react-dom": "^17.0.2", "react-grid-layout": "^1.3.4", "react-hook-form": "^7.43.0", - "react-i18next": "^12.1.1", + "react-i18next": "^12.2.2", "react-mailchimp-subscribe": "^2.1.3", "react-markdown": "^8.0.3", "react-redux": "^8.0.2", @@ -2804,15 +2805,15 @@ } }, "node_modules/@fortawesome/react-fontawesome": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", - "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~1 || ~6", - "react": ">=16.x" + "react": ">=16.3" } }, "node_modules/@headlessui/react": { @@ -10017,6 +10018,7 @@ "version": "3.30.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz", "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==", + "devOptional": true, "hasInstallScript": true, "funding": { "type": "opencollective", @@ -10094,6 +10096,33 @@ "dev": true, "peer": true }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -12738,9 +12767,9 @@ } }, "node_modules/fs": { - "version": "0.0.1-security", - "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", - "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz", + "integrity": "sha512-YAiVokMCrSIFZiroB1oz51hPiPRVcUtSa4x2U5RYXyhS9VAPdiFigKbPTnOSq7XY8wd3FIVPYmXpo5lMzFmxgg==" }, "node_modules/fs-constants": { "version": "1.0.0", @@ -13644,10 +13673,21 @@ "@babel/runtime": "^7.20.6" } }, - "node_modules/i18next-fs-backend": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz", - "integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA==" + "node_modules/i18next-browser-languagedetector": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz", + "integrity": "sha512-Pa5kFwaczXJAeHE56CHG2aWzFBMJNUNghf0Pm4SwSrEMps/PTKqW90EYWlIvhuYStf3Sn1K0vw+gH3+TLdkH1g==", + "dependencies": { + "@babel/runtime": "^7.19.4" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.2.0.tgz", + "integrity": "sha512-Z4sM7R6tzdLknSPER9GisEBxKPg5FkI07UrQniuroZmS15PHQrcCPLyuGKj8SS68tf+O2aEDYSUnmy1TZqZSbw==", + "dependencies": { + "cross-fetch": "3.1.5" + } }, "node_modules/iconv-lite": { "version": "0.4.24", @@ -16262,41 +16302,6 @@ } } }, - "node_modules/next-i18next": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-13.2.2.tgz", - "integrity": "sha512-t0WU6K+HJoq2nVQ0n6OiiEZja9GyMqtDSU74FmOafgk4ljns+iZ18bsNJiI8rOUXfFfkW96ea1N7D5kbMyT+PA==", - "funding": [ - { - "type": "individual", - "url": "https://locize.com/i18next.html" - }, - { - "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" - }, - { - "type": "individual", - "url": "https://locize.com" - } - ], - "dependencies": { - "@babel/runtime": "^7.20.13", - "@types/hoist-non-react-statics": "^3.3.1", - "core-js": "^3", - "hoist-non-react-statics": "^3.3.2", - "i18next-fs-backend": "^2.1.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "i18next": "^22.0.6", - "next": ">= 12.0.0", - "react": ">= 17.0.2", - "react-i18next": "^12.2.0" - } - }, "node_modules/next/node_modules/postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -17455,9 +17460,9 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/posthog-js": { - "version": "1.53.4", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.53.4.tgz", - "integrity": "sha512-aaQ9S+/eDuBl2XTuU/lMyMtX7eeNAQ/+53O0O+I05FwX7e5NDN1nVqlnkMP0pfZlFcnsPaVqm8N3HoYj+b7Eow==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.54.0.tgz", + "integrity": "sha512-5kT9zvmBrCshFkWqOrYxk13Y/2j7vtV0sF3XmQa5QDD0bVM1KGU4blyZySBt8SAcO1z3WsKvG4bFGxS7TPqjjw==", "dependencies": { "fflate": "^0.4.1", "rrweb-snapshot": "^1.1.14" @@ -23995,9 +24000,9 @@ } }, "@fortawesome/react-fontawesome": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", - "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", "requires": { "prop-types": "^15.8.1" } @@ -29322,7 +29327,8 @@ "core-js": { "version": "3.30.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz", - "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==" + "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==", + "devOptional": true }, "core-js-compat": { "version": "3.30.1", @@ -29382,6 +29388,24 @@ "dev": true, "peer": true }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -31412,9 +31436,9 @@ "dev": true }, "fs": { - "version": "0.0.1-security", - "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", - "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz", + "integrity": "sha512-YAiVokMCrSIFZiroB1oz51hPiPRVcUtSa4x2U5RYXyhS9VAPdiFigKbPTnOSq7XY8wd3FIVPYmXpo5lMzFmxgg==" }, "fs-constants": { "version": "1.0.0", @@ -32098,10 +32122,21 @@ "@babel/runtime": "^7.20.6" } }, - "i18next-fs-backend": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz", - "integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA==" + "i18next-browser-languagedetector": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz", + "integrity": "sha512-Pa5kFwaczXJAeHE56CHG2aWzFBMJNUNghf0Pm4SwSrEMps/PTKqW90EYWlIvhuYStf3Sn1K0vw+gH3+TLdkH1g==", + "requires": { + "@babel/runtime": "^7.19.4" + } + }, + "i18next-http-backend": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.2.0.tgz", + "integrity": "sha512-Z4sM7R6tzdLknSPER9GisEBxKPg5FkI07UrQniuroZmS15PHQrcCPLyuGKj8SS68tf+O2aEDYSUnmy1TZqZSbw==", + "requires": { + "cross-fetch": "3.1.5" + } }, "iconv-lite": { "version": "0.4.24", @@ -33950,18 +33985,6 @@ } } }, - "next-i18next": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-13.2.2.tgz", - "integrity": "sha512-t0WU6K+HJoq2nVQ0n6OiiEZja9GyMqtDSU74FmOafgk4ljns+iZ18bsNJiI8rOUXfFfkW96ea1N7D5kbMyT+PA==", - "requires": { - "@babel/runtime": "^7.20.13", - "@types/hoist-non-react-statics": "^3.3.1", - "core-js": "^3", - "hoist-non-react-statics": "^3.3.2", - "i18next-fs-backend": "^2.1.1" - } - }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -34799,9 +34822,9 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "posthog-js": { - "version": "1.53.4", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.53.4.tgz", - "integrity": "sha512-aaQ9S+/eDuBl2XTuU/lMyMtX7eeNAQ/+53O0O+I05FwX7e5NDN1nVqlnkMP0pfZlFcnsPaVqm8N3HoYj+b7Eow==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.54.0.tgz", + "integrity": "sha512-5kT9zvmBrCshFkWqOrYxk13Y/2j7vtV0sF3XmQa5QDD0bVM1KGU4blyZySBt8SAcO1z3WsKvG4bFGxS7TPqjjw==", "requires": { "fflate": "^0.4.1", "rrweb-snapshot": "^1.1.14" diff --git a/frontend/package.json b/frontend/package.json index 9414bc0b1..babf3c50d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,7 +19,7 @@ "@fortawesome/free-brands-svg-icons": "^6.1.2", "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.2", - "@fortawesome/react-fontawesome": "^0.1.19", + "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^1.7.7", "@hookform/resolvers": "^2.9.10", "@octokit/rest": "^19.0.7", @@ -52,18 +52,19 @@ "cookies": "^0.8.0", "cva": "npm:class-variance-authority@^0.4.0", "framer-motion": "^6.2.3", - "fs": "^0.0.1-security", + "fs": "^0.0.2", "gray-matter": "^4.0.3", "http-proxy": "^1.18.1", - "i18next": "^22.4.9", + "i18next": "^22.4.15", + "i18next-browser-languagedetector": "^7.0.1", + "i18next-http-backend": "^2.2.0", "infisical-node": "^1.0.37", "jspdf": "^2.5.1", "jsrp": "^0.2.4", "lottie-react": "^2.4.0", "markdown-it": "^13.0.1", "next": "^12.3.4", - "next-i18next": "^13.0.2", - "posthog-js": "^1.39.4", + "posthog-js": "^1.54.0", "query-string": "^7.1.3", "react": "^17.0.2", "react-beautiful-dnd": "^13.1.1", @@ -71,7 +72,7 @@ "react-dom": "^17.0.2", "react-grid-layout": "^1.3.4", "react-hook-form": "^7.43.0", - "react-i18next": "^12.1.1", + "react-i18next": "^12.2.2", "react-mailchimp-subscribe": "^2.1.3", "react-markdown": "^8.0.3", "react-redux": "^8.0.2", diff --git a/frontend/public/locales/en/activity.json b/frontend/public/locales/en/activity.json deleted file mode 100644 index 4db29f274..000000000 --- a/frontend/public/locales/en/activity.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "Audit Logs", - "subtitle": "Event history for this Infisical project.", - "event": { - "readSecrets": "Secrets Viewed", - "updateSecrets": "Secrets Updated", - "addSecrets": "Secrets Added", - "deleteSecrets": "Secrets Deleted" - }, - "ip-address": "IP Address" -} diff --git a/frontend/public/locales/en/billing.json b/frontend/public/locales/en/billing.json deleted file mode 100644 index 20c43c0a3..000000000 --- a/frontend/public/locales/en/billing.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Usage & Billing", - "description": "View and manage your organization's subscription here", - "subscription": "Subscription", - "starter": { - "name": "Starter", - "price-explanation": "up to 5 team members", - "text": "Manage any project with 5 members for free!", - "subtext": "$5 per member/month afterwards." - }, - "professional": { - "name": "Professional", - "price-explanation": "/member/month", - "subtext": "Includes unlimited projects & members.", - "text": "Keep up with key management as you grow." - }, - "enterprise": { - "name": "Enterprise", - "text": "Keep up with key management as you grow." - }, - "current-usage": "Current Usage", - "free": "Free", - "downgrade": "Downgrade", - "upgrade": "Upgrade", - "learn-more": "Learn More", - "custom-pricing": "Custom Pricing", - "schedule-demo": "Schedule a Demo" -} diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json deleted file mode 100644 index 4c966f09c..000000000 --- a/frontend/public/locales/en/common.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "head-title": "{{title}} | Infisical", - "error_project-already-exists": "A project with this name already exists.", - "no-mobile": " To use Infisical, please log in through a device with larger dimensions. ", - "email": "Email", - "password": "Password", - "first-name": "First Name", - "last-name": "Last Name", - "logout": "Log Out", - "validate-required": "Please input your {{name}}", - "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", - "click-to-copy": "Click to copy", - "project-id": "Project ID", - "save-changes": "Save Changes", - "saved": "Saved", - "drop-zone": "Drag and drop a .env, .json, or .yml file here.", - "drop-zone-keys": "Drag and drop a .env, .json, or .yml file here to add more secrets.", - "role": "Role", - "role_admin": "admin", - "display-name": "Display Name", - "environment": "Environment", - "expired-in": "Expires in", - "language": "Language", - "search": "Search...", - "note": "Note", - "view-more": "View More", - "end-of-history": "End of History", - "select-event": "Select an event", - "event": "Event", - "user": "User", - "source": "Source", - "time": "Time", - "timestamp": "Timestamp" -} \ No newline at end of file diff --git a/frontend/public/locales/en/dashboard.json b/frontend/public/locales/en/dashboard.json deleted file mode 100644 index 263887360..000000000 --- a/frontend/public/locales/en/dashboard.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "title": "Secrets", - "og-title": "Manage your .env files in seconds", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", - "search-keys": "Search keys...", - "add-key": "Add Key", - "personal": "Personal", - "personal-description": "Personal keys are only visible to you", - "shared": "Shared", - "shared-description": "Shared keys are visible to your whole team", - "make-shared": "Make Shared", - "make-personal": "Make Personal", - "add-secret": "Add a new secret", - "check-docs": { - "button": "Check Docs", - "title": "Good job!", - "line1": "Congrats on adding more secrets.", - "line2": "Here is how to connect them to your codebase." - }, - "sidebar": { - "secret": "Secret", - "key": "Key", - "value": "Value", - "override": "Override value with a personal value", - "version-history": "Version History", - "comments": "Comments & Notes", - "personal-explanation": "This secret is personal. It is not shared with any of your teammates.", - "generate-random-hex": "Generate Random Hex", - "digits": "digits", - "delete-key-dialog": { - "title": "Delete Key", - "confirm-delete-message": "Are you sure you want to delete this secret? This cannot be undone." - } - } - -} diff --git a/frontend/public/locales/en/integrations.json b/frontend/public/locales/en/integrations.json deleted file mode 100644 index 1fc92ca4e..000000000 --- a/frontend/public/locales/en/integrations.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Project Integrations", - "description": "Manage your integrations of Infisical with third-party services.", - "no-integrations1": "You don't have any integrations set up yet. When you do, they will appear here.", - "no-integrations2": "To start, click on any of the options below. It takes 5 clicks to set up.", - "available": "Platform & Cloud Integrations", - "available-text1": "Click on the integration you want to connect. This will let your environment variables flow automatically into selected third-party services.", - "available-text2": "Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com.", - "cloud-integrations": "Cloud Integrations", - "framework-integrations": "Framework Integrations", - "click-to-start": "Click on an integration to begin syncing secrets to it.", - "click-to-setup": "Click on a framework to get the setup instructions.", - "grant-access-to-secrets": "Grant Infisical access to your secrets", - "why-infisical-needs-access": "Most cloud integrations require Infisical to be able to decrypt your secrets so they can be forwarded over.", - "grant-access-button": "Grant access" -} diff --git a/frontend/public/locales/en/login.json b/frontend/public/locales/en/login.json deleted file mode 100644 index 75b56a014..000000000 --- a/frontend/public/locales/en/login.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "Login", - "og-title": "Log In to Infisical", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", - "login": "Log In", - "need-account": "Need an Infisical account?", - "create-account": "Create an account", - "forgot-password": "Forgot your password?", - "error-login": "Wrong credentials." -} diff --git a/frontend/public/locales/en/mfa.json b/frontend/public/locales/en/mfa.json deleted file mode 100644 index 2cc50c509..000000000 --- a/frontend/public/locales/en/mfa.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Sign Up", - "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...", - "signup": "Sign Up", - "already-have-account": "Have an account? Log in", - "forgot-password": "Forgot your password?", - "verify": "Verify", - "step1-start": "Let's get started", - "step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.", - "step1-submit": "Get Started", - "step2-message": "We've sent a verification code to", - "step2-code-error": "Oops. Your code is wrong. Tries left:", - "step2-resend-alert": "Don't see the code?", - "step2-resend-submit": "Resend", - "step2-resend-progress": "Resending...", - "step2-spam-alert": "Make sure to check your spam inbox.", - "step3-message": "Almost there!", - "step4-message": "Save your Emergency Kit", - "step4-description1": "If you get locked out of your account, your Emergency Kit is the only way to sign in.", - "step4-description2": "We recommend you download it and keep it somewhere safe.", - "step4-description3": "It contains your Secret Key which we cannot access or recover for you if you lose it.", - "step4-download": "Download PDF", - "step5-send-invites": "Send Invites", - "step5-invite-team": "Invite your team", - "step5-subtitle": "Infisical is meant to be used with your teammates. Invite them to test it out.", - "step5-skip": "Skip" -} diff --git a/frontend/public/locales/en/nav.json b/frontend/public/locales/en/nav.json deleted file mode 100644 index 3d0c6faca..000000000 --- a/frontend/public/locales/en/nav.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "support": { - "slack": "Join Slack Forum", - "docs": "Read Docs", - "issue": "Open a Github Issue", - "email": "Send us an Email" - }, - "user": { - "signed-in-as": "SIGNED IN AS", - "current-organization": "CURRENT ORGANIZATION", - "usage-billing": "Usage & Billing", - "invite": "Invite Members", - "other-organizations": "OTHER ORGANIZATION" - }, - "menu": { - "project": "PROJECT", - "secrets": "Secrets", - "members": "Members", - "integrations": "Integrations", - "project-settings": "Project Settings" - } -} diff --git a/frontend/public/locales/en/section-api-key.json b/frontend/public/locales/en/section-api-key.json deleted file mode 100644 index 3419744fe..000000000 --- a/frontend/public/locales/en/section-api-key.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "api-keys": "Service Tokens", - "api-keys-description": "Every service token is specific to you, a certain project and a certain environment within this project.", - "add-new": "Add New Token", - "add-dialog": { - "title": "Add an API Key", - "description": "Specify the name and expiry period. When an API key is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.", - "name": "API Key Name", - "add": "Add API Key", - "copy-service-token": "Copy your API key", - "copy-service-token-description": "Once you close this popup, you will never see your API key again" - } -} diff --git a/frontend/public/locales/en/section-incident.json b/frontend/public/locales/en/section-incident.json deleted file mode 100644 index de8f3e7b7..000000000 --- a/frontend/public/locales/en/section-incident.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "incident-contacts": "Incident Contacts", - "incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.", - "no-incident-contacts": "No incident contacts found.", - "add-contact": "Add Contact", - "add-dialog": { - "title": "Add an Incident Contact", - "description": "This contact will be notified in the unlikely event of a severe incident.", - "add-incident": "Add Incident Contact" - } -} diff --git a/frontend/public/locales/en/section-members.json b/frontend/public/locales/en/section-members.json deleted file mode 100644 index 89dbd2fea..000000000 --- a/frontend/public/locales/en/section-members.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "add-member": "Add Member", - "org-members": "Organization Members", - "org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.", - "search-members": "Search members...", - "add-dialog": { - "add-member-to-project": "Add a member to your project", - "already-all-invited": "All the users in your organization are already invited.", - "add-user-org-first": "Add more users to the organization first.", - "user-will-email": "The user will receive an email with the instructions.", - "looking-add": "<0>If you are looking to add users to your org,<1>click here", - "add-user-to-org": "Add Users to Organization" - } -} diff --git a/frontend/public/locales/en/section-password.json b/frontend/public/locales/en/section-password.json deleted file mode 100644 index 9c0410d6c..000000000 --- a/frontend/public/locales/en/section-password.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "password": "Password", - "change": "Change password", - "current": "Current password", - "current-wrong": "The current password may be wrong", - "new": "New password", - "validate-base": "Password should contain at least:", - "validate-length": "14 characters", - "validate-case": "1 lowercase character", - "validate-number": "1 number" -} diff --git a/frontend/public/locales/en/section-token.json b/frontend/public/locales/en/section-token.json deleted file mode 100644 index ce468b1af..000000000 --- a/frontend/public/locales/en/section-token.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "service-tokens": "Service Tokens", - "service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project.", - "add-new": "Add New Token", - "add-dialog": { - "title": "Add a service token for {{target}}", - "description": "When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.", - "name": "Service Token Name", - "add": "Add Service Token", - "copy-service-token": "Copy your service token", - "copy-service-token-description": "Once you close this popup, you will never see your service token again" - } -} diff --git a/frontend/public/locales/en/settings-members.json b/frontend/public/locales/en/settings-members.json deleted file mode 100644 index 128a649a0..000000000 --- a/frontend/public/locales/en/settings-members.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Project Members", - "description": "This page shows the members of the selected project, and allows you to modify their permissions." -} diff --git a/frontend/public/locales/en/settings-org.json b/frontend/public/locales/en/settings-org.json deleted file mode 100644 index d17baa7cd..000000000 --- a/frontend/public/locales/en/settings-org.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Organization Settings", - "description": "Manage members of your organization. These users could afterwards be formed into projects." -} diff --git a/frontend/public/locales/en/settings-personal.json b/frontend/public/locales/en/settings-personal.json deleted file mode 100644 index 66a90b6c3..000000000 --- a/frontend/public/locales/en/settings-personal.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Personal Settings", - "description": "View and manage your personal information here.", - "emergency": { - "name": "Emergency Kit", - "text1": "Your Emergency Kit contains the information you’ll need to sign in to your Infisical account.", - "text2": "Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.", - "download": "Download Emergency Kit" - }, - "change-language": "Change Language", - "api-keys": { - "title": "API Keys", - "description": "Manage your personal API Keys to access the Infisical API.", - "add-new": "Add new" - } -} diff --git a/frontend/public/locales/en/settings-project.json b/frontend/public/locales/en/settings-project.json deleted file mode 100644 index 3f3401f2e..000000000 --- a/frontend/public/locales/en/settings-project.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "title": "Project Settings", - "description": "These settings only apply to the currently selected Project.", - "danger-zone": "Danger Zone", - "delete-project": "Delete Project", - "project-to-delete": "Project to be Deleted", - "danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.", - "delete-project-note": "Note: You can only delete a project in case you have more than one", - "project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.", - "project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ", - "auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.", - "docs": "Infisical Docs", - "auto-capitalization": "Auto Capitalization", - "auto-capitalization-description": "According to standards, Infisical will automatically capitalize your keys. If you want to disable this feature, you can do so here." -} diff --git a/frontend/public/locales/en/signup.json b/frontend/public/locales/en/signup.json deleted file mode 100644 index 5fa5742e3..000000000 --- a/frontend/public/locales/en/signup.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Sign Up", - "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...", - "signup": "Sign Up", - "already-have-account": "Have an account? Log in", - "forgot-password": "Forgot your password?", - "verify": "Verify", - "step1-start": "Let's get started", - "step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.", - "step1-submit": "Get Started", - "step2-message": "We've sent a verification code to", - "step2-code-error": "Oops. Your code is wrong. Please try again.", - "step2-resend-alert": "Don't see the code?", - "step2-resend-submit": "Resend", - "step2-resend-progress": "Resending...", - "step2-spam-alert": "Make sure to check your spam inbox.", - "step3-message": "Almost there!", - "step4-message": "Save your Emergency Kit", - "step4-description1": "If you get locked out of your account, your Emergency Kit is the only way to sign in.", - "step4-description2": "We recommend you download it and keep it somewhere safe.", - "step4-description3": "It contains your Secret Key which we cannot access or recover for you if you lose it.", - "step4-download": "Download PDF", - "step5-send-invites": "Send Invites", - "step5-invite-team": "Invite your team", - "step5-subtitle": "Infisical is meant to be used with your teammates. Invite them to test it out.", - "step5-skip": "Skip" -} diff --git a/frontend/public/locales/en/translations.json b/frontend/public/locales/en/translations.json new file mode 100644 index 000000000..cb43bc1d4 --- /dev/null +++ b/frontend/public/locales/en/translations.json @@ -0,0 +1,319 @@ +{ + "activity": { + "title": "Audit Logs", + "subtitle": "Event history for this Infisical project.", + "event": { + "readSecrets": "Secrets Viewed", + "updateSecrets": "Secrets Updated", + "addSecrets": "Secrets Added", + "deleteSecrets": "Secrets Deleted" + }, + "ip-address": "IP Address" + }, + "billing": { + "title": "Usage & Billing", + "description": "View and manage your organization's subscription here", + "subscription": "Subscription", + "starter": { + "name": "Starter", + "price-explanation": "up to 5 team members", + "text": "Manage up to 3 project with up to 5 team members for free!", + "subtext": "" + }, + "professional": { + "name": "Professional", + "price-explanation": "/member/month", + "subtext": "Includes unlimited projects & members.", + "text": "Keep up with key management as you grow." + }, + "enterprise": { + "name": "Enterprise", + "text": "Keep up with key management as you grow." + }, + "current-usage": "Current Usage", + "free": "Free", + "downgrade": "Downgrade", + "upgrade": "Upgrade", + "learn-more": "Learn More", + "custom-pricing": "Custom Pricing", + "schedule-demo": "Schedule a Demo" + }, + "common": { + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "A project with this name already exists.", + "no-mobile": " To use Infisical, please log in through a device with larger dimensions. ", + "email": "Email", + "password": "Password", + "first-name": "First Name", + "last-name": "Last Name", + "logout": "Log Out", + "validate-required": "Please input your {{name}}", + "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", + "click-to-copy": "Click to copy", + "project-id": "Project ID", + "save-changes": "Save Changes", + "saved": "Saved", + "drop-zone": "Drag and drop a .env, .json, or .yml file here.", + "drop-zone-keys": "Drag and drop a .env, .json, or .yml file here to add more secrets.", + "role": "Role", + "role_admin": "admin", + "display-name": "Display Name", + "environment": "Environment", + "expired-in": "Expires in", + "language": "Language", + "search": "Search...", + "note": "Note", + "view-more": "View More", + "end-of-history": "End of History", + "select-event": "Select an event", + "event": "Event", + "user": "User", + "source": "Source", + "time": "Time", + "timestamp": "Timestamp" + }, + "dashboard": { + "title": "Secrets", + "og-title": "Manage your .env files in seconds", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "search-keys": "Search keys...", + "add-key": "Add Key", + "personal": "Personal", + "personal-description": "Personal keys are only visible to you", + "shared": "Shared", + "shared-description": "Shared keys are visible to your whole team", + "make-shared": "Make Shared", + "make-personal": "Make Personal", + "add-secret": "Add a new secret", + "check-docs": { + "button": "Check Docs", + "title": "Good job!", + "line1": "Congrats on adding more secrets.", + "line2": "Here is how to connect them to your codebase." + }, + "sidebar": { + "secret": "Secret", + "key": "Key", + "value": "Value", + "override": "Override value with a personal value", + "version-history": "Version History", + "comments": "Comments & Notes", + "personal-explanation": "This secret is personal. It is not shared with any of your teammates.", + "generate-random-hex": "Generate Random Hex", + "digits": "digits", + "delete-key-dialog": { + "title": "Delete Key", + "confirm-delete-message": "Are you sure you want to delete this secret? This cannot be undone." + } + } + }, + "integrations": { + "title": "Project Integrations", + "description": "Manage your integrations of Infisical with third-party services.", + "no-integrations1": "You don't have any integrations set up yet. When you do, they will appear here.", + "no-integrations2": "To start, click on any of the options below. It takes 5 clicks to set up.", + "available": "Platform & Cloud Integrations", + "available-text1": "Click on the integration you want to connect. This will let your environment variables flow automatically into selected third-party services.", + "available-text2": "Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com.", + "cloud-integrations": "Cloud Integrations", + "framework-integrations": "Framework Integrations", + "click-to-start": "Click on an integration to begin syncing secrets to it.", + "click-to-setup": "Click on a framework to get the setup instructions.", + "grant-access-to-secrets": "Grant Infisical access to your secrets", + "why-infisical-needs-access": "Most cloud integrations require Infisical to be able to decrypt your secrets so they can be forwarded over.", + "grant-access-button": "Grant access" + }, + "login": { + "title": "Login", + "og-title": "Log In to Infisical", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "login": "Log In", + "need-account": "Need an Infisical account?", + "create-account": "Create an account", + "forgot-password": "Forgot your password?", + "error-login": "Wrong credentials." + }, + "mfa": { + "title": "Sign Up", + "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Sign Up", + "already-have-account": "Have an account? Log in", + "forgot-password": "Forgot your password?", + "verify": "Verify", + "step1-start": "Let's get started", + "step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.", + "step1-submit": "Get Started", + "step2-message": "We've sent a verification code to", + "step2-code-error": "Oops. Your code is wrong. Tries left:", + "step2-resend-alert": "Don't see the code?", + "step2-resend-submit": "Resend", + "step2-resend-progress": "Resending...", + "step2-spam-alert": "Make sure to check your spam inbox.", + "step3-message": "Almost there!", + "step4-message": "Save your Emergency Kit", + "step4-description1": "If you get locked out of your account, your Emergency Kit is the only way to sign in.", + "step4-description2": "We recommend you download it and keep it somewhere safe.", + "step4-description3": "It contains your Secret Key which we cannot access or recover for you if you lose it.", + "step4-download": "Download PDF", + "step5-send-invites": "Send Invites", + "step5-invite-team": "Invite your team", + "step5-subtitle": "Infisical is meant to be used with your teammates. Invite them to test it out.", + "step5-skip": "Skip" + }, + "nav": { + "support": { + "slack": "Join Slack Forum", + "docs": "Read Docs", + "issue": "Open a Github Issue", + "email": "Send us an Email" + }, + "user": { + "signed-in-as": "SIGNED IN AS", + "current-organization": "CURRENT ORGANIZATION", + "usage-billing": "Usage & Billing", + "invite": "Invite Members", + "other-organizations": "OTHER ORGANIZATION" + }, + "menu": { + "project": "PROJECT", + "secrets": "Secrets", + "members": "Members", + "integrations": "Integrations", + "project-settings": "Project Settings" + } + }, + "section": { + "api-key": { + "api-keys": "Service Tokens", + "api-keys-description": "Every service token is specific to you, a certain project and a certain environment within this project.", + "add-new": "Add New Token", + "add-dialog": { + "title": "Add an API Key", + "description": "Specify the name and expiry period. When an API key is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.", + "name": "API Key Name", + "add": "Add API Key", + "copy-service-token": "Copy your API key", + "copy-service-token-description": "Once you close this popup, you will never see your API key again" + } + }, + "incident": { + "incident-contacts": "Incident Contacts", + "incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.", + "no-incident-contacts": "No incident contacts found.", + "add-contact": "Add Contact", + "add-dialog": { + "title": "Add an Incident Contact", + "description": "This contact will be notified in the unlikely event of a severe incident.", + "add-incident": "Add Incident Contact" + } + }, + "members": { + "add-member": "Add Member", + "org-members": "Organization Members", + "org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.", + "search-members": "Search members...", + "add-dialog": { + "add-member-to-project": "Add a member to your project", + "already-all-invited": "All the users in your organization are already invited.", + "add-user-org-first": "Add more users to the organization first.", + "user-will-email": "The user will receive an email with the instructions.", + "looking-add": "<0>If you are looking to add users to your org,<1>click here", + "add-user-to-org": "Add Users to Organization" + } + }, + "password": { + "password": "Password", + "change": "Change password", + "current": "Current password", + "current-wrong": "The current password may be wrong", + "new": "New password", + "validate-base": "Password should contain at least:", + "validate-length": "14 characters", + "validate-case": "1 lowercase character", + "validate-number": "1 number" + }, + "token": { + "service-tokens": "Service Tokens", + "service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project.", + "add-new": "Add New Token", + "add-dialog": { + "title": "Add a service token for {{target}}", + "description": "When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.", + "name": "Service Token Name", + "add": "Add Service Token", + "copy-service-token": "Copy your service token", + "copy-service-token-description": "Once you close this popup, you will never see your service token again" + } + } + }, + "settings": { + "members": { + "title": "Project Members", + "description": "This page shows the members of the selected project, and allows you to modify their permissions." + }, + "org": { + "title": "Organization Settings", + "description": "Manage members of your organization. These users could afterwards be formed into projects." + }, + "personal": { + "title": "Personal Settings", + "description": "View and manage your personal information here.", + "emergency": { + "name": "Emergency Kit", + "text1": "Your Emergency Kit contains the information you’ll need to sign in to your Infisical account.", + "text2": "Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.", + "download": "Download Emergency Kit" + }, + "change-language": "Change Language", + "api-keys": { + "title": "API Keys", + "description": "Manage your personal API Keys to access the Infisical API.", + "add-new": "Add new" + } + }, + "project": { + "title": "Project Settings", + "description": "These settings only apply to the currently selected Project.", + "danger-zone": "Danger Zone", + "delete-project": "Delete Project", + "project-to-delete": "Project to be Deleted", + "danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.", + "delete-project-note": "Note: You can only delete a project in case you have more than one", + "project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.", + "project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ", + "auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.", + "docs": "Infisical Docs", + "auto-capitalization": "Auto Capitalization", + "auto-capitalization-description": "According to standards, Infisical will automatically capitalize your keys. If you want to disable this feature, you can do so here." + } + }, + "signup": { + "title": "Sign Up", + "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Sign Up", + "already-have-account": "Have an account? Log in", + "forgot-password": "Forgot your password?", + "verify": "Verify", + "step1-start": "Let's get started", + "step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.", + "step1-submit": "Get Started", + "step2-message": "We've sent a verification code to", + "step2-code-error": "Oops. Your code is wrong. Please try again.", + "step2-resend-alert": "Don't see the code?", + "step2-resend-submit": "Resend", + "step2-resend-progress": "Resending...", + "step2-spam-alert": "Make sure to check your spam inbox.", + "step3-message": "Almost there!", + "step4-message": "Save your Emergency Kit", + "step4-description1": "If you get locked out of your account, your Emergency Kit is the only way to sign in.", + "step4-description2": "We recommend you download it and keep it somewhere safe.", + "step4-description3": "It contains your Secret Key which we cannot access or recover for you if you lose it.", + "step4-download": "Download PDF", + "step5-send-invites": "Send Invites", + "step5-invite-team": "Invite your team", + "step5-subtitle": "Infisical is meant to be used with your teammates. Invite them to test it out.", + "step5-skip": "Skip" + } +} diff --git a/frontend/public/locales/es/activity.json b/frontend/public/locales/es/activity.json deleted file mode 100644 index ef275e39c..000000000 --- a/frontend/public/locales/es/activity.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "Historial de eventos", - "subtitle": "Historial de eventos para este proyecto de Infisical.", - "event": { - "readSecrets": "Secrets vistas", - "updateSecrets": "Secrets actualizadas", - "addSecrets": "Secrets añadidas", - "deleteSecrets": "Secrets eliminadas" - }, - "ip-address": "Dirección IP" -} diff --git a/frontend/public/locales/es/billing.json b/frontend/public/locales/es/billing.json deleted file mode 100644 index 8ffc62c84..000000000 --- a/frontend/public/locales/es/billing.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Uso & Facturación", - "description": "Visualiza y gestiona la suscripción de tu organización", - "subscription": "Suscripción", - "starter": { - "name": "Starter", - "price-explanation": "hasta 5 miembros", - "text": "¡Hasta 5 personas gratis!", - "subtext": "Después, $5 por miembro/mes." - }, - "professional": { - "name": "Professional", - "price-explanation": "/miembro/mes", - "subtext": "Includes unlimited projects & members.", - "text": "Mantén la gestión de claves a medida que creces." - }, - "enterprise": { - "name": "Enterprise", - "text": "Mantén la gestión de claves a medida que creces." - }, - "current-usage": "Uso actual", - "free": "Gratis", - "downgrade": "Reducir", - "upgrade": "Mejorar", - "learn-more": "Saber más", - "custom-pricing": "A medida", - "schedule-demo": "Solicitar una demo" -} diff --git a/frontend/public/locales/es/common.json b/frontend/public/locales/es/common.json deleted file mode 100644 index 8b0446085..000000000 --- a/frontend/public/locales/es/common.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "head-title": "{{title}} | Infisical", - "error_project-already-exists": "Ya existe un proyecto con este nombre.", - "no-mobile": "Para usar Infisical, inicia sesión con un dispositivo de mayores dimesiones.", - "email": "Correo electrónico", - "password": "Contraseña", - "first-name": "Nombre", - "last-name": "Apellidos", - "logout": "Cerrar sesión", - "validate-required": "Por favor, introduce tu {{name}}", - "maintenance-alert": "Estamos experimentando problemas técnicos. Estamos trabajando para resolverlos. Por favor, vuelve en unos minutos.", - "click-to-copy": "Click para copiar", - "project-id": "ID de proyecto", - "save-changes": "Guardar cambios", - "saved": "Guardado", - "drop-zone": "Arrastra y suelta un archivo .env, .json o .yml aquí.", - "drop-zone-keys": "Arrastra y suelta un archivo .env, .json, or .yml aquí para añadir más secrets.", - "role": "Rol", - "role_admin": "admin", - "display-name": "Nombre visible", - "environment": "Entorno", - "expired-in": "Expira en", - "language": "Idioma", - "search": "Buscar...", - "note": "Nota", - "view-more": "Ver más", - "end-of-history": "Fin del historial", - "select-event": "Selecciona un evento", - "event": "Evento", - "user": "Usuario", - "source": "Fuente", - "time": "Hora", - "timestamp": "Marca temporal" -} \ No newline at end of file diff --git a/frontend/public/locales/es/dashboard.json b/frontend/public/locales/es/dashboard.json deleted file mode 100644 index ac3cef0dd..000000000 --- a/frontend/public/locales/es/dashboard.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "title": "Secrets", - "og-title": "Gestiona tus archivos .env en segundos", - "og-description": "Infisical es una solución cifrada de extremo a extremo que habilita a los equipos a compartir archivos .env de forma sencilla.", - "search-keys": "Buscar claves...", - "add-key": "Añadir clave", - "personal": "Personal", - "personal-description": "Las claves personales solo son visibles para ti", - "shared": "Compartido", - "shared-description": "Claves compartidas son visibles para todo tu equipo", - "make-shared": "Hacer compartida", - "make-personal": "Hacer personal", - "add-secret": "Añadir una nueva clave", - "check-docs": { - "button": "Comprueba la documentación", - "title": "¡Buen trabajo!", - "line1": "Enhorabuena por añadir claves.", - "line2": "Averigua como usarlo desde tu código." - }, - "sidebar": { - "secret": "Secret", - "key": "Clave", - "value": "valor", - "override": "Sobreescribir valor con el valor personal", - "version-history": "Historial de versiones", - "comments": "Comentarios & Notas", - "personal-explanation": "Esta clave es personal. No será compartida con ninguno de tus compañeros.", - "generate-random-hex": "Generar Hex aleatorio", - "digits": "dígitos", - "delete-key-dialog": { - "title": "Eliminar clave", - "confirm-delete-message": "¿Estás seguro de que quieres eliminar esta clave? Esta operación no se puede deshacer." - } - } -} diff --git a/frontend/public/locales/es/integrations.json b/frontend/public/locales/es/integrations.json deleted file mode 100644 index 38d299d5a..000000000 --- a/frontend/public/locales/es/integrations.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Integraciones del proyecto", - "description": "Gestiona tus integraciones de Infisical con aplicaciones de terceros.", - "no-integrations1": "No tienes ninguna integración configurada. Cuando las tengas, aparecerán aquí.", - "no-integrations2": "Para empezar haz click en cualquiera de las opciones siguientes. Se necesitan tan solo 5 pasos.", - "available": "Integraciones con la nube", - "available-text1": "Haz click en la integración que quieras conectar. Esto hará que las variables de entorno se configuren automáticamente en los servicios de terceros seleccionados.", - "available-text2": "Nota: en la integración con Heroku, por motivos de seguridad, es imposible mantener el cifrado de extremo a extremo. En teoría, esto permite a Infisical descifrar tus variables de entorno. En la práctica, te podemos asegurar que esto nunca va a suceder. El núcleo del servicio Infisical siempre estará cifrado de extremo a extremo. Si tienes dudas, escríbenos a support@infisical.com.", - "cloud-integrations": "Integraciones con la nube", - "framework-integrations": "Integraciones con frameworks", - "click-to-start": "Haz click en una integración para empezar a sincronizar las claves.", - "click-to-setup": "Haz click en un framework para ver las instrucciones de uso.", - "grant-access-to-secrets": "Autorizar Infisical el acceso a tus claves", - "why-infisical-needs-access": "La mayoría de las integraciones en la nube requieren a Infisical tener permiso para descifrar tus claves, para que puedan ser enviadas.", - "grant-access-button": "Autorizar acceso" -} diff --git a/frontend/public/locales/es/login.json b/frontend/public/locales/es/login.json deleted file mode 100644 index 1fdd5b970..000000000 --- a/frontend/public/locales/es/login.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "Iniciar sesión", - "og-title": "Iniciar sesión en Infisical", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", - "login": "Iniciar sesión", - "need-account": "¿Necesitas una cuenta de Infisical?", - "create-account": "Crea una cuenta", - "forgot-password": "¿Has olvidado tu contraseña?", - "error-login": "Datos incorrectos." -} diff --git a/frontend/public/locales/es/mfa.json b/frontend/public/locales/es/mfa.json deleted file mode 100644 index 35d41adf5..000000000 --- a/frontend/public/locales/es/mfa.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Registrarse", - "og-title": "Reemplaza los archivos .env con una línea de código. Regístrate en Infisical en solo 3 minutos.", - "og-description": "Infisical es una plataforma sencilla cifrada de extremo a extremo que permite a equipos sincronizar y gestionar API-keys y variables de entorno. Funciona con Node.js, Next.js, Gatsby, Nest.js...", - "signup": "Registrarse", - "already-have-account": "¿Ya tienes una cuenta? Inicia sesión", - "forgot-password": "¿Has olvidado tu contraseña?", - "verify": "Verificar", - "step1-start": "Vamos a empezar", - "step1-privacy": "Al crear la cuenta, aceptas nuestros Términos y has leído y comprendido nuestra Política de privacidad.", - "step1-submit": "Empezar", - "step2-message": "Hemos enviado un código a", - "step2-code-error": "Oops. Tu código es incorrecto. Intentos restantes:", - "step2-resend-alert": "¿No ves el código?", - "step2-resend-submit": "Volver a enviar", - "step2-resend-progress": "Reenviando...", - "step2-spam-alert": "Asegúrate de comprobar la carpeta de spam.", - "step3-message": "¡Casi hemos terminado!", - "step4-message": "Guarda tu Kit de emergencia", - "step4-description1": "Si pierdes el acceso a tu cuenta, tu Kit de emergencia es la única forma de iniciar sesión.", - "step4-description2": "Te recomendamos que lo descargues y lo guardes en un sitio seguro.", - "step4-description3": "Contiene tu Clave secreta, a la que no tenemos acceso y tampoco podemos recuperar si la pierdes.", - "step4-download": "Descargar PDF", - "step5-send-invites": "Enviar invitaciones", - "step5-invite-team": "Invita a tu equipo", - "step5-subtitle": "Infisical está pensado para usarlo con tus compañeros. Invítalos a probarlo.", - "step5-skip": "Saltar" -} diff --git a/frontend/public/locales/es/nav.json b/frontend/public/locales/es/nav.json deleted file mode 100644 index a83446626..000000000 --- a/frontend/public/locales/es/nav.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "support": { - "slack": "Unirse al Slack", - "docs": "Leer documentación", - "issue": "Abrir una Github Issue", - "email": "Envíanos un correo electrónico" - }, - "user": { - "signed-in-as": "INICIADO COMO", - "current-organization": "ORGANIZACIÓN ACTUAL", - "usage-billing": "Uso & Facturación", - "invite": "Invitar miembros", - "other-organizations": "OTRA ORGANIZACIÓN" - }, - "menu": { - "project": "PROYECTO", - "secrets": "Claves", - "members": "Miembros", - "integrations": "Integraciones", - "project-settings": "Configuración del proyecto" - } -} diff --git a/frontend/public/locales/es/section-api-key.json b/frontend/public/locales/es/section-api-key.json deleted file mode 100644 index bf385862b..000000000 --- a/frontend/public/locales/es/section-api-key.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "api-keys": "Tokens de servicio", - "api-keys-description": "Cada token de servicio es específico para ti, para cada proyecto y para cada entorno en este proyecto.", - "add-new": "Añadir nuevo token", - "add-dialog": { - "title": "Añadir una API Key", - "description": "Especifica el nombre y el período de expiración. Cuando una API key es generada, solo podrás verla una vez hasta que desaparezca. Asegúrate de guardarla en algún lado.", - "name": "Nombre de la API Key", - "add": "Añadir API Key", - "copy-service-token": "Copia tu API key", - "copy-service-token-description": "Una vez que cierres esta ventana, no volverás a ver tu API key" - } -} diff --git a/frontend/public/locales/es/section-incident.json b/frontend/public/locales/es/section-incident.json deleted file mode 100644 index 79505ab60..000000000 --- a/frontend/public/locales/es/section-incident.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "incident-contacts": "Contactos de incidencias", - "incident-contacts-description": "Estos contactos serán notificados en caso de una incidencia grave.", - "no-incident-contacts": "No se han encontrado contactos para incidencias.", - "add-contact": "Añadir contacto", - "add-dialog": { - "title": "Añadir un contacto de incidencias", - "description": "Este contacto será notificado en el caso de una incidencia grave.", - "add-incident": "Añadir contacto de incidencias" - } -} diff --git a/frontend/public/locales/es/section-members.json b/frontend/public/locales/es/section-members.json deleted file mode 100644 index 26996d697..000000000 --- a/frontend/public/locales/es/section-members.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "add-member": "Añadir miembro", - "org-members": "Miembros de la organización", - "org-members-description": "Gestiona los miembros de tu organización. Estos usuarios podrán ser agrupados en proyectos más tarde.", - "search-members": "Buscar miembros...", - "add-dialog": { - "add-member-to-project": "Añadir un miembro al proyecto", - "already-all-invited": "Todos los uaurios en tu organización han sido invitados.", - "add-user-org-first": "Añadir primero más usuarios a la organización.", - "user-will-email": "El usuario recibirá un correo electrónico con la invitación.", - "looking-add": "<0>Si quieres añadir usuarios a tu organización, haz<1>click aquí", - "add-user-to-org": "Añadir usuarios a la organización" - } -} diff --git a/frontend/public/locales/es/section-password.json b/frontend/public/locales/es/section-password.json deleted file mode 100644 index f3b957ee2..000000000 --- a/frontend/public/locales/es/section-password.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "password": "Contraseña", - "change": "Cambiar contraseña", - "current": "Contraseña actual", - "current-wrong": "La contraseña actual puede puede que sea incorrecta", - "new": "Nueva contraseña", - "validate-base": "La contraseña debe contener como mínimo:", - "validate-length": "14 caracteres", - "validate-case": "1 letra en minúsculas", - "validate-number": "1 número" -} diff --git a/frontend/public/locales/es/section-token.json b/frontend/public/locales/es/section-token.json deleted file mode 100644 index fdf04e600..000000000 --- a/frontend/public/locales/es/section-token.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "service-tokens": "Tokens de servicio", - "service-tokens-description": "Cada token de servicio es específico para ti, para cada proyecto y para cada entorno en este proyectos.", - "add-new": "Añadir nuevo token", - "add-dialog": { - "title": "Añade un nuevo token de servicio para {{target}}", - "description": "Cuando se genera un token, solo podrás verlo una vez antes de que desaparezca. Asegúrate de guardarlo en algún lugar.", - "name": "Nombre del token de servicio", - "add": "Añadir token de servicio", - "copy-service-token": "Copiar tu token de servicio", - "copy-service-token-description": "Una vez cierres esta ventana, no volverás a ver tu token de nuevo" - } -} diff --git a/frontend/public/locales/es/settings-members.json b/frontend/public/locales/es/settings-members.json deleted file mode 100644 index bf6a0c106..000000000 --- a/frontend/public/locales/es/settings-members.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Miembros del proyecto", - "description": "Esta página muestra los miembros del proyecto seleccionado, y permite modificar sus permisos." -} diff --git a/frontend/public/locales/es/settings-org.json b/frontend/public/locales/es/settings-org.json deleted file mode 100644 index 3988bd165..000000000 --- a/frontend/public/locales/es/settings-org.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Configuración de la organización", - "description": "Gestiona los miembros de tu organización. Estos usuarios podrán ser gestionados en proyectos más adelante." -} diff --git a/frontend/public/locales/es/settings-personal.json b/frontend/public/locales/es/settings-personal.json deleted file mode 100644 index 540386578..000000000 --- a/frontend/public/locales/es/settings-personal.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Preferencias personales", - "description": "Visualiza y gestiona aquí tu información personal.", - "emergency": { - "name": "Kit de emergencia", - "text1": "Tu Kit de emergencia contiene la información que necesitarás para iniciar sesión en tu cuenta de Infisical.", - "text2": "Solo el último Kit de emergencia descargado es válido. Para conseguir uno nuevo, introduce tu contraseña.", - "download": "Descargar Kit de emergencia" - }, - "change-language": "Cambiar idioma", - "api-keys": { - "title": "API Keys", - "description": "Gestiona tus API Keys personales para acceder a la API de Infisical.", - "add-new": "Añadir" - } -} diff --git a/frontend/public/locales/es/settings-project.json b/frontend/public/locales/es/settings-project.json deleted file mode 100644 index b1757d072..000000000 --- a/frontend/public/locales/es/settings-project.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "title": "Configuración de proyecto", - "description": "Esta configuración solo afecta al proyecto seleccionado.", - "danger-zone": "Zona de peligro", - "delete-project": "Eliminar proyecto", - "project-to-delete": "Proyecto a eliminar", - "danger-zone-note": "Tan pronto como elimines el proyecto, no podrás volver atrás. Esto eliminará todas las claves. Si aún quieres hacerlo, introduce el nombre del proyecto a continuación.", - "delete-project-note": "Nota: Solo puedes eliminar un proyecto si tienes más de uno", - "project-id-description": "Para integrar Infisical en tu aplicación y obtener la inyección automática de variables de entorno, debes usar el siguiente ID de Proyecto.", - "project-id-description2": "Para más guías, incluyendo ejemplos de código en diferentes lenguajes y frameworks, visita ", - "auto-generated": "Este es el ID único y autogenerado de proyecto. No se puede modificar.", - "docs": "Documentación de Infisical", - "auto-capitalization": "Mayúsculas automáticas", - "auto-capitalization-description": "De acuerdo con los estándares, Infisical pondrá en mayúsculas tus claves. Si quieres desactivar esta funcionalidad, lo puedes hacer aquí." -} diff --git a/frontend/public/locales/es/signup.json b/frontend/public/locales/es/signup.json deleted file mode 100644 index 35d41adf5..000000000 --- a/frontend/public/locales/es/signup.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Registrarse", - "og-title": "Reemplaza los archivos .env con una línea de código. Regístrate en Infisical en solo 3 minutos.", - "og-description": "Infisical es una plataforma sencilla cifrada de extremo a extremo que permite a equipos sincronizar y gestionar API-keys y variables de entorno. Funciona con Node.js, Next.js, Gatsby, Nest.js...", - "signup": "Registrarse", - "already-have-account": "¿Ya tienes una cuenta? Inicia sesión", - "forgot-password": "¿Has olvidado tu contraseña?", - "verify": "Verificar", - "step1-start": "Vamos a empezar", - "step1-privacy": "Al crear la cuenta, aceptas nuestros Términos y has leído y comprendido nuestra Política de privacidad.", - "step1-submit": "Empezar", - "step2-message": "Hemos enviado un código a", - "step2-code-error": "Oops. Tu código es incorrecto. Intentos restantes:", - "step2-resend-alert": "¿No ves el código?", - "step2-resend-submit": "Volver a enviar", - "step2-resend-progress": "Reenviando...", - "step2-spam-alert": "Asegúrate de comprobar la carpeta de spam.", - "step3-message": "¡Casi hemos terminado!", - "step4-message": "Guarda tu Kit de emergencia", - "step4-description1": "Si pierdes el acceso a tu cuenta, tu Kit de emergencia es la única forma de iniciar sesión.", - "step4-description2": "Te recomendamos que lo descargues y lo guardes en un sitio seguro.", - "step4-description3": "Contiene tu Clave secreta, a la que no tenemos acceso y tampoco podemos recuperar si la pierdes.", - "step4-download": "Descargar PDF", - "step5-send-invites": "Enviar invitaciones", - "step5-invite-team": "Invita a tu equipo", - "step5-subtitle": "Infisical está pensado para usarlo con tus compañeros. Invítalos a probarlo.", - "step5-skip": "Saltar" -} diff --git a/frontend/public/locales/es/translations.json b/frontend/public/locales/es/translations.json new file mode 100644 index 000000000..e734fb3f2 --- /dev/null +++ b/frontend/public/locales/es/translations.json @@ -0,0 +1,319 @@ +{ + "activity": { + "title": "Historial de eventos", + "subtitle": "Historial de eventos para este proyecto de Infisical.", + "event": { + "readSecrets": "Secrets vistas", + "updateSecrets": "Secrets actualizadas", + "addSecrets": "Secrets añadidas", + "deleteSecrets": "Secrets eliminadas" + }, + "ip-address": "Dirección IP" + }, + "billing": { + "title": "Uso & Facturación", + "description": "Visualiza y gestiona la suscripción de tu organización", + "subscription": "Suscripción", + "starter": { + "name": "Starter", + "price-explanation": "hasta 5 miembros", + "text": "¡Hasta 5 personas gratis!", + "subtext": "Después, $5 por miembro/mes." + }, + "professional": { + "name": "Professional", + "price-explanation": "/miembro/mes", + "subtext": "Includes unlimited projects & members.", + "text": "Mantén la gestión de claves a medida que creces." + }, + "enterprise": { + "name": "Enterprise", + "text": "Mantén la gestión de claves a medida que creces." + }, + "current-usage": "Uso actual", + "free": "Gratis", + "downgrade": "Reducir", + "upgrade": "Mejorar", + "learn-more": "Saber más", + "custom-pricing": "A medida", + "schedule-demo": "Solicitar una demo" + }, + "common": { + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "Ya existe un proyecto con este nombre.", + "no-mobile": "Para usar Infisical, inicia sesión con un dispositivo de mayores dimesiones.", + "email": "Correo electrónico", + "password": "Contraseña", + "first-name": "Nombre", + "last-name": "Apellidos", + "logout": "Cerrar sesión", + "validate-required": "Por favor, introduce tu {{name}}", + "maintenance-alert": "Estamos experimentando problemas técnicos. Estamos trabajando para resolverlos. Por favor, vuelve en unos minutos.", + "click-to-copy": "Click para copiar", + "project-id": "ID de proyecto", + "save-changes": "Guardar cambios", + "saved": "Guardado", + "drop-zone": "Arrastra y suelta un archivo .env, .json o .yml aquí.", + "drop-zone-keys": "Arrastra y suelta un archivo .env, .json, or .yml aquí para añadir más secrets.", + "role": "Rol", + "role_admin": "admin", + "display-name": "Nombre visible", + "environment": "Entorno", + "expired-in": "Expira en", + "language": "Idioma", + "search": "Buscar...", + "note": "Nota", + "view-more": "Ver más", + "end-of-history": "Fin del historial", + "select-event": "Selecciona un evento", + "event": "Evento", + "user": "Usuario", + "source": "Fuente", + "time": "Hora", + "timestamp": "Marca temporal" + }, + "dashboard": { + "title": "Secrets", + "og-title": "Gestiona tus archivos .env en segundos", + "og-description": "Infisical es una solución cifrada de extremo a extremo que habilita a los equipos a compartir archivos .env de forma sencilla.", + "search-keys": "Buscar claves...", + "add-key": "Añadir clave", + "personal": "Personal", + "personal-description": "Las claves personales solo son visibles para ti", + "shared": "Compartido", + "shared-description": "Claves compartidas son visibles para todo tu equipo", + "make-shared": "Hacer compartida", + "make-personal": "Hacer personal", + "add-secret": "Añadir una nueva clave", + "check-docs": { + "button": "Comprueba la documentación", + "title": "¡Buen trabajo!", + "line1": "Enhorabuena por añadir claves.", + "line2": "Averigua como usarlo desde tu código." + }, + "sidebar": { + "secret": "Secret", + "key": "Clave", + "value": "valor", + "override": "Sobreescribir valor con el valor personal", + "version-history": "Historial de versiones", + "comments": "Comentarios & Notas", + "personal-explanation": "Esta clave es personal. No será compartida con ninguno de tus compañeros.", + "generate-random-hex": "Generar Hex aleatorio", + "digits": "dígitos", + "delete-key-dialog": { + "title": "Eliminar clave", + "confirm-delete-message": "¿Estás seguro de que quieres eliminar esta clave? Esta operación no se puede deshacer." + } + } + }, + "integrations": { + "title": "Integraciones del proyecto", + "description": "Gestiona tus integraciones de Infisical con aplicaciones de terceros.", + "no-integrations1": "No tienes ninguna integración configurada. Cuando las tengas, aparecerán aquí.", + "no-integrations2": "Para empezar haz click en cualquiera de las opciones siguientes. Se necesitan tan solo 5 pasos.", + "available": "Integraciones con la nube", + "available-text1": "Haz click en la integración que quieras conectar. Esto hará que las variables de entorno se configuren automáticamente en los servicios de terceros seleccionados.", + "available-text2": "Nota: en la integración con Heroku, por motivos de seguridad, es imposible mantener el cifrado de extremo a extremo. En teoría, esto permite a Infisical descifrar tus variables de entorno. En la práctica, te podemos asegurar que esto nunca va a suceder. El núcleo del servicio Infisical siempre estará cifrado de extremo a extremo. Si tienes dudas, escríbenos a support@infisical.com.", + "cloud-integrations": "Integraciones con la nube", + "framework-integrations": "Integraciones con frameworks", + "click-to-start": "Haz click en una integración para empezar a sincronizar las claves.", + "click-to-setup": "Haz click en un framework para ver las instrucciones de uso.", + "grant-access-to-secrets": "Autorizar Infisical el acceso a tus claves", + "why-infisical-needs-access": "La mayoría de las integraciones en la nube requieren a Infisical tener permiso para descifrar tus claves, para que puedan ser enviadas.", + "grant-access-button": "Autorizar acceso" + }, + "login": { + "title": "Iniciar sesión", + "og-title": "Iniciar sesión en Infisical", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "login": "Iniciar sesión", + "need-account": "¿Necesitas una cuenta de Infisical?", + "create-account": "Crea una cuenta", + "forgot-password": "¿Has olvidado tu contraseña?", + "error-login": "Datos incorrectos." + }, + "mfa": { + "title": "Registrarse", + "og-title": "Reemplaza los archivos .env con una línea de código. Regístrate en Infisical en solo 3 minutos.", + "og-description": "Infisical es una plataforma sencilla cifrada de extremo a extremo que permite a equipos sincronizar y gestionar API-keys y variables de entorno. Funciona con Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Registrarse", + "already-have-account": "¿Ya tienes una cuenta? Inicia sesión", + "forgot-password": "¿Has olvidado tu contraseña?", + "verify": "Verificar", + "step1-start": "Vamos a empezar", + "step1-privacy": "Al crear la cuenta, aceptas nuestros Términos y has leído y comprendido nuestra Política de privacidad.", + "step1-submit": "Empezar", + "step2-message": "Hemos enviado un código a", + "step2-code-error": "Oops. Tu código es incorrecto. Intentos restantes:", + "step2-resend-alert": "¿No ves el código?", + "step2-resend-submit": "Volver a enviar", + "step2-resend-progress": "Reenviando...", + "step2-spam-alert": "Asegúrate de comprobar la carpeta de spam.", + "step3-message": "¡Casi hemos terminado!", + "step4-message": "Guarda tu Kit de emergencia", + "step4-description1": "Si pierdes el acceso a tu cuenta, tu Kit de emergencia es la única forma de iniciar sesión.", + "step4-description2": "Te recomendamos que lo descargues y lo guardes en un sitio seguro.", + "step4-description3": "Contiene tu Clave secreta, a la que no tenemos acceso y tampoco podemos recuperar si la pierdes.", + "step4-download": "Descargar PDF", + "step5-send-invites": "Enviar invitaciones", + "step5-invite-team": "Invita a tu equipo", + "step5-subtitle": "Infisical está pensado para usarlo con tus compañeros. Invítalos a probarlo.", + "step5-skip": "Saltar" + }, + "nav": { + "support": { + "slack": "Unirse al Slack", + "docs": "Leer documentación", + "issue": "Abrir una Github Issue", + "email": "Envíanos un correo electrónico" + }, + "user": { + "signed-in-as": "INICIADO COMO", + "current-organization": "ORGANIZACIÓN ACTUAL", + "usage-billing": "Uso & Facturación", + "invite": "Invitar miembros", + "other-organizations": "OTRA ORGANIZACIÓN" + }, + "menu": { + "project": "PROYECTO", + "secrets": "Claves", + "members": "Miembros", + "integrations": "Integraciones", + "project-settings": "Configuración del proyecto" + } + }, + "section": { + "api-key": { + "api-keys": "Tokens de servicio", + "api-keys-description": "Cada token de servicio es específico para ti, para cada proyecto y para cada entorno en este proyecto.", + "add-new": "Añadir nuevo token", + "add-dialog": { + "title": "Añadir una API Key", + "description": "Especifica el nombre y el período de expiración. Cuando una API key es generada, solo podrás verla una vez hasta que desaparezca. Asegúrate de guardarla en algún lado.", + "name": "Nombre de la API Key", + "add": "Añadir API Key", + "copy-service-token": "Copia tu API key", + "copy-service-token-description": "Una vez que cierres esta ventana, no volverás a ver tu API key" + } + }, + "incident": { + "incident-contacts": "Contactos de incidencias", + "incident-contacts-description": "Estos contactos serán notificados en caso de una incidencia grave.", + "no-incident-contacts": "No se han encontrado contactos para incidencias.", + "add-contact": "Añadir contacto", + "add-dialog": { + "title": "Añadir un contacto de incidencias", + "description": "Este contacto será notificado en el caso de una incidencia grave.", + "add-incident": "Añadir contacto de incidencias" + } + }, + "members": { + "add-member": "Añadir miembro", + "org-members": "Miembros de la organización", + "org-members-description": "Gestiona los miembros de tu organización. Estos usuarios podrán ser agrupados en proyectos más tarde.", + "search-members": "Buscar miembros...", + "add-dialog": { + "add-member-to-project": "Añadir un miembro al proyecto", + "already-all-invited": "Todos los uaurios en tu organización han sido invitados.", + "add-user-org-first": "Añadir primero más usuarios a la organización.", + "user-will-email": "El usuario recibirá un correo electrónico con la invitación.", + "looking-add": "<0>Si quieres añadir usuarios a tu organización, haz<1>click aquí", + "add-user-to-org": "Añadir usuarios a la organización" + } + }, + "password": { + "password": "Contraseña", + "change": "Cambiar contraseña", + "current": "Contraseña actual", + "current-wrong": "La contraseña actual puede puede que sea incorrecta", + "new": "Nueva contraseña", + "validate-base": "La contraseña debe contener como mínimo:", + "validate-length": "14 caracteres", + "validate-case": "1 letra en minúsculas", + "validate-number": "1 número" + }, + "token": { + "service-tokens": "Tokens de servicio", + "service-tokens-description": "Cada token de servicio es específico para ti, para cada proyecto y para cada entorno en este proyectos.", + "add-new": "Añadir nuevo token", + "add-dialog": { + "title": "Añade un nuevo token de servicio para {{target}}", + "description": "Cuando se genera un token, solo podrás verlo una vez antes de que desaparezca. Asegúrate de guardarlo en algún lugar.", + "name": "Nombre del token de servicio", + "add": "Añadir token de servicio", + "copy-service-token": "Copiar tu token de servicio", + "copy-service-token-description": "Una vez cierres esta ventana, no volverás a ver tu token de nuevo" + } + } + }, + "settings": { + "members": { + "title": "Miembros del proyecto", + "description": "Esta página muestra los miembros del proyecto seleccionado, y permite modificar sus permisos." + }, + "org": { + "title": "Configuración de la organización", + "description": "Gestiona los miembros de tu organización. Estos usuarios podrán ser gestionados en proyectos más adelante." + }, + "personal": { + "title": "Preferencias personales", + "description": "Visualiza y gestiona aquí tu información personal.", + "emergency": { + "name": "Kit de emergencia", + "text1": "Tu Kit de emergencia contiene la información que necesitarás para iniciar sesión en tu cuenta de Infisical.", + "text2": "Solo el último Kit de emergencia descargado es válido. Para conseguir uno nuevo, introduce tu contraseña.", + "download": "Descargar Kit de emergencia" + }, + "change-language": "Cambiar idioma", + "api-keys": { + "title": "API Keys", + "description": "Gestiona tus API Keys personales para acceder a la API de Infisical.", + "add-new": "Añadir" + } + }, + "project": { + "title": "Configuración de proyecto", + "description": "Esta configuración solo afecta al proyecto seleccionado.", + "danger-zone": "Zona de peligro", + "delete-project": "Eliminar proyecto", + "project-to-delete": "Proyecto a eliminar", + "danger-zone-note": "Tan pronto como elimines el proyecto, no podrás volver atrás. Esto eliminará todas las claves. Si aún quieres hacerlo, introduce el nombre del proyecto a continuación.", + "delete-project-note": "Nota: Solo puedes eliminar un proyecto si tienes más de uno", + "project-id-description": "Para integrar Infisical en tu aplicación y obtener la inyección automática de variables de entorno, debes usar el siguiente ID de Proyecto.", + "project-id-description2": "Para más guías, incluyendo ejemplos de código en diferentes lenguajes y frameworks, visita ", + "auto-generated": "Este es el ID único y autogenerado de proyecto. No se puede modificar.", + "docs": "Documentación de Infisical", + "auto-capitalization": "Mayúsculas automáticas", + "auto-capitalization-description": "De acuerdo con los estándares, Infisical pondrá en mayúsculas tus claves. Si quieres desactivar esta funcionalidad, lo puedes hacer aquí." + } + }, + "signup": { + "title": "Registrarse", + "og-title": "Reemplaza los archivos .env con una línea de código. Regístrate en Infisical en solo 3 minutos.", + "og-description": "Infisical es una plataforma sencilla cifrada de extremo a extremo que permite a equipos sincronizar y gestionar API-keys y variables de entorno. Funciona con Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Registrarse", + "already-have-account": "¿Ya tienes una cuenta? Inicia sesión", + "forgot-password": "¿Has olvidado tu contraseña?", + "verify": "Verificar", + "step1-start": "Vamos a empezar", + "step1-privacy": "Al crear la cuenta, aceptas nuestros Términos y has leído y comprendido nuestra Política de privacidad.", + "step1-submit": "Empezar", + "step2-message": "Hemos enviado un código a", + "step2-code-error": "Oops. Tu código es incorrecto. Intentos restantes:", + "step2-resend-alert": "¿No ves el código?", + "step2-resend-submit": "Volver a enviar", + "step2-resend-progress": "Reenviando...", + "step2-spam-alert": "Asegúrate de comprobar la carpeta de spam.", + "step3-message": "¡Casi hemos terminado!", + "step4-message": "Guarda tu Kit de emergencia", + "step4-description1": "Si pierdes el acceso a tu cuenta, tu Kit de emergencia es la única forma de iniciar sesión.", + "step4-description2": "Te recomendamos que lo descargues y lo guardes en un sitio seguro.", + "step4-description3": "Contiene tu Clave secreta, a la que no tenemos acceso y tampoco podemos recuperar si la pierdes.", + "step4-download": "Descargar PDF", + "step5-send-invites": "Enviar invitaciones", + "step5-invite-team": "Invita a tu equipo", + "step5-subtitle": "Infisical está pensado para usarlo con tus compañeros. Invítalos a probarlo.", + "step5-skip": "Saltar" + } +} diff --git a/frontend/public/locales/fr/activity.json b/frontend/public/locales/fr/activity.json deleted file mode 100644 index 4360d7d0c..000000000 --- a/frontend/public/locales/fr/activity.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "Journaux d'activité", - "subtitle": "Historique des événements pour ce projet Infisical.", - "event": { - "readSecrets": "Secrets Visualisés", - "updateSecrets": "Secrets Mis à jour", - "addSecrets": "Secrets Ajoutés", - "deleteSecrets": "Secrets Supprimés" - }, - "ip-address": "Adresse IP" -} diff --git a/frontend/public/locales/fr/billing.json b/frontend/public/locales/fr/billing.json deleted file mode 100644 index 1acb44339..000000000 --- a/frontend/public/locales/fr/billing.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Utilisation et Facturation", - "description": "Voir et gérer l'abonnement de votre organisation ici", - "subscription": "Abonnement", - "starter": { - "name": "Starter", - "price-explanation": "jusqu'à 5 membres de l'équipe", - "text": "Gérez n'importe quel projet jusqu'à 5 membres gratuitement!", - "subtext": "$5 par membre / mois par la suite." - }, - "professional": { - "name": "Professionnel", - "price-explanation": "/membre/mois", - "subtext": "Comprend des projets et des membres illimités.", - "text": "Suivez la gestion clé à mesure que vous grandissez." - }, - "enterprise": { - "name": "Entreprise", - "text": "Suivez la gestion clé à mesure que vous grandissez." - }, - "current-usage": "Utilisation actuelle", - "free": "Gratuit", - "downgrade": "Rétrograder", - "upgrade": "Améliorer", - "learn-more": "En savoir plus", - "custom-pricing": "Prix personnalisés", - "schedule-demo": "Planifier une démo" -} diff --git a/frontend/public/locales/fr/common.json b/frontend/public/locales/fr/common.json deleted file mode 100644 index 1f6a52447..000000000 --- a/frontend/public/locales/fr/common.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "head-title": "{{title}} | Infisical", - "error_project-already-exists": "Un projet avec ce nom existe déjà.", - "no-mobile": " Pour utiliser Infisical, veuillez vous connecter avec un appareil avec des dimensions plus grandes. ", - "email": "Email", - "password": "Mot de passe", - "first-name": "Prénom", - "last-name": "Nom", - "logout": "Déconnexion", - "validate-required": "Veuillez saisir votre {{name}}", - "maintenance-alert": "Nous rencontrons des difficultés techniques mineures. Nous travaillons sur leurs résolution dès maintenant. Revenez dans quelques minutes.", - "click-to-copy": "Cliquez pour copiez", - "project-id": "Identifiant du Projet", - "save-changes": "Sauvegarder les modifications", - "saved": "Enregistrée", - "drop-zone": "Glissez et déposez un fichier .env ou .yml ici.", - "drop-zone-keys": "Glissez et déposez un fichier .env ou .yml ici pour ajouter plus de clés.", - "role": "Rôle", - "role_admin": "administrateur", - "display-name": "Nom d'affichage", - "environment": "Environnement", - "expired-in": "Expire dans", - "language": "Langue", - "search": "Recherche...", - "note": "Note", - "view-more": "Voir plus", - "end-of-history": "Fin de l'historique", - "select-event": "Sélectionnez un événement", - "event": "Événement", - "user": "Utilisateur", - "source": "Source", - "time": "Heure", - "timestamp": "Horodatage" -} \ No newline at end of file diff --git a/frontend/public/locales/fr/dashboard.json b/frontend/public/locales/fr/dashboard.json deleted file mode 100644 index f90bf1fc2..000000000 --- a/frontend/public/locales/fr/dashboard.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "title": "Secrets", - "og-title": "Gérez vos fichiers .env rapidement", - "og-description": "Infisical une plate-forme simple et chiffré de bout en bout qui permet aux équipes de synchroniser et de gérer leurs fichiers .env.", - "search-keys": "Recherche les clefs...", - "add-key": "Ajouter une clef", - "personal": "Personnel", - "personal-description": "Les clés personnelles ne sont visibles que pour vous", - "shared": "Partagé", - "shared-description": "Les clés partagées sont visibles à toute votre équipe", - "make-shared": "Rendre Partagé", - "make-personal": "Rendre Personnel", - "add-secret": "Ajouter un nouveau secret", - "check-docs": { - "button": "Vérifier la documentation", - "title": "Bon travail!", - "line1": "Félicitations pour avoir ajouté plus de secrets.", - "line2": "Voici comment les connecter à votre base de code." - }, - "sidebar": { - "secret": "Secret", - "key": "Clef", - "value": "Valeur", - "override": "Remplacer la valeur avec une valeur personnelle", - "version-history": "Historique des versions", - "comments": "Commentaires & Notes", - "personal-explanation": "Ce secret est personnel. Il n'est partagé avec aucun de vos coéquipiers.", - "generate-random-hex": "Générer un Hex aléatoire", - "digits": "chiffres", - "delete-key-dialog": { - "title": "Supprimer la clef", - "confirm-delete-message": "Êtes-vous sûr de vouloir supprimer ce secret? Cela ne peut pas être annulé." - } - } - -} diff --git a/frontend/public/locales/fr/integrations.json b/frontend/public/locales/fr/integrations.json deleted file mode 100644 index 887e79dfd..000000000 --- a/frontend/public/locales/fr/integrations.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Intégrations de Projet", - "description": "Gérez vos intégrations d'Infisical avec des services tiers.", - "no-integrations1": "Vous n'avez pas encore d'intégration. Quand vous en aurez, elles apparaîtront ici.", - "no-integrations2": "Pour commencer, cliquez sur l'une des options ci-dessous. La configuration se fait en 5 clics.", - "available": "Intégrations de plate-forme et cloud", - "available-text1": "Cliquez sur l'intégration que vous souhaitez connecter. Cela permettra à vos variables d'environnement de circuler automatiquement dans les services tiers sélectionnés.", - "available-text2": "Remarque: Lors d'une intégration avec Heroku, pour des raisons de sécurité, il est impossible de maintenir le chiffrage de bout en bout. En théorie, cela permet à Infisical de déchiffrer les variables d'environnement. En pratique, nous pouvons vous assurer que cela ne sera jamais fait, et cela nous permet de protéger vos secrets des mauvais acteurs en ligne. Le service Infisical de base restera toujours chiffré de bout en bout. Pour toutes vos intérogations, contactez support@infisical.com.", - "cloud-integrations": "Intégrations Cloud", - "framework-integrations": "Intégrations Framework", - "click-to-start": "Cliquez sur une intégration pour commencer à synchroniser les secrets avec elle.", - "click-to-setup": "Cliquez sur un framework pour obtenir les instructions de configuration.", - "grant-access-to-secrets": "Accordez un accès Infisical à vos secrets", - "why-infisical-needs-access": "La plupart des intégrations cloud nécessitent qu'Infisical puisse déchiffrer vos secrets afin qu'ils puissent être transmis.", - "grant-access-button": "Autoriser l'accès" -} diff --git a/frontend/public/locales/fr/login.json b/frontend/public/locales/fr/login.json deleted file mode 100644 index 8c93da9fb..000000000 --- a/frontend/public/locales/fr/login.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "Connexion", - "og-title": "Connectez-vous à Infisical", - "og-description": "Infisical, une plate-forme simple et chiffré de bout en bout permettant aux équipes de synchroniser et de gérer leurs fichiers .env.", - "login": "Se connecter", - "need-account": "Besoin d'un compte Infisical?", - "create-account": "Créer un compte", - "forgot-password": "Mot de passe oublié?", - "error-login": "Mauvais identifiants." -} diff --git a/frontend/public/locales/fr/mfa.json b/frontend/public/locales/fr/mfa.json deleted file mode 100644 index 60e3201ed..000000000 --- a/frontend/public/locales/fr/mfa.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "S'inscrire", - "og-title": "Remplacez les fichiers .env par 1 ligne de code. Inscrivez-vous à Infisical en 3 minutes.", - "og-description": "Infisical, une plate-forme simple et chiffré de bout en bout qui permet aux équipes de synchroniser et de gérer des clefs API et des variables d'environnement. Fonctionne avec Node.js, Next.js, Gatsby, Nest.js ...", - "signup": "S'inscrire", - "already-have-account": "Déjà inscris? Se connecter", - "forgot-password": "Mot de passe oublié?", - "verify": "Vérifier", - "step1-start": "Bon, on commence!", - "step1-privacy": "En créant votre compte, vous acceptez nos conditions et avez lu et reconnu notre politique de confidentialité.", - "step1-submit": "C'est parti", - "step2-message": "Nous avons envoyé un email de vérification à", - "step2-code-error": "Oops. Votre code est faux. Essais restants:", - "step2-resend-alert": "Vous ne voyez pas le code?", - "step2-resend-submit": "Renvoyer", - "step2-resend-progress": "Envoie en cours...", - "step2-spam-alert": "Assurez-vous de vérifier vos spams.", - "step3-message": "Nous y sommes presque!", - "step4-message": "Enregistrez votre kit d'urgence", - "step4-description1": "Si vous n'arrivez plus à vous connecter à votre compte, votre kit d'urgence est le seul moyen d'y arriver.", - "step4-description2": "Nous vous recommandons de le télécharger et de le garder en sécurité.", - "step4-description3": "Il contient votre clef secrète que nous ne pouvons pas récupérer pour vous si vous la perdez.", - "step4-download": "Téléchargez le PDF", - "step5-send-invites": "Envoyer les invitations", - "step5-invite-team": "Invitez votre équipe", - "step5-subtitle": "Infisical a pour but d'être utilisé avec vos coéquipiers. Invitez-les à le tester.", - "step5-skip": "Passer" -} diff --git a/frontend/public/locales/fr/nav.json b/frontend/public/locales/fr/nav.json deleted file mode 100644 index 1fda27af9..000000000 --- a/frontend/public/locales/fr/nav.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "support": { - "slack": "[NEW] Rejoignez le forum Slack", - "docs": "Lire les documentations", - "issue": "Ouvrir une issue Github", - "email": "Envoyez-nous un email" - }, - "user": { - "signed-in-as": "CONNECTÉ EN TANT QUE", - "current-organization": "ORGANISATION ACTUELLE", - "usage-billing": "Utilisation & Facturation", - "invite": "Inviter des membres", - "other-organizations": "AUTRE ORGANISATION" - }, - "menu": { - "project": "PROJET", - "secrets": "Secrets", - "members": "Membres", - "integrations": "Intégrations", - "project-settings": "Paramètres du Projet" - } -} diff --git a/frontend/public/locales/fr/section-incident.json b/frontend/public/locales/fr/section-incident.json deleted file mode 100644 index 95b77ea13..000000000 --- a/frontend/public/locales/fr/section-incident.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "incident-contacts": "Contacts Incidents", - "incident-contacts-description": "Ces contacts seront informés dans le cas improbable d'un incident grave.", - "no-incident-contacts": "Aucun contact incident trouvé.", - "add-contact": "Ajouter un contact", - "add-dialog": { - "title": "Ajouter un contact incident", - "description": "Ce contact sera informé dans le cas improbable d'un incident grave.", - "add-incident": "Ajouter un contact incident" - } -} diff --git a/frontend/public/locales/fr/section-members.json b/frontend/public/locales/fr/section-members.json deleted file mode 100644 index 8faed80e7..000000000 --- a/frontend/public/locales/fr/section-members.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "add-member": "Ajouter un Membre", - "org-members": "Membres de l'organisation", - "org-members-description": "Gérer les membres de votre organisation. Ces utilisateurs pourraient ensuite être répartis en projets.", - "search-members": "Recherche des membres...", - "add-dialog": { - "add-member-to-project": "Ajoutez un membre à votre projet", - "already-all-invited": "Tous les utilisateurs de votre organisation sont déjà invités.", - "add-user-org-first": "Ajoutez d'abord plus d'utilisateurs à l'organisation.", - "user-will-email": "L'utilisateur recevra un email avec les instructions.", - "looking-add": "<0>Si vous cherchez à ajouter des utilisateurs à votre organisation,<1>cliquez ici", - "add-user-to-org": "Ajouter des Utilisateurs à l'Organisation" - } -} diff --git a/frontend/public/locales/fr/section-password.json b/frontend/public/locales/fr/section-password.json deleted file mode 100644 index 0928233e6..000000000 --- a/frontend/public/locales/fr/section-password.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "password": "Mot de passe", - "change": "Changer le mot de passe", - "current": "Mot de passe actuel", - "current-wrong": "Le mot de passe actuel peut être érroné", - "new": "Nouveau mot de passe", - "validate-base": "Le mot de passe doit contenir au moins:", - "validate-length": "14 caractères", - "validate-case": "1 caractère miniscule", - "validate-number": "1 chiffre" -} diff --git a/frontend/public/locales/fr/section-token.json b/frontend/public/locales/fr/section-token.json deleted file mode 100644 index 1f2a3b233..000000000 --- a/frontend/public/locales/fr/section-token.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "service-tokens": "Jetons de service", - "service-tokens-description": "Chaque jeton de service vous est spécifique, à un certain projet et à un certain environnement dans ce projet.", - "add-new": "Ajouter un nouveau jeton", - "add-dialog": { - "title": "Ajouter un jeton de service pour {{target}}", - "description": "Spécifiez le nom, l'environnement et la période d'expiration. Lorsqu'un jeton est généré, vous ne pourrez le voir qu'une seule fois avant qu'il ne disparaisse. Assurez-vous de le sauvegarder quelque part.", - "name": "Nom du jeton de service", - "add": "Ajouter un jeton de service", - "copy-service-token": "Copiez votre jeton de service", - "copy-service-token-description": "Une fois que vous aurez fermé cette fenêtre, vous ne reverrez plus jamais votre jeton de service" - } -} diff --git a/frontend/public/locales/fr/settings-members.json b/frontend/public/locales/fr/settings-members.json deleted file mode 100644 index 9f34c7a68..000000000 --- a/frontend/public/locales/fr/settings-members.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Membres du projet", - "description": "Cette page affiche les membres du projet sélectionné." -} diff --git a/frontend/public/locales/fr/settings-org.json b/frontend/public/locales/fr/settings-org.json deleted file mode 100644 index 952bd68c8..000000000 --- a/frontend/public/locales/fr/settings-org.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Paramètres d'Organisation", - "description": "Gérer les membres de votre organisation. Ces utilisateurs pourraient ensuite être répartis en projets." -} diff --git a/frontend/public/locales/fr/settings-personal.json b/frontend/public/locales/fr/settings-personal.json deleted file mode 100644 index 30a3d6fa3..000000000 --- a/frontend/public/locales/fr/settings-personal.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "Paramètres Personnels", - "description": "Consultez et gérez vos informations personnelles ici.", - "emergency": { - "name": "Kit d'urgence", - "text1": "Votre kit d'urgence contient les informations dont vous aurez besoin pour vous connecter à votre compte Infisical.", - "text2": "Seul le dernier kit d'urgence émis reste valide. Pour obtenir un nouveau kit d'urgence, vérifiez votre mot de passe.", - "download": "Télécharger le kit d'urgence" - }, - "change-language": "Changer de langue" -} diff --git a/frontend/public/locales/fr/settings-project.json b/frontend/public/locales/fr/settings-project.json deleted file mode 100644 index a5a3f1ee3..000000000 --- a/frontend/public/locales/fr/settings-project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Paramètres du Projet", - "description": "Ces paramètres ne s'appliquent qu'au Projet actuellement sélectionné.", - "danger-zone": "Zone de danger", - "delete-project": "Supprimer le Projet", - "project-to-delete": "Projet à Supprimer", - "danger-zone-note": "Dès que vous supprimez ce projet, vous ne pourrez plus revenir en arrière. Cela supprimera immédiatement toutes les clefs. Si vous voulez toujours le faire, veuillez saisir le nom du projet ci-dessous.", - "delete-project-note": "Remarque: Vous ne pouvez supprimer qu'un projet que si vous en avez plus d'un.", - "project-id-description": "Pour intégrer Infisical dans votre base de code et obtenir une injection automatique de variables d'environnement, vous devez utiliser l'ID du projet suivant.", - "project-id-description2": "Pour plus de conseils, y compris des extraits de code pour diverses langues et frameworks, voir ", - "auto-generated": "Ceci est l'identifiant unique généré automatiquement pour votre projet. Il ne peut pas être modifié.", - "docs": "Documentation Infisical" -} diff --git a/frontend/public/locales/fr/signup.json b/frontend/public/locales/fr/signup.json deleted file mode 100644 index 63d869193..000000000 --- a/frontend/public/locales/fr/signup.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "S'inscrire", - "og-title": "Remplacez les fichiers .env par 1 ligne de code. Inscrivez-vous à Infisical en 3 minutes.", - "og-description": "Infisical, une plate-forme simple et chiffré de bout en bout qui permet aux équipes de synchroniser et de gérer des clefs API et des variables d'environnement. Fonctionne avec Node.js, Next.js, Gatsby, Nest.js ...", - "signup": "S'inscrire", - "already-have-account": "Déjà inscris? Se connecter", - "forgot-password": "Mot de passe oublié?", - "verify": "Vérifier", - "step1-start": "Bon, on commence!", - "step1-privacy": "En créant votre compte, vous acceptez nos conditions et avez lu et reconnu notre politique de confidentialité.", - "step1-submit": "C'est parti", - "step2-message": "Nous avons envoyé un email de vérification à", - "step2-code-error": "Oops. Votre code est faux. Veuillez réessayer.", - "step2-resend-alert": "Vous ne voyez pas le code?", - "step2-resend-submit": "Renvoyer", - "step2-resend-progress": "Envoie en cours...", - "step2-spam-alert": "Assurez-vous de vérifier vos spams.", - "step3-message": "Nous y sommes presque!", - "step4-message": "Enregistrez votre kit d'urgence", - "step4-description1": "Si vous n'arrivez plus à vous connecter à votre compte, votre kit d'urgence est le seul moyen d'y arriver.", - "step4-description2": "Nous vous recommandons de le télécharger et de le garder en sécurité.", - "step4-description3": "Il contient votre clef secrète que nous ne pouvons pas récupérer pour vous si vous la perdez.", - "step4-download": "Téléchargez le PDF", - "step5-send-invites": "Envoyer les invitations", - "step5-invite-team": "Invitez votre équipe", - "step5-subtitle": "Infisical a pour but d'être utilisé avec vos coéquipiers. Invitez-les à le tester.", - "step5-skip": "Passer" -} diff --git a/frontend/public/locales/fr/translations.json b/frontend/public/locales/fr/translations.json new file mode 100644 index 000000000..6914e7ea1 --- /dev/null +++ b/frontend/public/locales/fr/translations.json @@ -0,0 +1,299 @@ +{ + "activity": { + "title": "Journaux d'activité", + "subtitle": "Historique des événements pour ce projet Infisical.", + "event": { + "readSecrets": "Secrets Visualisés", + "updateSecrets": "Secrets Mis à jour", + "addSecrets": "Secrets Ajoutés", + "deleteSecrets": "Secrets Supprimés" + }, + "ip-address": "Adresse IP" + }, + "billing": { + "title": "Utilisation et Facturation", + "description": "Voir et gérer l'abonnement de votre organisation ici", + "subscription": "Abonnement", + "starter": { + "name": "Starter", + "price-explanation": "jusqu'à 5 membres de l'équipe", + "text": "Gérez n'importe quel projet jusqu'à 5 membres gratuitement!", + "subtext": "$5 par membre / mois par la suite." + }, + "professional": { + "name": "Professionnel", + "price-explanation": "/membre/mois", + "subtext": "Comprend des projets et des membres illimités.", + "text": "Suivez la gestion clé à mesure que vous grandissez." + }, + "enterprise": { + "name": "Entreprise", + "text": "Suivez la gestion clé à mesure que vous grandissez." + }, + "current-usage": "Utilisation actuelle", + "free": "Gratuit", + "downgrade": "Rétrograder", + "upgrade": "Améliorer", + "learn-more": "En savoir plus", + "custom-pricing": "Prix personnalisés", + "schedule-demo": "Planifier une démo" + }, + "common": { + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "Un projet avec ce nom existe déjà.", + "no-mobile": " Pour utiliser Infisical, veuillez vous connecter avec un appareil avec des dimensions plus grandes. ", + "email": "Email", + "password": "Mot de passe", + "first-name": "Prénom", + "last-name": "Nom", + "logout": "Déconnexion", + "validate-required": "Veuillez saisir votre {{name}}", + "maintenance-alert": "Nous rencontrons des difficultés techniques mineures. Nous travaillons sur leurs résolution dès maintenant. Revenez dans quelques minutes.", + "click-to-copy": "Cliquez pour copiez", + "project-id": "Identifiant du Projet", + "save-changes": "Sauvegarder les modifications", + "saved": "Enregistrée", + "drop-zone": "Glissez et déposez un fichier .env ou .yml ici.", + "drop-zone-keys": "Glissez et déposez un fichier .env ou .yml ici pour ajouter plus de clés.", + "role": "Rôle", + "role_admin": "administrateur", + "display-name": "Nom d'affichage", + "environment": "Environnement", + "expired-in": "Expire dans", + "language": "Langue", + "search": "Recherche...", + "note": "Note", + "view-more": "Voir plus", + "end-of-history": "Fin de l'historique", + "select-event": "Sélectionnez un événement", + "event": "Événement", + "user": "Utilisateur", + "source": "Source", + "time": "Heure", + "timestamp": "Horodatage" + }, + "dashboard": { + "title": "Secrets", + "og-title": "Gérez vos fichiers .env rapidement", + "og-description": "Infisical une plate-forme simple et chiffré de bout en bout qui permet aux équipes de synchroniser et de gérer leurs fichiers .env.", + "search-keys": "Recherche les clefs...", + "add-key": "Ajouter une clef", + "personal": "Personnel", + "personal-description": "Les clés personnelles ne sont visibles que pour vous", + "shared": "Partagé", + "shared-description": "Les clés partagées sont visibles à toute votre équipe", + "make-shared": "Rendre Partagé", + "make-personal": "Rendre Personnel", + "add-secret": "Ajouter un nouveau secret", + "check-docs": { + "button": "Vérifier la documentation", + "title": "Bon travail!", + "line1": "Félicitations pour avoir ajouté plus de secrets.", + "line2": "Voici comment les connecter à votre base de code." + }, + "sidebar": { + "secret": "Secret", + "key": "Clef", + "value": "Valeur", + "override": "Remplacer la valeur avec une valeur personnelle", + "version-history": "Historique des versions", + "comments": "Commentaires & Notes", + "personal-explanation": "Ce secret est personnel. Il n'est partagé avec aucun de vos coéquipiers.", + "generate-random-hex": "Générer un Hex aléatoire", + "digits": "chiffres", + "delete-key-dialog": { + "title": "Supprimer la clef", + "confirm-delete-message": "Êtes-vous sûr de vouloir supprimer ce secret? Cela ne peut pas être annulé." + } + } + }, + "integrations": { + "title": "Intégrations de Projet", + "description": "Gérez vos intégrations d'Infisical avec des services tiers.", + "no-integrations1": "Vous n'avez pas encore d'intégration. Quand vous en aurez, elles apparaîtront ici.", + "no-integrations2": "Pour commencer, cliquez sur l'une des options ci-dessous. La configuration se fait en 5 clics.", + "available": "Intégrations de plate-forme et cloud", + "available-text1": "Cliquez sur l'intégration que vous souhaitez connecter. Cela permettra à vos variables d'environnement de circuler automatiquement dans les services tiers sélectionnés.", + "available-text2": "Remarque: Lors d'une intégration avec Heroku, pour des raisons de sécurité, il est impossible de maintenir le chiffrage de bout en bout. En théorie, cela permet à Infisical de déchiffrer les variables d'environnement. En pratique, nous pouvons vous assurer que cela ne sera jamais fait, et cela nous permet de protéger vos secrets des mauvais acteurs en ligne. Le service Infisical de base restera toujours chiffré de bout en bout. Pour toutes vos intérogations, contactez support@infisical.com.", + "cloud-integrations": "Intégrations Cloud", + "framework-integrations": "Intégrations Framework", + "click-to-start": "Cliquez sur une intégration pour commencer à synchroniser les secrets avec elle.", + "click-to-setup": "Cliquez sur un framework pour obtenir les instructions de configuration.", + "grant-access-to-secrets": "Accordez un accès Infisical à vos secrets", + "why-infisical-needs-access": "La plupart des intégrations cloud nécessitent qu'Infisical puisse déchiffrer vos secrets afin qu'ils puissent être transmis.", + "grant-access-button": "Autoriser l'accès" + }, + "login": { + "title": "Connexion", + "og-title": "Connectez-vous à Infisical", + "og-description": "Infisical, une plate-forme simple et chiffré de bout en bout permettant aux équipes de synchroniser et de gérer leurs fichiers .env.", + "login": "Se connecter", + "need-account": "Besoin d'un compte Infisical?", + "create-account": "Créer un compte", + "forgot-password": "Mot de passe oublié?", + "error-login": "Mauvais identifiants." + }, + "mfa": { + "title": "S'inscrire", + "og-title": "Remplacez les fichiers .env par 1 ligne de code. Inscrivez-vous à Infisical en 3 minutes.", + "og-description": "Infisical, une plate-forme simple et chiffré de bout en bout qui permet aux équipes de synchroniser et de gérer des clefs API et des variables d'environnement. Fonctionne avec Node.js, Next.js, Gatsby, Nest.js ...", + "signup": "S'inscrire", + "already-have-account": "Déjà inscris? Se connecter", + "forgot-password": "Mot de passe oublié?", + "verify": "Vérifier", + "step1-start": "Bon, on commence!", + "step1-privacy": "En créant votre compte, vous acceptez nos conditions et avez lu et reconnu notre politique de confidentialité.", + "step1-submit": "C'est parti", + "step2-message": "Nous avons envoyé un email de vérification à", + "step2-code-error": "Oops. Votre code est faux. Essais restants:", + "step2-resend-alert": "Vous ne voyez pas le code?", + "step2-resend-submit": "Renvoyer", + "step2-resend-progress": "Envoie en cours...", + "step2-spam-alert": "Assurez-vous de vérifier vos spams.", + "step3-message": "Nous y sommes presque!", + "step4-message": "Enregistrez votre kit d'urgence", + "step4-description1": "Si vous n'arrivez plus à vous connecter à votre compte, votre kit d'urgence est le seul moyen d'y arriver.", + "step4-description2": "Nous vous recommandons de le télécharger et de le garder en sécurité.", + "step4-description3": "Il contient votre clef secrète que nous ne pouvons pas récupérer pour vous si vous la perdez.", + "step4-download": "Téléchargez le PDF", + "step5-send-invites": "Envoyer les invitations", + "step5-invite-team": "Invitez votre équipe", + "step5-subtitle": "Infisical a pour but d'être utilisé avec vos coéquipiers. Invitez-les à le tester.", + "step5-skip": "Passer" + }, + "nav": { + "support": { + "slack": "[NEW] Rejoignez le forum Slack", + "docs": "Lire les documentations", + "issue": "Ouvrir une issue Github", + "email": "Envoyez-nous un email" + }, + "user": { + "signed-in-as": "CONNECTÉ EN TANT QUE", + "current-organization": "ORGANISATION ACTUELLE", + "usage-billing": "Utilisation & Facturation", + "invite": "Inviter des membres", + "other-organizations": "AUTRE ORGANISATION" + }, + "menu": { + "project": "PROJET", + "secrets": "Secrets", + "members": "Membres", + "integrations": "Intégrations", + "project-settings": "Paramètres du Projet" + } + }, + "section": { + "incident": { + "incident-contacts": "Contacts Incidents", + "incident-contacts-description": "Ces contacts seront informés dans le cas improbable d'un incident grave.", + "no-incident-contacts": "Aucun contact incident trouvé.", + "add-contact": "Ajouter un contact", + "add-dialog": { + "title": "Ajouter un contact incident", + "description": "Ce contact sera informé dans le cas improbable d'un incident grave.", + "add-incident": "Ajouter un contact incident" + } + }, + "members": { + "add-member": "Ajouter un Membre", + "org-members": "Membres de l'organisation", + "org-members-description": "Gérer les membres de votre organisation. Ces utilisateurs pourraient ensuite être répartis en projets.", + "search-members": "Recherche des membres...", + "add-dialog": { + "add-member-to-project": "Ajoutez un membre à votre projet", + "already-all-invited": "Tous les utilisateurs de votre organisation sont déjà invités.", + "add-user-org-first": "Ajoutez d'abord plus d'utilisateurs à l'organisation.", + "user-will-email": "L'utilisateur recevra un email avec les instructions.", + "looking-add": "<0>Si vous cherchez à ajouter des utilisateurs à votre organisation,<1>cliquez ici", + "add-user-to-org": "Ajouter des Utilisateurs à l'Organisation" + } + }, + "password": { + "password": "Mot de passe", + "change": "Changer le mot de passe", + "current": "Mot de passe actuel", + "current-wrong": "Le mot de passe actuel peut être érroné", + "new": "Nouveau mot de passe", + "validate-base": "Le mot de passe doit contenir au moins:", + "validate-length": "14 caractères", + "validate-case": "1 caractère miniscule", + "validate-number": "1 chiffre" + }, + "token": { + "service-tokens": "Jetons de service", + "service-tokens-description": "Chaque jeton de service vous est spécifique, à un certain projet et à un certain environnement dans ce projet.", + "add-new": "Ajouter un nouveau jeton", + "add-dialog": { + "title": "Ajouter un jeton de service pour {{target}}", + "description": "Spécifiez le nom, l'environnement et la période d'expiration. Lorsqu'un jeton est généré, vous ne pourrez le voir qu'une seule fois avant qu'il ne disparaisse. Assurez-vous de le sauvegarder quelque part.", + "name": "Nom du jeton de service", + "add": "Ajouter un jeton de service", + "copy-service-token": "Copiez votre jeton de service", + "copy-service-token-description": "Une fois que vous aurez fermé cette fenêtre, vous ne reverrez plus jamais votre jeton de service" + } + } + }, + "settings": { + "members": { + "title": "Membres du projet", + "description": "Cette page affiche les membres du projet sélectionné." + }, + "org": { + "title": "Paramètres d'Organisation", + "description": "Gérer les membres de votre organisation. Ces utilisateurs pourraient ensuite être répartis en projets." + }, + "personal": { + "title": "Paramètres Personnels", + "description": "Consultez et gérez vos informations personnelles ici.", + "emergency": { + "name": "Kit d'urgence", + "text1": "Votre kit d'urgence contient les informations dont vous aurez besoin pour vous connecter à votre compte Infisical.", + "text2": "Seul le dernier kit d'urgence émis reste valide. Pour obtenir un nouveau kit d'urgence, vérifiez votre mot de passe.", + "download": "Télécharger le kit d'urgence" + }, + "change-language": "Changer de langue" + }, + "project": { + "title": "Paramètres du Projet", + "description": "Ces paramètres ne s'appliquent qu'au Projet actuellement sélectionné.", + "danger-zone": "Zone de danger", + "delete-project": "Supprimer le Projet", + "project-to-delete": "Projet à Supprimer", + "danger-zone-note": "Dès que vous supprimez ce projet, vous ne pourrez plus revenir en arrière. Cela supprimera immédiatement toutes les clefs. Si vous voulez toujours le faire, veuillez saisir le nom du projet ci-dessous.", + "delete-project-note": "Remarque: Vous ne pouvez supprimer qu'un projet que si vous en avez plus d'un.", + "project-id-description": "Pour intégrer Infisical dans votre base de code et obtenir une injection automatique de variables d'environnement, vous devez utiliser l'ID du projet suivant.", + "project-id-description2": "Pour plus de conseils, y compris des extraits de code pour diverses langues et frameworks, voir ", + "auto-generated": "Ceci est l'identifiant unique généré automatiquement pour votre projet. Il ne peut pas être modifié.", + "docs": "Documentation Infisical" + } + }, + "signup": { + "title": "S'inscrire", + "og-title": "Remplacez les fichiers .env par 1 ligne de code. Inscrivez-vous à Infisical en 3 minutes.", + "og-description": "Infisical, une plate-forme simple et chiffré de bout en bout qui permet aux équipes de synchroniser et de gérer des clefs API et des variables d'environnement. Fonctionne avec Node.js, Next.js, Gatsby, Nest.js ...", + "signup": "S'inscrire", + "already-have-account": "Déjà inscris? Se connecter", + "forgot-password": "Mot de passe oublié?", + "verify": "Vérifier", + "step1-start": "Bon, on commence!", + "step1-privacy": "En créant votre compte, vous acceptez nos conditions et avez lu et reconnu notre politique de confidentialité.", + "step1-submit": "C'est parti", + "step2-message": "Nous avons envoyé un email de vérification à", + "step2-code-error": "Oops. Votre code est faux. Veuillez réessayer.", + "step2-resend-alert": "Vous ne voyez pas le code?", + "step2-resend-submit": "Renvoyer", + "step2-resend-progress": "Envoie en cours...", + "step2-spam-alert": "Assurez-vous de vérifier vos spams.", + "step3-message": "Nous y sommes presque!", + "step4-message": "Enregistrez votre kit d'urgence", + "step4-description1": "Si vous n'arrivez plus à vous connecter à votre compte, votre kit d'urgence est le seul moyen d'y arriver.", + "step4-description2": "Nous vous recommandons de le télécharger et de le garder en sécurité.", + "step4-description3": "Il contient votre clef secrète que nous ne pouvons pas récupérer pour vous si vous la perdez.", + "step4-download": "Téléchargez le PDF", + "step5-send-invites": "Envoyer les invitations", + "step5-invite-team": "Invitez votre équipe", + "step5-subtitle": "Infisical a pour but d'être utilisé avec vos coéquipiers. Invitez-les à le tester.", + "step5-skip": "Passer" + } +} \ No newline at end of file diff --git a/frontend/public/locales/ko/billing.json b/frontend/public/locales/ko/billing.json deleted file mode 100644 index 788afa8e4..000000000 --- a/frontend/public/locales/ko/billing.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "요금제 & 결제", - "description": "이곳에서 조직의 구독을 확인하고 관리할 수 있어요.", - "subscription": "구독", - "starter": { - "name": "스타터", - "price-explanation": "5명의 팀 맴버까지", - "text": "어떤 프로젝트든 다섯명의 맴버까지 무료로 이용할 수 있어요!", - "subtext": "$5명/달 로 바뀔 예정입니다." - }, - "professional": { - "name": "전문가", - "price-explanation": "/맴버/달", - "subtext": "무제한의 프로젝트와 맴버", - "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." - }, - "enterprise": { - "name": "엔터프라이즈", - "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." - }, - "current-usage": "현재 요금제", - "free": "무료", - "downgrade": "다운그레이드", - "upgrade": "업그레이드", - "learn-more": "자세히 알아보기", - "custom-pricing": "커스텀 가격", - "schedule-demo": "데모 예약하기" -} diff --git a/frontend/public/locales/ko/common.json b/frontend/public/locales/ko/common.json deleted file mode 100644 index f0692ebf7..000000000 --- a/frontend/public/locales/ko/common.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "head-title": "{{title}} | Infisical", - "error_project-already-exists": "동일한 이름을 가진 프로젝트가 이미 존재해요.", - "no-mobile": " Infisical을 사용하려면, 큰 화면을 가진 디바이스로 로그인하여 주세요.", - "email": "메일", - "password": "비밀번호", - "first-name": "이름", - "last-name": "성", - "logout": "로그아웃", - "validate-required": "{{name}} 을/를 입력하세요.", - "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", - "click-to-copy": "클릭하여 복사하기", - "project-id": "프로젝트 ID", - "save-changes": "변경사항 저장하기", - "saved": "저장됨", - "drop-zone": ".env 파일을 이곳에 드래그 & 드롭 하세요.", - "drop-zone-keys": "이곳에 .env 파일을 드래그 & 드롭 하여 더 많은 키들을 추가하세요.", - "role": "Role", - "role_admin": "admin", - "display-name": "표시 이름", - "environment": "환경", - "expired-in": "만료 기한:", - "language": "언어", - "search": "검색하기...", - "note": "Note" -} \ No newline at end of file diff --git a/frontend/public/locales/ko/dashboard.json b/frontend/public/locales/ko/dashboard.json deleted file mode 100644 index 73fcf155b..000000000 --- a/frontend/public/locales/ko/dashboard.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "title": "시크릿", - "og-title": "빠르게 .env 파일을 관리하세요", - "og-description": "Infisical은 팀원과 .env파일을 공유할 수 있는 심플한 end-to-end 암호화 플렛폼입니다.", - "search-keys": "키 검색하기...", - "add-key": "키 추가하기", - "personal": "개인", - "personal-description": "개인 키는 오직 본인만 볼 수 있어요", - "shared": "공유", - "shared-description": "공유 키는 팀 전체가 볼 수 있어요", - "make-shared": "공유로 만들기", - "make-personal": "개인으로 만들기", - "check-docs": { - "button": "문서 확인하기", - "title": "좋았어요!", - "line1": "더 많은 시크릿들을 추가한 것을 축하합니다.", - "line2": "코드와 연결하는 사용하는 방법을 한번 알아보지 않을래요?" - }, - "sidebar": { - "secret": "Secret", - "key": "Key", - "value": "Value", - "override": "Override value with a personal value", - "version-history": "Version History", - "comments": "Comments & Notes", - "personal-explanation": "This secret is personal. It is not shared with any of your teammates.", - "generate-random-hex": "Generate Random Hex", - "digits": "digits" - } -} diff --git a/frontend/public/locales/ko/integrations.json b/frontend/public/locales/ko/integrations.json deleted file mode 100644 index 7431831ae..000000000 --- a/frontend/public/locales/ko/integrations.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "available": "사용 가능한 연동", - "available-text1": "연결하고 싶은 서비스를 클릭하세요. 환경 변수가 선택한 외부 서비스와 자동으로 연동됩니다.", - "available-text2": "참고: Heroku와의 연동에서는 보안상의 이유로 End-To-End 암호화를 유지하는 것이 불가능합니다. 이론적으로는 Infisical이 시크릿을 읽는것이 가능하지만, 절대 그러지 않는다고 확신할 수 있습니다. 핵심 Infisical 서비스는 항상 End-To-End 암호화 상태를 유지합니다. 질문이 있으면 support@infisical.com으로 문의하세요.", - "description": "외부 서비스와 함께 Infisical을 연동하고 관리하세요", - "no-integrations1": "연동된 서비스가 없어요. 연동하게 된다면 이곳에서 표시돼요.", - "no-integrations2": "시작하려면, 아래의 옵션을 클릭하세요. 대체로 5분 이내로 가능해요.", - "title": "프로젝트 연동", - "cloud-integrations": "Cloud Integrations", - "framework-integrations": "Framework Integrations", - "click-to-start": "Click on an integration to begin syncing secrets to it.", - "click-to-setup": "Click on a framework to get the setup instructions.", - "grant-access-to-secrets": "Grant Infisical access to your secrets", - "why-infisical-needs-access": "Most cloud integrations require Infisical to be able to decrypt your secrets so they can be forwarded over.", - "grant-access-button": "Grant access" -} diff --git a/frontend/public/locales/ko/login.json b/frontend/public/locales/ko/login.json deleted file mode 100644 index 70a77d69f..000000000 --- a/frontend/public/locales/ko/login.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "title": "로그인", - "og-title": "Infisical에 로그인하기", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", - "login": "로그인", - "need-account": "Infisical계정이 필요하신가요?", - "create-account": "회원가입 하기" -} diff --git a/frontend/public/locales/ko/mfa.json b/frontend/public/locales/ko/mfa.json deleted file mode 100644 index 6c17a68cf..000000000 --- a/frontend/public/locales/ko/mfa.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "title": "회원가입", - "og-title": "한줄의 코드르 .env파일을 교체하세요. 3분이면 가입할 수 있어요.", - "og-description": "Infisical은 팀원과 .env파일을 공유하고 연동할 수 있는 심플한 end-to-end 암호화 플렛폼입니다. Node.js, Next.js, Gatsby, Nest.js 와 같은 다양한 플렛폼에서 작동해요.", - "signup": "회원가입", - "already-have-account": "이미 계정이 있나요? 로그인하기", - "forgot-password": "비밀번호를 잊으셨나요?", - "verify": "인증", - "step1-start": "시작하기", - "step1-privacy": "회원가입시 약관과 개인 정보 보호 정책을 읽고 동의한 것으로 간주합니다.", - "step1-submit": "시작하기", - "step2-message": "{{email}}로 인증 메일을 전송하였습니다{{email}}", - "step2-code-error": "코드가 잘못된 것 같아요. 남은 시도:", - "step2-spam-alert": "스팸함에 메일이 있지는 않은지 확인하세요", - "step3-message": "거의다 끝났어요!", - "step4-message": "긴급복구 키트 저장하기", - "step4-description1": "계정이 잠겼을 경우 비상 키트를 사용하여 로그인할 수 있어요.", - "step4-description2": "다운로드 후 안전한 곳에 보관하는 것을 추천합니다.", - "step4-description3": "분실시 접근하거나 복구할 수 없는 시크릿 키가 포함되어 있어요.", - "step4-download": "PDF 다운로드" -} diff --git a/frontend/public/locales/ko/nav.json b/frontend/public/locales/ko/nav.json deleted file mode 100644 index b07510ff4..000000000 --- a/frontend/public/locales/ko/nav.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "support": { - "slack": "[NEW] 슬랙 포럼에 가입하기", - "docs": "문서 보기", - "issue": "깃허브 이슈 열기", - "email": "Infisical팀에게 메일 보내기" - }, - "user": { - "signed-in-as": "다음으로 로그인됨", - "current-organization": "현재 조직", - "usage-billing": "요금제 & 결제", - "invite": "맴버 초대하기", - "other-organizations": "다른 조직" - }, - "menu": { - "project": "프로젝트", - "secrets": "시크릿", - "members": "맴버", - "integrations": "연동", - "project-settings": "프로젝트 설정" - } -} diff --git a/frontend/public/locales/ko/section-incident.json b/frontend/public/locales/ko/section-incident.json deleted file mode 100644 index cbafc5ecb..000000000 --- a/frontend/public/locales/ko/section-incident.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "add-contact": "연락처 추가하기", - "add-dialog": { - "add-incident": "비상 연락처 추가하기", - "description": "중대한 일이 생길 경우, 이 연락처로 알림이 전송됩니다.", - "title": "비상 연락처 추가하기" - }, - "incident-contacts": "비상 연락망", - "incident-contacts-description": "중대한 일이 생길 경우, 아래의 연락처로 알림이 전송됩니다.", - "no-incident-contacts": "비상 연락망이 존재하지 않아요." -} diff --git a/frontend/public/locales/ko/section-members.json b/frontend/public/locales/ko/section-members.json deleted file mode 100644 index 848574aff..000000000 --- a/frontend/public/locales/ko/section-members.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "add-member": "맴버 추가하기", - "org-members": "조직 맴버", - "search-members": "맴버를 검색하기...", - "add-dialog": { - "add-member-to-project": "프로젝트에 맴버 추가하기", - "already-all-invited": "조직의 모든 유저가 이미 초대되었습니다.", - "add-user-org-first": "유저를 먼저 조직에 추가해 주세요.", - "user-will-email": "유저는 안내가 포함된 메일을 받게 됩니다.", - "looking-add": "<0>조직에 유저를 추가하고 싶다면,<1>여기를 클릭하세요", - "add-user-to-org": "조직에 유저 추가하기" - }, - "org-members-description": "조직의 맴버들을 관리하세요." -} diff --git a/frontend/public/locales/ko/section-password.json b/frontend/public/locales/ko/section-password.json deleted file mode 100644 index e7c6a6b74..000000000 --- a/frontend/public/locales/ko/section-password.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "password": "비밀번호", - "change": "비밀번호 변경", - "current": "현재 비밀번호", - "new": "새 비밀번호", - "current-wrong": "현재 비밀번호가 잘못되었어요", - "validate-base": "비밀번호는 다음 조건을 만족해야 합니다:", - "validate-length": "14 글자 이상", - "validate-case": "1개 이상의 소문자", - "validate-number": "1개 이상의 숫자" -} diff --git a/frontend/public/locales/ko/section-token.json b/frontend/public/locales/ko/section-token.json deleted file mode 100644 index 936c6066c..000000000 --- a/frontend/public/locales/ko/section-token.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "add-dialog": { - "add": "서비스 토큰 추가하기", - "copy-service-token": "서비스 토큰 복사하기", - "copy-service-token-description": "팝업을 닫을 시 다시는 토큰을 확인할 수 없어요.", - "description": "이름, 환경, 만료일을 지정하세요. 토큰이 생성되면 최초 한번만 볼 수 있어요. 안전한 곳에 저장하세요.", - "name": "서비스 토큰 이름", - "title": "{{target}}의 토큰 추가하기" - }, - "add-new": "새 토큰 추가하기", - "service-tokens": "서비스 토큰", - "service-tokens-description": "모든 서비스 토큰은 프로젝트 및 환경에 따라 다릅니다." -} diff --git a/frontend/public/locales/ko/settings-members.json b/frontend/public/locales/ko/settings-members.json deleted file mode 100644 index 5954b2bb5..000000000 --- a/frontend/public/locales/ko/settings-members.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "맴버 설정", - "description": "선택한 프로젝트의 맴버를 확인하세요." -} diff --git a/frontend/public/locales/ko/settings-org.json b/frontend/public/locales/ko/settings-org.json deleted file mode 100644 index 64b5e5e3e..000000000 --- a/frontend/public/locales/ko/settings-org.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "조직 설정", - "description": "조직의 맴버를 관리하세요." -} diff --git a/frontend/public/locales/ko/settings-personal.json b/frontend/public/locales/ko/settings-personal.json deleted file mode 100644 index 2234272e4..000000000 --- a/frontend/public/locales/ko/settings-personal.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "개인 설정", - "description": "계정 및 기본적인 설정을 확인하고 변경하세요.", - "emergency": { - "name": "긴급복구 키트", - "text1": "긴급복구 키트는 Infisical계정에 로그인 할 수 있는 정보를 가지고 있어요.", - "text2": "오직 마지막으로 발급한 긴급복구 키트만 사용 가능해요. 새로운 긴급복구 키트를 받으려면, 비밀번호를 입력하세요.", - "download": "긴급복구 키트 다운로드" - }, - "change-language": "언어 변경하기" -} diff --git a/frontend/public/locales/ko/settings-project.json b/frontend/public/locales/ko/settings-project.json deleted file mode 100644 index 8dca5941c..000000000 --- a/frontend/public/locales/ko/settings-project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "프로젝트 설정", - "description": "현재 선택한 프로젝트에 대해서 설정해요.", - "auto-generated": "자동으로 생성된 고유한 키 입니다. 변경할 수 없어요.", - "danger-zone": "위험존", - "danger-zone-note": "프로젝트를 삭제한다면 모든 키가 즉시 삭제되며 다시는 되돌릴 수 없어요. 삭제를 원한다면 프로젝트 이름을 아래에 적어주세요.", - "delete-project": "프로젝트 삭제", - "delete-project-note": "노트: 최소 한개 이상의 프로젝트는 조직에 존재해야 해요.", - "docs": "Infisical 문서", - "project-id-description": "다른 코드에서 Infisical과 환경변수를 연동하기 위해서는 프로젝트 ID가 필요해요.", - "project-id-description2": "다양한 언어 및 프레임워크에 대한 가이드를 확인하고 싶다면, 다음을 확인하세요. ", - "project-to-delete": "삭제할 프로젝트" -} diff --git a/frontend/public/locales/ko/signup.json b/frontend/public/locales/ko/signup.json deleted file mode 100644 index 3b4576963..000000000 --- a/frontend/public/locales/ko/signup.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "title": "회원가입", - "og-title": "한줄의 코드르 .env파일을 교체하세요. 3분이면 가입할 수 있어요.", - "og-description": "Infisical은 팀원과 .env파일을 공유하고 연동할 수 있는 심플한 end-to-end 암호화 플렛폼입니다. Node.js, Next.js, Gatsby, Nest.js 와 같은 다양한 플렛폼에서 작동해요.", - "signup": "회원가입", - "already-have-account": "이미 계정이 있나요? 로그인하기", - "forgot-password": "비밀번호를 잊으셨나요?", - "verify": "인증", - "step1-start": "시작하기", - "step1-privacy": "회원가입시 약관과 개인 정보 보호 정책을 읽고 동의한 것으로 간주합니다.", - "step1-submit": "시작하기", - "step2-message": "{{email}}로 인증 메일을 전송하였습니다{{email}}", - "step2-code-error": "코드가 잘못된 것 같아요. 다시 시도해주세요.", - "step2-spam-alert": "스팸함에 메일이 있지는 않은지 확인하세요", - "step3-message": "거의다 끝났어요!", - "step4-message": "긴급복구 키트 저장하기", - "step4-description1": "계정이 잠겼을 경우 비상 키트를 사용하여 로그인할 수 있어요.", - "step4-description2": "다운로드 후 안전한 곳에 보관하는 것을 추천합니다.", - "step4-description3": "분실시 접근하거나 복구할 수 없는 시크릿 키가 포함되어 있어요.", - "step4-download": "PDF 다운로드" -} diff --git a/frontend/public/locales/ko/translations.json b/frontend/public/locales/ko/translations.json new file mode 100644 index 000000000..eea81f37e --- /dev/null +++ b/frontend/public/locales/ko/translations.json @@ -0,0 +1,259 @@ +{ + "billing": { + "title": "요금제 & 결제", + "description": "이곳에서 조직의 구독을 확인하고 관리할 수 있어요.", + "subscription": "구독", + "starter": { + "name": "스타터", + "price-explanation": "5명의 팀 맴버까지", + "text": "어떤 프로젝트든 다섯명의 맴버까지 무료로 이용할 수 있어요!", + "subtext": "$5명/달 로 바뀔 예정입니다." + }, + "professional": { + "name": "전문가", + "price-explanation": "/맴버/달", + "subtext": "무제한의 프로젝트와 맴버", + "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." + }, + "enterprise": { + "name": "엔터프라이즈", + "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." + }, + "current-usage": "현재 요금제", + "free": "무료", + "downgrade": "다운그레이드", + "upgrade": "업그레이드", + "learn-more": "자세히 알아보기", + "custom-pricing": "커스텀 가격", + "schedule-demo": "데모 예약하기" + }, + "common": { + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "동일한 이름을 가진 프로젝트가 이미 존재해요.", + "no-mobile": " Infisical을 사용하려면, 큰 화면을 가진 디바이스로 로그인하여 주세요.", + "email": "메일", + "password": "비밀번호", + "first-name": "이름", + "last-name": "성", + "logout": "로그아웃", + "validate-required": "{{name}} 을/를 입력하세요.", + "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", + "click-to-copy": "클릭하여 복사하기", + "project-id": "프로젝트 ID", + "save-changes": "변경사항 저장하기", + "saved": "저장됨", + "drop-zone": ".env 파일을 이곳에 드래그 & 드롭 하세요.", + "drop-zone-keys": "이곳에 .env 파일을 드래그 & 드롭 하여 더 많은 키들을 추가하세요.", + "role": "Role", + "role_admin": "admin", + "display-name": "표시 이름", + "environment": "환경", + "expired-in": "만료 기한:", + "language": "언어", + "search": "검색하기...", + "note": "Note" + }, + "dashboard": { + "title": "시크릿", + "og-title": "빠르게 .env 파일을 관리하세요", + "og-description": "Infisical은 팀원과 .env파일을 공유할 수 있는 심플한 end-to-end 암호화 플렛폼입니다.", + "search-keys": "키 검색하기...", + "add-key": "키 추가하기", + "personal": "개인", + "personal-description": "개인 키는 오직 본인만 볼 수 있어요", + "shared": "공유", + "shared-description": "공유 키는 팀 전체가 볼 수 있어요", + "make-shared": "공유로 만들기", + "make-personal": "개인으로 만들기", + "check-docs": { + "button": "문서 확인하기", + "title": "좋았어요!", + "line1": "더 많은 시크릿들을 추가한 것을 축하합니다.", + "line2": "코드와 연결하는 사용하는 방법을 한번 알아보지 않을래요?" + }, + "sidebar": { + "secret": "Secret", + "key": "Key", + "value": "Value", + "override": "Override value with a personal value", + "version-history": "Version History", + "comments": "Comments & Notes", + "personal-explanation": "This secret is personal. It is not shared with any of your teammates.", + "generate-random-hex": "Generate Random Hex", + "digits": "digits" + } + }, + "integrations": { + "available": "사용 가능한 연동", + "available-text1": "연결하고 싶은 서비스를 클릭하세요. 환경 변수가 선택한 외부 서비스와 자동으로 연동됩니다.", + "available-text2": "참고: Heroku와의 연동에서는 보안상의 이유로 End-To-End 암호화를 유지하는 것이 불가능합니다. 이론적으로는 Infisical이 시크릿을 읽는것이 가능하지만, 절대 그러지 않는다고 확신할 수 있습니다. 핵심 Infisical 서비스는 항상 End-To-End 암호화 상태를 유지합니다. 질문이 있으면 support@infisical.com으로 문의하세요.", + "description": "외부 서비스와 함께 Infisical을 연동하고 관리하세요", + "no-integrations1": "연동된 서비스가 없어요. 연동하게 된다면 이곳에서 표시돼요.", + "no-integrations2": "시작하려면, 아래의 옵션을 클릭하세요. 대체로 5분 이내로 가능해요.", + "title": "프로젝트 연동", + "cloud-integrations": "Cloud Integrations", + "framework-integrations": "Framework Integrations", + "click-to-start": "Click on an integration to begin syncing secrets to it.", + "click-to-setup": "Click on a framework to get the setup instructions.", + "grant-access-to-secrets": "Grant Infisical access to your secrets", + "why-infisical-needs-access": "Most cloud integrations require Infisical to be able to decrypt your secrets so they can be forwarded over.", + "grant-access-button": "Grant access" + }, + "login": { + "title": "로그인", + "og-title": "Infisical에 로그인하기", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "login": "로그인", + "need-account": "Infisical계정이 필요하신가요?", + "create-account": "회원가입 하기" + }, + "mfa": { + "title": "회원가입", + "og-title": "한줄의 코드르 .env파일을 교체하세요. 3분이면 가입할 수 있어요.", + "og-description": "Infisical은 팀원과 .env파일을 공유하고 연동할 수 있는 심플한 end-to-end 암호화 플렛폼입니다. Node.js, Next.js, Gatsby, Nest.js 와 같은 다양한 플렛폼에서 작동해요.", + "signup": "회원가입", + "already-have-account": "이미 계정이 있나요? 로그인하기", + "forgot-password": "비밀번호를 잊으셨나요?", + "verify": "인증", + "step1-start": "시작하기", + "step1-privacy": "회원가입시 약관과 개인 정보 보호 정책을 읽고 동의한 것으로 간주합니다.", + "step1-submit": "시작하기", + "step2-message": "{{email}}로 인증 메일을 전송하였습니다{{email}}", + "step2-code-error": "코드가 잘못된 것 같아요. 남은 시도:", + "step2-spam-alert": "스팸함에 메일이 있지는 않은지 확인하세요", + "step3-message": "거의다 끝났어요!", + "step4-message": "긴급복구 키트 저장하기", + "step4-description1": "계정이 잠겼을 경우 비상 키트를 사용하여 로그인할 수 있어요.", + "step4-description2": "다운로드 후 안전한 곳에 보관하는 것을 추천합니다.", + "step4-description3": "분실시 접근하거나 복구할 수 없는 시크릿 키가 포함되어 있어요.", + "step4-download": "PDF 다운로드" + }, + "nav": { + "support": { + "slack": "[NEW] 슬랙 포럼에 가입하기", + "docs": "문서 보기", + "issue": "깃허브 이슈 열기", + "email": "Infisical팀에게 메일 보내기" + }, + "user": { + "signed-in-as": "다음으로 로그인됨", + "current-organization": "현재 조직", + "usage-billing": "요금제 & 결제", + "invite": "맴버 초대하기", + "other-organizations": "다른 조직" + }, + "menu": { + "project": "프로젝트", + "secrets": "시크릿", + "members": "맴버", + "integrations": "연동", + "project-settings": "프로젝트 설정" + } + }, + "section": { + "incident": { + "add-contact": "연락처 추가하기", + "add-dialog": { + "add-incident": "비상 연락처 추가하기", + "description": "중대한 일이 생길 경우, 이 연락처로 알림이 전송됩니다.", + "title": "비상 연락처 추가하기" + }, + "incident-contacts": "비상 연락망", + "incident-contacts-description": "중대한 일이 생길 경우, 아래의 연락처로 알림이 전송됩니다.", + "no-incident-contacts": "비상 연락망이 존재하지 않아요." + }, + "members": { + "add-member": "맴버 추가하기", + "org-members": "조직 맴버", + "search-members": "맴버를 검색하기...", + "add-dialog": { + "add-member-to-project": "프로젝트에 맴버 추가하기", + "already-all-invited": "조직의 모든 유저가 이미 초대되었습니다.", + "add-user-org-first": "유저를 먼저 조직에 추가해 주세요.", + "user-will-email": "유저는 안내가 포함된 메일을 받게 됩니다.", + "looking-add": "<0>조직에 유저를 추가하고 싶다면,<1>여기를 클릭하세요", + "add-user-to-org": "조직에 유저 추가하기" + }, + "org-members-description": "조직의 맴버들을 관리하세요." + }, + "password": { + "password": "비밀번호", + "change": "비밀번호 변경", + "current": "현재 비밀번호", + "new": "새 비밀번호", + "current-wrong": "현재 비밀번호가 잘못되었어요", + "validate-base": "비밀번호는 다음 조건을 만족해야 합니다:", + "validate-length": "14 글자 이상", + "validate-case": "1개 이상의 소문자", + "validate-number": "1개 이상의 숫자" + }, + "token": { + "add-dialog": { + "add": "서비스 토큰 추가하기", + "copy-service-token": "서비스 토큰 복사하기", + "copy-service-token-description": "팝업을 닫을 시 다시는 토큰을 확인할 수 없어요.", + "description": "이름, 환경, 만료일을 지정하세요. 토큰이 생성되면 최초 한번만 볼 수 있어요. 안전한 곳에 저장하세요.", + "name": "서비스 토큰 이름", + "title": "{{target}}의 토큰 추가하기" + }, + "add-new": "새 토큰 추가하기", + "service-tokens": "서비스 토큰", + "service-tokens-description": "모든 서비스 토큰은 프로젝트 및 환경에 따라 다릅니다." + } + }, + "settings": { + "members": { + "title": "맴버 설정", + "description": "선택한 프로젝트의 맴버를 확인하세요." + }, + "org": { + "title": "조직 설정", + "description": "조직의 맴버를 관리하세요." + }, + "personal": { + "title": "개인 설정", + "description": "계정 및 기본적인 설정을 확인하고 변경하세요.", + "emergency": { + "name": "긴급복구 키트", + "text1": "긴급복구 키트는 Infisical계정에 로그인 할 수 있는 정보를 가지고 있어요.", + "text2": "오직 마지막으로 발급한 긴급복구 키트만 사용 가능해요. 새로운 긴급복구 키트를 받으려면, 비밀번호를 입력하세요.", + "download": "긴급복구 키트 다운로드" + }, + "change-language": "언어 변경하기" + }, + "project": { + "title": "프로젝트 설정", + "description": "현재 선택한 프로젝트에 대해서 설정해요.", + "auto-generated": "자동으로 생성된 고유한 키 입니다. 변경할 수 없어요.", + "danger-zone": "위험존", + "danger-zone-note": "프로젝트를 삭제한다면 모든 키가 즉시 삭제되며 다시는 되돌릴 수 없어요. 삭제를 원한다면 프로젝트 이름을 아래에 적어주세요.", + "delete-project": "프로젝트 삭제", + "delete-project-note": "노트: 최소 한개 이상의 프로젝트는 조직에 존재해야 해요.", + "docs": "Infisical 문서", + "project-id-description": "다른 코드에서 Infisical과 환경변수를 연동하기 위해서는 프로젝트 ID가 필요해요.", + "project-id-description2": "다양한 언어 및 프레임워크에 대한 가이드를 확인하고 싶다면, 다음을 확인하세요. ", + "project-to-delete": "삭제할 프로젝트" + } + }, + "signup": { + "title": "회원가입", + "og-title": "한줄의 코드르 .env파일을 교체하세요. 3분이면 가입할 수 있어요.", + "og-description": "Infisical은 팀원과 .env파일을 공유하고 연동할 수 있는 심플한 end-to-end 암호화 플렛폼입니다. Node.js, Next.js, Gatsby, Nest.js 와 같은 다양한 플렛폼에서 작동해요.", + "signup": "회원가입", + "already-have-account": "이미 계정이 있나요? 로그인하기", + "forgot-password": "비밀번호를 잊으셨나요?", + "verify": "인증", + "step1-start": "시작하기", + "step1-privacy": "회원가입시 약관과 개인 정보 보호 정책을 읽고 동의한 것으로 간주합니다.", + "step1-submit": "시작하기", + "step2-message": "{{email}}로 인증 메일을 전송하였습니다{{email}}", + "step2-code-error": "코드가 잘못된 것 같아요. 다시 시도해주세요.", + "step2-spam-alert": "스팸함에 메일이 있지는 않은지 확인하세요", + "step3-message": "거의다 끝났어요!", + "step4-message": "긴급복구 키트 저장하기", + "step4-description1": "계정이 잠겼을 경우 비상 키트를 사용하여 로그인할 수 있어요.", + "step4-description2": "다운로드 후 안전한 곳에 보관하는 것을 추천합니다.", + "step4-description3": "분실시 접근하거나 복구할 수 없는 시크릿 키가 포함되어 있어요.", + "step4-download": "PDF 다운로드" + } +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/activity.json b/frontend/public/locales/pt-BR/activity.json deleted file mode 100644 index 9ffdf766d..000000000 --- a/frontend/public/locales/pt-BR/activity.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "Registro de Atividade", - "subtitle": "Histórico de eventos para esse projeto Infisical.", - "event": { - "readSecrets": "Segredos Visualizados", - "updateSecrets": "Segredos Atualizados", - "addSecrets": "Segredos Adicionados", - "deleteSecrets": "Segredos Excluídos" - }, - "ip-address": "Endereço IP" -} diff --git a/frontend/public/locales/pt-BR/billing.json b/frontend/public/locales/pt-BR/billing.json deleted file mode 100644 index db784ab2d..000000000 --- a/frontend/public/locales/pt-BR/billing.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Uso & Faturamento", - "description": "Visualize e gerencie a assinatura da sua organização aqui", - "subscription": "Inscrição", - "starter": { - "name": "Base", - "price-explanation": "Até 5 membros de equipe", - "text": "Gerencie qualquer projeto com 5 membros gratuitamente!", - "subtext": "$5 por membro adicional / mês." - }, - "professional": { - "name": "Profissional", - "price-explanation": "/membro/mês", - "subtext": "Inclui projetos e membros ilimitados.", - "text": "Acompanhe o gerenciamento de chaves à medida que você cresce." - }, - "enterprise": { - "name": "Empreendimento", - "text": "Acompanhe o gerenciamento de chaves à medida que você cresce." - }, - "current-usage": "Uso atual", - "free": "Grátis", - "downgrade": "Reduzir", - "upgrade": "Melhorar", - "learn-more": "Saber Mais", - "custom-pricing": "Preço Personalizado", - "schedule-demo": "Agende uma Demonstração" -} diff --git a/frontend/public/locales/pt-BR/common.json b/frontend/public/locales/pt-BR/common.json deleted file mode 100644 index 05b0b87fa..000000000 --- a/frontend/public/locales/pt-BR/common.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "head-title": "{{title}} | Infisical", - "error_project-already-exists": "Já exite um projeto com este nome.", - "no-mobile": "Para usar o Infisical, faça o login através de um dispositivo com dimensões maiores.", - "email": "Email", - "password": "Senha", - "first-name": "Primeiro Nome", - "last-name": "Ultimo Nome", - "logout": "Sair", - "validate-required": "Por favor insira o seu {{name}}", - "maintenance-alert": "Estamos passando por pequenas dificuldades técnicas. Estamos trabalhando para resolvê-las agora. Por favor, volte dentro de alguns minutos.", - "click-to-copy": "Clique para copiar", - "project-id": "ID do Projeto", - "save-changes": "Salvar Alterações", - "saved": "Salvou", - "drop-zone": "Arraste e solte seu arquivo .env aqui.", - "drop-zone-keys": "Arraste e solte seu arquivo .env aqui para adicionar mais chaves.", - "role": "Role", - "role_admin": "admin", - "display-name": "Nome de exibição", - "environment": "Ambiente", - "expired-in": "Expira em", - "language": "Idioma", - "search": "Procurar...", - "note": "Note", - "view-more": "Ver mais", - "end-of-history": "Fim do Histórico", - "select-event": "Selecione um evento", - "event": "Evento", - "user": "Usuário", - "source": "Fonte", - "time": "Data/Hora", - "timestamp": "Timestamp" -} diff --git a/frontend/public/locales/pt-BR/dashboard.json b/frontend/public/locales/pt-BR/dashboard.json deleted file mode 100644 index 4f4474237..000000000 --- a/frontend/public/locales/pt-BR/dashboard.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "title": "Segredos", - "og-title": "Gerencie seus arquivos .env em segundos", - "og-description": "Infisical é uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem seus arquivos .env.", - "search-keys": "Pesquisar chaves...", - "add-key": "Adicionar Chave", - "personal": "Pessoal", - "personal-description": "As chaves pessoais são visíveis apenas para você", - "shared": "Compartilhado", - "shared-description": "As chaves compartilhadas ficam visíveis para toda a sua equipe", - "make-shared": "Tornar Compartilhado", - "make-personal": "Tornar Pessoal", - "check-docs": { - "button": "Checkar Documentação", - "title": "Bom trabalho!!", - "line1": "Parabéns por adicionar mais segredos.", - "line2": "Veja como conectá-los à sua base de código." - }, - "sidebar": { - "secret": "Segredo", - "key": "Chave", - "value": "Valor", - "override": "Substitua o valor por um valor pessoal", - "version-history": "Histórico da versão", - "comments": "Comentários e Notas", - "personal-explanation": "Este segredo é pessoal. Não é compartilhado com nenhum de seus colegas de equipe.", - "generate-random-hex": "Gerar HEX Aleatório", - "digits": "dígitos", - "delete-key-dialog": { - "title": "Excluir Chave", - "confirm-delete-message": "Você tem certeza que deseja excluir esta chave? Essa ação não pode ser desfeita." - } - } -} diff --git a/frontend/public/locales/pt-BR/integrations.json b/frontend/public/locales/pt-BR/integrations.json deleted file mode 100644 index 21c20db5c..000000000 --- a/frontend/public/locales/pt-BR/integrations.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Integrações de Projetos", - "description": "Gerencie suas integrações da Infisical com serviços de terceiros.", - "no-integrations1": "Você ainda não tem integrações configuradas. Quando você fizer isso, elas aparecerão aqui.", - "no-integrations2": "Para começar, clique em qualquer uma das opções abaixo. Leva 5 cliques para configurar.", - "available": "Integrações de Plataforma e em Nuvem", - "available-text1": "Clique na integração que deseja conectar. Isso permitirá que suas variáveis de ambiente fluam automaticamente para serviços de terceiros selecionados.", - "available-text2": "Observação: durante uma integração com o Heroku, por questões de segurança, é impossível manter a criptografia de ponta a ponta. Em teoria, isso permite que o Infisical descriptografe suas variáveis de ambiente. Na prática, podemos garantir que isso nunca será feito e nos permite proteger seus segredos de pessoas mal-intencionadas online. O serviço básico da Infisical sempre permanecerá criptografado de ponta a ponta. Em caso de dúvidas, entre em contato com support@infisical.com.", - "cloud-integrations": "Integrações em Nuvem", - "framework-integrations": "Integrações com framework", - "click-to-start": "Clique em uma integração para começar a sincronizar segredos com ela.", - "click-to-setup": "Clique em uma estrutura para obter as instruções de configuração.", - "grant-access-to-secrets": "Conceda acesso Infisical aos seus segredos", - "why-infisical-needs-access": "A maioria das integrações em Nuvem exige que o Infisical seja capaz de descriptografar seus segredos para que possam ser encaminhados.", - "grant-access-button": "Garantir acesso" -} diff --git a/frontend/public/locales/pt-BR/login.json b/frontend/public/locales/pt-BR/login.json deleted file mode 100644 index e06a59acd..000000000 --- a/frontend/public/locales/pt-BR/login.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "title": "Entrar", - "og-title": "Entrar no Infisical", - "og-description": "Infisical é uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem seus arquivos .env.", - "login": "Entrar", - "need-account": "Precisa de uma conta Infisical?", - "forgot-password": "Esqueceu sua senha?", - "create-account": "Criar uma conta" -} diff --git a/frontend/public/locales/pt-BR/mfa.json b/frontend/public/locales/pt-BR/mfa.json deleted file mode 100644 index a2a87b322..000000000 --- a/frontend/public/locales/pt-BR/mfa.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "title": "Criar uma conta", - "og-title": "Substitua os arquivos .env por 1 linha de código. Cadastre-se no Infisical em 3 minutos.", - "og-description": "Infisical é uma plataforma criptografada de ponta a ponta simples que permite que as equipes sincronizem e gerenciem chaves de API e variáveis ambientais. Funciona com Node.js, Next.js, Gatsby, Nest.js...", - "signup": "Criar uma conta", - "already-have-account": "Possui uma conta? Conecte-se", - "forgot-password": "Esqueceu sua senha?", - "verify": "Verificar", - "step1-start": "Vamos começar", - "step1-privacy": "Ao criar uma conta, você concorda com nossos Termos e leu a Política de Privacidade.", - "step1-submit": "Começar", - "step2-message": "Enviamos um e-mail de verificação para{{email}}", - "step2-code-error": "Ops. Seu código está errado. Tentativas restantes:", - "step2-spam-alert": "Lembre-se de verificar sua caixa de entrada de spam.", - "step3-message": "Quase lá!", - "step4-message": "Guarde o seu Kit de Emergência", - "step4-description1": "Se sua conta for bloqueada, seu Kit de emergência é a única maneira de fazer login.", - "step4-description2": "Recomendamos que você faça o download e guarde-o em algum lugar seguro.", - "step4-description3": "Ele contém sua chave secreta que não podemos acessar ou recuperar para você se você a perder.", - "step4-download": "Baixar PDF", - "step5-send-invites": "Enviar convites", - "step5-invite-team": "Convide sua equipe", - "step5-subtitle": "Infisical foi feito para ser usado com seus colegas. Convide-os para eles testarem também.", - "step5-skip": "Pular" -} diff --git a/frontend/public/locales/pt-BR/nav.json b/frontend/public/locales/pt-BR/nav.json deleted file mode 100644 index 7922312dd..000000000 --- a/frontend/public/locales/pt-BR/nav.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "support": { - "slack": "[NEW] Participe do fórum do Slack", - "docs": "Leia a Documentação", - "issue": "Abra uma Issue no Github", - "email": "Envie-nos um e-mail" - }, - "user": { - "signed-in-as": "ASSINADO COMO", - "current-organization": "ORGANIZAÇÃO ATUAL", - "usage-billing": "Uso & Faturamento", - "invite": "Convide Membros", - "other-organizations": "OUTRA ORGANIZAÇÃO" - }, - "menu": { - "project": "PROJETO", - "secrets": "Segredos", - "members": "Membros", - "integrations": "Integrações", - "project-settings": "Configurações do Projeto" - } -} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/section-incident.json b/frontend/public/locales/pt-BR/section-incident.json deleted file mode 100644 index cbe902783..000000000 --- a/frontend/public/locales/pt-BR/section-incident.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "incident-contacts": "Contatos de Emergência", - "incident-contacts-description": "Esses contatos serão notificados no caso improvável de um incidente grave.", - "no-incident-contacts": "Nenhum contato de emergência encontrado.", - "add-contact": "Adicionar contato", - "add-dialog": { - "title": "Adicionar um contato de emergência", - "description": "Este contato será notificado no caso improvável de um incidente grave.", - "add-incident": "Adicionar contato de emergência" - } -} diff --git a/frontend/public/locales/pt-BR/section-members.json b/frontend/public/locales/pt-BR/section-members.json deleted file mode 100644 index c8ee1d2a9..000000000 --- a/frontend/public/locales/pt-BR/section-members.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "add-member": "Adicionar membro", - "org-members": "Membros da Organização", - "org-members-description": "Gerencie os membros da sua organização. Esses usuários poderiam posteriormente ser associados a projetos.", - "search-members": "Pesquisar membros...", - "add-dialog": { - "add-member-to-project": "Adicionar um membro ao seu projeto", - "already-all-invited": "Todos os usuários da sua organização já foram convidados.", - "add-user-org-first": "Adicione mais usuários à organização primeiro.", - "user-will-email": "O usuário receberá um e-mail com as instruções.", - "looking-add": "<0>Se você deseja adicionar usuários à sua organização,<1>clique aqui", - "add-user-to-org": "Adicionar usuários à organização" - } -} diff --git a/frontend/public/locales/pt-BR/section-password.json b/frontend/public/locales/pt-BR/section-password.json deleted file mode 100644 index 771581768..000000000 --- a/frontend/public/locales/pt-BR/section-password.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "password": "Senha", - "change": "Mudar senha", - "current": "Senha atual", - "current-wrong": "A senha atual pode estar errada", - "new": "Nova Senha", - "validate-base": "A senha deve conter pelo menos:", - "validate-length": "14 caracteres", - "validate-case": "1 caractere minúsculo", - "validate-number": "1 número" -} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/section-token.json b/frontend/public/locales/pt-BR/section-token.json deleted file mode 100644 index 1713f8118..000000000 --- a/frontend/public/locales/pt-BR/section-token.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "service-tokens": "Tokens de Serviço", - "service-tokens-description": "Cada token de serviço é específico para você, um determinado projeto e um determinado ambiente dentro deste projeto.", - "add-new": "Adicionar novo token", - "add-dialog": { - "title": "Adicione um token de serviço para {{target}}", - "description": "Especifique o nome, o ambiente e o período de expiração. Quando um token é gerado, você só poderá vê-lo uma vez antes que ele desapareça. Certifique-se de salvá-lo em algum lugar.", - "name": "Nome do token de serviço", - "add": "Adicionar token de serviço", - "copy-service-token": "Copie seu token de serviço", - "copy-service-token-description": "Depois de fechar este pop-up, você nunca mais verá seu token de serviço" - } -} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/settings-members.json b/frontend/public/locales/pt-BR/settings-members.json deleted file mode 100644 index f48913547..000000000 --- a/frontend/public/locales/pt-BR/settings-members.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Membros do Projeto", - "description": "Esta página mostra os membros do projeto selecionado." -} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/settings-org.json b/frontend/public/locales/pt-BR/settings-org.json deleted file mode 100644 index 458a8ac09..000000000 --- a/frontend/public/locales/pt-BR/settings-org.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Configurações da organização", - "description": "Gerencie os membros da sua organização. Esses usuários poderiam posteriormente ser associados a projetos." -} diff --git a/frontend/public/locales/pt-BR/settings-personal.json b/frontend/public/locales/pt-BR/settings-personal.json deleted file mode 100644 index 9d5dd7f50..000000000 --- a/frontend/public/locales/pt-BR/settings-personal.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "Configurações Pessoais", - "description": "Visualize e gerencie suas informações pessoais aqui.", - "emergency": { - "name": "Kit de emergência", - "text1": "Seu Kit de Emergência contém as informações necessárias para acessar sua conta Infisical.", - "text2": "Apenas o último kit de emergência emitido permanece válido. Para obter um novo Kit de emergência, verifique sua senha.", - "download": "Baixe o kit de emergência" - }, - "change-language": "Mudar idioma" -} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/settings-project.json b/frontend/public/locales/pt-BR/settings-project.json deleted file mode 100644 index acd88a5d0..000000000 --- a/frontend/public/locales/pt-BR/settings-project.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "title": "Configurações do Projeto", - "description": "Essas configurações se aplicam apenas ao projeto atualmente selecionado.", - "danger-zone": "Zona de perigo", - "delete-project": "Excluir projeto", - "project-to-delete": "Projeto a ser deletado", - "danger-zone-note": "Assim que você excluir este projeto, não poderá desfazê-lo. Isso removerá imediatamente todas as chaves. Se você ainda quiser fazer isso, digite o nome do projeto abaixo.", - "delete-project-note": "Observação: você só pode excluir um projeto caso tenha mais de um", - "project-id-description": "Para integrar Infisical em sua base de código e obter injeção automática de variáveis de ambiente, você deve usar o seguinte ID do projeto.", - "project-id-description2": "Para obter mais orientações, incluindo trechos de código para várias linguagens e frameworks, consulte ", - "auto-generated": "Este é o identificador exclusivo - gerado automaticamente - do seu projeto. Não pode ser alterado.", - "docs": "Documentação do Infisical", - "auto-capitalization": "Converter em caixa alta automaticamente", - "auto-capitalization-description": "Por padrão, Infisical converte automaticamente as chaves em caixa alta. Se você quiser desativar essa funcionalidade, pode fazê-lo aqui." -} diff --git a/frontend/public/locales/pt-BR/signup.json b/frontend/public/locales/pt-BR/signup.json deleted file mode 100644 index c08ffea7c..000000000 --- a/frontend/public/locales/pt-BR/signup.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "title": "Inscrever-se", - "og-title": "Substitua os arquivos .env por 1 linha de código. Cadastre-se no Infisical em 3 minutos.", - "og-description": "Infisical é uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem chaves de API e variáveis de ambiente. Funciona com Node.js, Next.js, Gatsby, Nest.js...", - "signup": "Inscrever-se", - "already-have-account": "Possui uma conta? Conecte-se", - "forgot-password": "Esqueceu sua senha?", - "verify": "Verificar", - "step1-start": "Vamos começar", - "step1-privacy": "Ao criar uma conta, você concorda com nossos Termos e leu e reconheceu a Política de Privacidade.", - "step1-submit": "Iniciar", - "step2-message": "Enviamos um e-mail de verificação para{{email}}", - "step2-code-error": "Ops. Seu código está errado. Por favor, tente novamente.", - "step2-spam-alert": "Certifique-se de verificar sua caixa de entrada de spam.", - "step3-message": "Quase lá!", - "step4-message": "Guarde o seu Kit de Emergência", - "step4-description1": "Se sua conta for bloqueada, seu Kit de emergência é a única maneira de fazer login.", - "step4-description2": "Recomendamos que você faça o download e guarde-o em algum lugar seguro.", - "step4-description3": "Ele contém sua chave secreta que não podemos acessar ou recuperar para você se você a perder.", - "step4-download": "Baixar PDF", - "step5-send-invites": "Enviar convites", - "step5-invite-team": "Convide sua equipe", - "step5-subtitle": "Infisical foi feito para ser usado com seus colegas. Convide-os para testar também.", - "step5-skip": "Pular" -} diff --git a/frontend/public/locales/pt-BR/translations.json b/frontend/public/locales/pt-BR/translations.json new file mode 100644 index 000000000..5b53ce503 --- /dev/null +++ b/frontend/public/locales/pt-BR/translations.json @@ -0,0 +1,293 @@ +{ + "activity": { + "title": "Registro de Atividade", + "subtitle": "Histórico de eventos para esse projeto Infisical.", + "event": { + "readSecrets": "Segredos Visualizados", + "updateSecrets": "Segredos Atualizados", + "addSecrets": "Segredos Adicionados", + "deleteSecrets": "Segredos Excluídos" + }, + "ip-address": "Endereço IP" + }, + "billing": { + "title": "Uso & Faturamento", + "description": "Visualize e gerencie a assinatura da sua organização aqui", + "subscription": "Inscrição", + "starter": { + "name": "Base", + "price-explanation": "Até 5 membros de equipe", + "text": "Gerencie qualquer projeto com 5 membros gratuitamente!", + "subtext": "$5 por membro adicional / mês." + }, + "professional": { + "name": "Profissional", + "price-explanation": "/membro/mês", + "subtext": "Inclui projetos e membros ilimitados.", + "text": "Acompanhe o gerenciamento de chaves à medida que você cresce." + }, + "enterprise": { + "name": "Empreendimento", + "text": "Acompanhe o gerenciamento de chaves à medida que você cresce." + }, + "current-usage": "Uso atual", + "free": "Grátis", + "downgrade": "Reduzir", + "upgrade": "Melhorar", + "learn-more": "Saber Mais", + "custom-pricing": "Preço Personalizado", + "schedule-demo": "Agende uma Demonstração" + }, + "common": { + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "Já exite um projeto com este nome.", + "no-mobile": "Para usar o Infisical, faça o login através de um dispositivo com dimensões maiores.", + "email": "Email", + "password": "Senha", + "first-name": "Primeiro Nome", + "last-name": "Ultimo Nome", + "logout": "Sair", + "validate-required": "Por favor insira o seu {{name}}", + "maintenance-alert": "Estamos passando por pequenas dificuldades técnicas. Estamos trabalhando para resolvê-las agora. Por favor, volte dentro de alguns minutos.", + "click-to-copy": "Clique para copiar", + "project-id": "ID do Projeto", + "save-changes": "Salvar Alterações", + "saved": "Salvou", + "drop-zone": "Arraste e solte seu arquivo .env aqui.", + "drop-zone-keys": "Arraste e solte seu arquivo .env aqui para adicionar mais chaves.", + "role": "Role", + "role_admin": "admin", + "display-name": "Nome de exibição", + "environment": "Ambiente", + "expired-in": "Expira em", + "language": "Idioma", + "search": "Procurar...", + "note": "Note", + "view-more": "Ver mais", + "end-of-history": "Fim do Histórico", + "select-event": "Selecione um evento", + "event": "Evento", + "user": "Usuário", + "source": "Fonte", + "time": "Data/Hora", + "timestamp": "Timestamp" + }, + "dashboard": { + "title": "Segredos", + "og-title": "Gerencie seus arquivos .env em segundos", + "og-description": "Infisical é uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem seus arquivos .env.", + "search-keys": "Pesquisar chaves...", + "add-key": "Adicionar Chave", + "personal": "Pessoal", + "personal-description": "As chaves pessoais são visíveis apenas para você", + "shared": "Compartilhado", + "shared-description": "As chaves compartilhadas ficam visíveis para toda a sua equipe", + "make-shared": "Tornar Compartilhado", + "make-personal": "Tornar Pessoal", + "check-docs": { + "button": "Checkar Documentação", + "title": "Bom trabalho!!", + "line1": "Parabéns por adicionar mais segredos.", + "line2": "Veja como conectá-los à sua base de código." + }, + "sidebar": { + "secret": "Segredo", + "key": "Chave", + "value": "Valor", + "override": "Substitua o valor por um valor pessoal", + "version-history": "Histórico da versão", + "comments": "Comentários e Notas", + "personal-explanation": "Este segredo é pessoal. Não é compartilhado com nenhum de seus colegas de equipe.", + "generate-random-hex": "Gerar HEX Aleatório", + "digits": "dígitos", + "delete-key-dialog": { + "title": "Excluir Chave", + "confirm-delete-message": "Você tem certeza que deseja excluir esta chave? Essa ação não pode ser desfeita." + } + } + }, + "integrations": { + "title": "Integrações de Projetos", + "description": "Gerencie suas integrações da Infisical com serviços de terceiros.", + "no-integrations1": "Você ainda não tem integrações configuradas. Quando você fizer isso, elas aparecerão aqui.", + "no-integrations2": "Para começar, clique em qualquer uma das opções abaixo. Leva 5 cliques para configurar.", + "available": "Integrações de Plataforma e em Nuvem", + "available-text1": "Clique na integração que deseja conectar. Isso permitirá que suas variáveis de ambiente fluam automaticamente para serviços de terceiros selecionados.", + "available-text2": "Observação: durante uma integração com o Heroku, por questões de segurança, é impossível manter a criptografia de ponta a ponta. Em teoria, isso permite que o Infisical descriptografe suas variáveis de ambiente. Na prática, podemos garantir que isso nunca será feito e nos permite proteger seus segredos de pessoas mal-intencionadas online. O serviço básico da Infisical sempre permanecerá criptografado de ponta a ponta. Em caso de dúvidas, entre em contato com support@infisical.com.", + "cloud-integrations": "Integrações em Nuvem", + "framework-integrations": "Integrações com framework", + "click-to-start": "Clique em uma integração para começar a sincronizar segredos com ela.", + "click-to-setup": "Clique em uma estrutura para obter as instruções de configuração.", + "grant-access-to-secrets": "Conceda acesso Infisical aos seus segredos", + "why-infisical-needs-access": "A maioria das integrações em Nuvem exige que o Infisical seja capaz de descriptografar seus segredos para que possam ser encaminhados.", + "grant-access-button": "Garantir acesso" + }, + "login": { + "title": "Entrar", + "og-title": "Entrar no Infisical", + "og-description": "Infisical é uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem seus arquivos .env.", + "login": "Entrar", + "need-account": "Precisa de uma conta Infisical?", + "forgot-password": "Esqueceu sua senha?", + "create-account": "Criar uma conta" + }, + "mfa": { + "title": "Criar uma conta", + "og-title": "Substitua os arquivos .env por 1 linha de código. Cadastre-se no Infisical em 3 minutos.", + "og-description": "Infisical é uma plataforma criptografada de ponta a ponta simples que permite que as equipes sincronizem e gerenciem chaves de API e variáveis ambientais. Funciona com Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Criar uma conta", + "already-have-account": "Possui uma conta? Conecte-se", + "forgot-password": "Esqueceu sua senha?", + "verify": "Verificar", + "step1-start": "Vamos começar", + "step1-privacy": "Ao criar uma conta, você concorda com nossos Termos e leu a Política de Privacidade.", + "step1-submit": "Começar", + "step2-message": "Enviamos um e-mail de verificação para{{email}}", + "step2-code-error": "Ops. Seu código está errado. Tentativas restantes:", + "step2-spam-alert": "Lembre-se de verificar sua caixa de entrada de spam.", + "step3-message": "Quase lá!", + "step4-message": "Guarde o seu Kit de Emergência", + "step4-description1": "Se sua conta for bloqueada, seu Kit de emergência é a única maneira de fazer login.", + "step4-description2": "Recomendamos que você faça o download e guarde-o em algum lugar seguro.", + "step4-description3": "Ele contém sua chave secreta que não podemos acessar ou recuperar para você se você a perder.", + "step4-download": "Baixar PDF", + "step5-send-invites": "Enviar convites", + "step5-invite-team": "Convide sua equipe", + "step5-subtitle": "Infisical foi feito para ser usado com seus colegas. Convide-os para eles testarem também.", + "step5-skip": "Pular" + }, + "nav": { + "support": { + "slack": "[NEW] Participe do fórum do Slack", + "docs": "Leia a Documentação", + "issue": "Abra uma Issue no Github", + "email": "Envie-nos um e-mail" + }, + "user": { + "signed-in-as": "ASSINADO COMO", + "current-organization": "ORGANIZAÇÃO ATUAL", + "usage-billing": "Uso & Faturamento", + "invite": "Convide Membros", + "other-organizations": "OUTRA ORGANIZAÇÃO" + }, + "menu": { + "project": "PROJETO", + "secrets": "Segredos", + "members": "Membros", + "integrations": "Integrações", + "project-settings": "Configurações do Projeto" + } + }, + "section": { + "incident": { + "incident-contacts": "Contatos de Emergência", + "incident-contacts-description": "Esses contatos serão notificados no caso improvável de um incidente grave.", + "no-incident-contacts": "Nenhum contato de emergência encontrado.", + "add-contact": "Adicionar contato", + "add-dialog": { + "title": "Adicionar um contato de emergência", + "description": "Este contato será notificado no caso improvável de um incidente grave.", + "add-incident": "Adicionar contato de emergência" + } + }, + "members": { + "add-member": "Adicionar membro", + "org-members": "Membros da Organização", + "org-members-description": "Gerencie os membros da sua organização. Esses usuários poderiam posteriormente ser associados a projetos.", + "search-members": "Pesquisar membros...", + "add-dialog": { + "add-member-to-project": "Adicionar um membro ao seu projeto", + "already-all-invited": "Todos os usuários da sua organização já foram convidados.", + "add-user-org-first": "Adicione mais usuários à organização primeiro.", + "user-will-email": "O usuário receberá um e-mail com as instruções.", + "looking-add": "<0>Se você deseja adicionar usuários à sua organização,<1>clique aqui", + "add-user-to-org": "Adicionar usuários à organização" + } + }, + "password": { + "password": "Senha", + "change": "Mudar senha", + "current": "Senha atual", + "current-wrong": "A senha atual pode estar errada", + "new": "Nova Senha", + "validate-base": "A senha deve conter pelo menos:", + "validate-length": "14 caracteres", + "validate-case": "1 caractere minúsculo", + "validate-number": "1 número" + }, + "token": { + "service-tokens": "Tokens de Serviço", + "service-tokens-description": "Cada token de serviço é específico para você, um determinado projeto e um determinado ambiente dentro deste projeto.", + "add-new": "Adicionar novo token", + "add-dialog": { + "title": "Adicione um token de serviço para {{target}}", + "description": "Especifique o nome, o ambiente e o período de expiração. Quando um token é gerado, você só poderá vê-lo uma vez antes que ele desapareça. Certifique-se de salvá-lo em algum lugar.", + "name": "Nome do token de serviço", + "add": "Adicionar token de serviço", + "copy-service-token": "Copie seu token de serviço", + "copy-service-token-description": "Depois de fechar este pop-up, você nunca mais verá seu token de serviço" + } + } + }, + "settings": { + "members": { + "title": "Membros do Projeto", + "description": "Esta página mostra os membros do projeto selecionado." + }, + "org": { + "title": "Configurações da organização", + "description": "Gerencie os membros da sua organização. Esses usuários poderiam posteriormente ser associados a projetos." + }, + "personal": { + "title": "Configurações Pessoais", + "description": "Visualize e gerencie suas informações pessoais aqui.", + "emergency": { + "name": "Kit de emergência", + "text1": "Seu Kit de Emergência contém as informações necessárias para acessar sua conta Infisical.", + "text2": "Apenas o último kit de emergência emitido permanece válido. Para obter um novo Kit de emergência, verifique sua senha.", + "download": "Baixe o kit de emergência" + }, + "change-language": "Mudar idioma" + }, + "project": { + "title": "Configurações do Projeto", + "description": "Essas configurações se aplicam apenas ao projeto atualmente selecionado.", + "danger-zone": "Zona de perigo", + "delete-project": "Excluir projeto", + "project-to-delete": "Projeto a ser deletado", + "danger-zone-note": "Assim que você excluir este projeto, não poderá desfazê-lo. Isso removerá imediatamente todas as chaves. Se você ainda quiser fazer isso, digite o nome do projeto abaixo.", + "delete-project-note": "Observação: você só pode excluir um projeto caso tenha mais de um", + "project-id-description": "Para integrar Infisical em sua base de código e obter injeção automática de variáveis de ambiente, você deve usar o seguinte ID do projeto.", + "project-id-description2": "Para obter mais orientações, incluindo trechos de código para várias linguagens e frameworks, consulte ", + "auto-generated": "Este é o identificador exclusivo - gerado automaticamente - do seu projeto. Não pode ser alterado.", + "docs": "Documentação do Infisical", + "auto-capitalization": "Converter em caixa alta automaticamente", + "auto-capitalization-description": "Por padrão, Infisical converte automaticamente as chaves em caixa alta. Se você quiser desativar essa funcionalidade, pode fazê-lo aqui." + } + }, + "signup": { + "title": "Inscrever-se", + "og-title": "Substitua os arquivos .env por 1 linha de código. Cadastre-se no Infisical em 3 minutos.", + "og-description": "Infisical é uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem chaves de API e variáveis de ambiente. Funciona com Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Inscrever-se", + "already-have-account": "Possui uma conta? Conecte-se", + "forgot-password": "Esqueceu sua senha?", + "verify": "Verificar", + "step1-start": "Vamos começar", + "step1-privacy": "Ao criar uma conta, você concorda com nossos Termos e leu e reconheceu a Política de Privacidade.", + "step1-submit": "Iniciar", + "step2-message": "Enviamos um e-mail de verificação para{{email}}", + "step2-code-error": "Ops. Seu código está errado. Por favor, tente novamente.", + "step2-spam-alert": "Certifique-se de verificar sua caixa de entrada de spam.", + "step3-message": "Quase lá!", + "step4-message": "Guarde o seu Kit de Emergência", + "step4-description1": "Se sua conta for bloqueada, seu Kit de emergência é a única maneira de fazer login.", + "step4-description2": "Recomendamos que você faça o download e guarde-o em algum lugar seguro.", + "step4-description3": "Ele contém sua chave secreta que não podemos acessar ou recuperar para você se você a perder.", + "step4-download": "Baixar PDF", + "step5-send-invites": "Enviar convites", + "step5-invite-team": "Convide sua equipe", + "step5-subtitle": "Infisical foi feito para ser usado com seus colegas. Convide-os para testar também.", + "step5-skip": "Pular" + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/activity.json b/frontend/public/locales/tr/activity.json deleted file mode 100644 index 80ac8f90d..000000000 --- a/frontend/public/locales/tr/activity.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "title": "Aktivite Günlükleri", - "subtitle": "Bu Infisical projesi için Olay Geçmişi.", - "event": { - "readSecrets": "Sırlar Görüntülendi", - "updateSecrets": "Sırlar Güncellendi", - "addSecrets": "Sırlar Eklendi", - "deleteSecrets": "Sırlar Silindi" - }, - "ip-address": "IP Addresi" -} \ No newline at end of file diff --git a/frontend/public/locales/tr/billing.json b/frontend/public/locales/tr/billing.json deleted file mode 100644 index d27ddc976..000000000 --- a/frontend/public/locales/tr/billing.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Planlar & Fiyatlandırma", - "description": "Kuruluşunuzun aboneliğini buradan görüntüleyin ve yönetin", - "subscription": "Abonelik", - "starter": { - "name": "Başlangıç", - "price-explanation": "5 takım üyesine kadar", - "text": "5 kişiyle herhangi bir projeyi ücretsiz yönet!", - "subtext": "Sonrasında aylık her üye başına 5$." - }, - "professional": { - "name": "Profesyonel", - "price-explanation": "/üye/ay", - "subtext": "Sınırsız miktarda üye ve proje dahildir.", - "text": "Anahtar yönetimine siz büyüdükçe ayak uydurun.." - }, - "enterprise": { - "name": "Kurumsal", - "text": "Anahtar yönetimine siz büyüdükçe ayak uydurun." - }, - "current-usage": "Mevcut Plan", - "free": "Ücretsiz", - "downgrade": "Düşürün", - "upgrade": "Yükseltin", - "learn-more": "Daha fazlasını öğrenim", - "custom-pricing": "Özel Fiyatlandırma", - "schedule-demo": "Bir Deneme Sürümü Planlayın " -} \ No newline at end of file diff --git a/frontend/public/locales/tr/common.json b/frontend/public/locales/tr/common.json deleted file mode 100644 index 38d54b476..000000000 --- a/frontend/public/locales/tr/common.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "head-title": "{{title}} | Infisical", - "error_project-already-exists": "Bu isimle bir proje zaten mevcut.", - "no-mobile": " Infisical'ı kullanmak için, lütfen daha büyük boyutlara sahip bir cihaz üzerinden giriş yapın. ", - "email": "Email", - "password": "Şifre", - "first-name": "Adınız", - "last-name": "Soyadınız", - "logout": "Çıkış Yap", - "validate-required": "Lütfen girin, sahip olduğunuz {{name}}", - "maintenance-alert": "Ufak teknik problemler yaşıyoruz. Sorunu çözmek üzere çalışıyoruz. Lütfen birkaç dakika içerisinde yeniden deneyin.", - "click-to-copy": "Kopyala", - "project-id": "Project ID", - "save-changes": "Değişiklikleri Kaydet", - "saved": "Kaydedildi", - "drop-zone": ".env yada .yaml dosyasını buraya sürükleyin", - "drop-zone-keys": "Daha çok anahatar eklemek için bir .env yada .yaml dosyasını sürükleyin.", - "role": "Rol", - "role_admin": "yönetici", - "display-name": "Ekran Adı", - "environment": "Environment", - "expired-in": "Süresi geçicek", - "language": "Dil", - "search": "Ara...", - "note": "Not", - "view-more": "Daha Fazla Göster", - "end-of-history": "Geçmişin Sonu", - "select-event": "Bir olay seçin", - "event": "Olay", - "user": "Kullanıcı", - "source": "Kaynak", - "time": "Zaman", - "timestamp": "Zaman Damgası" -} \ No newline at end of file diff --git a/frontend/public/locales/tr/dashboard.json b/frontend/public/locales/tr/dashboard.json deleted file mode 100644 index c480ba18b..000000000 --- a/frontend/public/locales/tr/dashboard.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "title": "Sırlar", - "og-title": "Saniyeler içerisinde .env dosyalarınızı yönetin", - "og-description": "Infisical takımların .env dosyalarını senkronize etmelerini ve yönetmelerini sağlayan uçtan uca şifrelenmiş basit bir platformdur", - "search-keys": "Anahtarları ara...", - "add-key": "Anahtar Ekle", - "personal": "Kişisel", - "personal-description": "Kişisel anahtarlar sadece sana görünür", - "shared": "Paylaşılan", - "shared-description": "Paylaşılan anahatarlar tüm takımına görünür", - "make-shared": "Paylaşılan Yap", - "make-personal": "Kişisel Yap", - "add-secret": "Yeni bir sır ekle", - "check-docs": { - "button": "Dokümanları Kontrol Et", - "title": "İyi iş!", - "line1": "Tebrikler, yeni anahtarlar eklediniz.", - "line2": "Bunları kendi Codebase' inize nasıl bağlarsınız, işte böyle." - }, - "sidebar": { - "secret": "Sır", - "key": "Anahtar", - "value": "Değer", - "override": "Bu değerin üzerine bir kişisel değer yazın ", - "version-history": "Versiyon Geçmişi", - "comments": "Yorumlar & Notlar", - "personal-explanation": "Bu bir kişisel sır. Herhangi bir takım üyesi ile paylaşılmaz.", - "generate-random-hex": "Rastegele hex oluştur", - "digits": "basamak", - "delete-key-dialog": { - "title": "Anahtarı Sil", - "confirm-delete-message": "Bu sırrı silmek istediğinden emin misin? Bu işlem geri alınamaz." - } - } -} \ No newline at end of file diff --git a/frontend/public/locales/tr/integrations.json b/frontend/public/locales/tr/integrations.json deleted file mode 100644 index b8fe599f4..000000000 --- a/frontend/public/locales/tr/integrations.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Proje Entegrasyonları", - "description": "Infisical'ın üçüncü taraf hizmetlerle olan entegrasyonlarınızı yönetin.", - "no-integrations1": "Henüz ayarlanmış bir entegrasyonunuz yok. Oluşturduğunuz zaman, burada görünecekler.", - "no-integrations2": "Başlamak için aşağıdaki seçeneklerden herhangi birine tıklayın. Sadece 5 tıklama ile kurulumu halledin.", - "available": "Platform & Cloud Entegrasyonları", - "available-text1": "Bağlanmak istediğiniz entegrasyona tıklayın. Bu, ortam değişkenlerinizin seçilen üçüncü taraf hizmetlere otomatik olarak akmasını sağlar.", - "available-text2": "Not: Heroku ile entegrasyon sırasında güvenlik nedenleriyle uçtan uca şifrelemenin sürdürülmesi mümkün değildir. Teorik olarak bu, Infisical'ın ortam değişkenlerinin şifresini çözmesine izin verir. Pratikte biz bunun asla yapılmayacağının garantisini verebiliriz ve bu durum sırlarınızı çevrimiçi kötü niyetlilerden korumamıza olanak tanır. Çekirdek Infisical hizmeti her zaman uçtan uca şifreli kalacaktır. Sorularınız için support@infisical.com adresine ulaşın.", - "cloud-integrations": "Cloud Entegrasyonları", - "framework-integrations": "Framework Entegrasyonları", - "click-to-start": "Sırlarınızı senkronize etmeye başlamak için bir entegrasyona tıklayın.", - "click-to-setup": "Kurulum talimatlarını almak için bir frameworke tıklayın.", - "grant-access-to-secrets": "Infisical'a sırlarınıza erişim izni verin", - "why-infisical-needs-access": "Çoğu cloud entegrasyonu, Infisical'ın sırlarınızı aktarabilmek için sırlarınızı deşifre etmesini gerektirir.", - "grant-access-button": "Erişim izni ver" -} \ No newline at end of file diff --git a/frontend/public/locales/tr/login.json b/frontend/public/locales/tr/login.json deleted file mode 100644 index f42551188..000000000 --- a/frontend/public/locales/tr/login.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "title": "Giriş Yap", - "og-title": "Infisical'a Giriş Yap", - "og-description": "Infisical ekiplerin .env dosyalarını senkronize etmelerini ve yönetmelerini sağlayan uçtan uca şifrelenmiş basit bir platformdur", - "login": "Giriş Yap", - "need-account": "Bir Infisical hesabına mı ihtiyacınız var?", - "create-account": "Hesap oluşturun", - "forgot-password": "Şifrenizi mi unuttunuz?", - "error-login": "Kimlik bilgileri yanlış." -} \ No newline at end of file diff --git a/frontend/public/locales/tr/mfa.json b/frontend/public/locales/tr/mfa.json deleted file mode 100644 index fe4eb1654..000000000 --- a/frontend/public/locales/tr/mfa.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Kayıt olun", - "og-title": "Tek satır kodla .env dosyalarını değiştirin. 3 dakika içerinde Infisical'a kayıt olun.", - "og-description": "Infisical takımların API anahtarlarını ve ortam değişkenlerini yönetmelerini ve senkronize etmelerini sağlayan basit, uçtan uca şifrelenmiş bir platformdur. Node.js, Next.js, Gatsby, Nest.js ve daha fazlası ile çalışır.", - "signup": "Kayıt ol", - "already-have-account": "Hesabın var mı? Giriş yap", - "forgot-password": "Şifreni mi unuttun?", - "verify": "Doğrula", - "step1-start": "Hadi başlayalım", - "step1-privacy": "Hesap oluşturarak, Şartlarımızı ve Gizlilik Politikasını okuyup kabul etmiş olursunuz.", - "step1-submit": "Başla", - "step2-message": "Şu adrese bir doğrulama maili yolladık", - "step2-code-error": "Tüh. Kodun hatalı. Kalan denemeler:", - "step2-resend-alert": "Kodu ulaşamadı mı?", - "step2-resend-submit": "Tekrar Yolla", - "step2-resend-progress": "Tekrar yollanıyor...", - "step2-spam-alert": "Spam kutunuzu kontrol ettiğinizden emin olun.", - "step3-message": "Çok az kaldı!", - "step4-message": "Acil Durum Kitinizi kayıt edin", - "step4-description1": "Eğer hesabınıza erişemezseniz, Acil Durum Kitiniz giriş yapmanın tek yoludur.", - "step4-description2": "Bunu indirmenizi ve güvenli bir ortamda saklamanızı öneriyoruz.", - "step4-description3": "Kaybetmeniz durumunda bizim dahi erişemeyeceğimiz veya kurtaramayacağımız Gizli Anahtarınızı barındırır.", - "step4-download": "PDF'yi indir", - "step5-send-invites": "Davetleri yolla", - "step5-invite-team": "Takımını davet et", - "step5-subtitle": "Infisical takım arkadaşlarınız ile kullanılmak üzere yapılmıştır. Birlikte test etmek için onları davet edin.", - "step5-skip": "Atla" -} \ No newline at end of file diff --git a/frontend/public/locales/tr/nav.json b/frontend/public/locales/tr/nav.json deleted file mode 100644 index aa6ea2df4..000000000 --- a/frontend/public/locales/tr/nav.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "support": { - "slack": "[YENİ] Slack Foruma katılın", - "docs": "Dokümanları okuyun", - "issue": "Bir Github Issue açın", - "email": "Bize mail yollayın" - }, - "user": { - "signed-in-as": "ŞU HESABA GİRİŞ YAPILDI", - "current-organization": "MEVZUT ORGANİZASYON", - "usage-billing": "Plan & Fiyatlandırma", - "invite": "Üyeleri Davet Et", - "other-organizations": "DİĞER ORGANİZASYONLAR" - }, - "menu": { - "project": "PROJE", - "secrets": "Sırlar", - "members": "Üyeler", - "integrations": "Entegrasyonlar", - "project-settings": "Proje Ayarları" - } -} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-api-key.json b/frontend/public/locales/tr/section-api-key.json deleted file mode 100644 index 0c768ded6..000000000 --- a/frontend/public/locales/tr/section-api-key.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "api-keys": "Servis Belirteçleri", - "api-keys-description": "Her servis belirteci size, belirli bir projeye ve o proje içindeki belirli bir ortama özeldir.", - "add-new": "Yeni Belirteç Ekleyin", - "add-dialog": { - "title": "Bir API Anahtarı Ekleyin", - "description": "Adını ve son kullanma süresini belirleyin. Bir API anahtarı oluşturulduğunda, kaybolmadan önce yalnızca bir kez görebileceksiniz. Bir yere kaydettiğinizden emin olun.", - "name": "API Anahtarı Adı", - "add": "API Anahtarı Ekleyin", - "copy-service-token": "API Anahtarızı kopyalayın", - "copy-service-token-description": "Bu açılır pencereyi kapattığınızda, API anahtarınızı bir daha asla görmeyeceksiniz" - } -} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-incident.json b/frontend/public/locales/tr/section-incident.json deleted file mode 100644 index 776c71c63..000000000 --- a/frontend/public/locales/tr/section-incident.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "incident-contacts": "Özel Durum İletişim Adresleri", - "incident-contacts-description": "Bu adresler olası olmayan ciddi bir olay durumunda bilgilendirilecek.", - "no-incident-contacts": "Hiçbir Özel Durum İletişim Adresi bulunamadı.", - "add-contact": "İletişim Adresi Ekle", - "add-dialog": { - "title": "Bir Özel Durum İletişim Adresi Ekleyin", - "description": "Bu kişi, olası olmayan ciddi bir olay durumunda bilgilendirilecektir..", - "add-incident": "Özel Durum İletişim Adresi Ekle" - } -} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-members.json b/frontend/public/locales/tr/section-members.json deleted file mode 100644 index b4a0c0ec7..000000000 --- a/frontend/public/locales/tr/section-members.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "add-member": "Üye Ekle", - "org-members": "Kuruluş Üyeleri", - "org-members-description": "Kuruluşunuzun üyelerini yönetin. Bu kullanıcılar daha sonra projelere yönlendirilebilir..", - "search-members": "Üyeleri arayın...", - "add-dialog": { - "add-member-to-project": "Projenize bir üye ekleyin", - "already-all-invited": "Kuruluşunuzdaki tüm kullanıcılar zaten davet edildi.", - "add-user-org-first": "Önce kuruluşa daha fazla kullanıcı ekleyin.", - "user-will-email": "Kullanıcı, talimatları içeren bir e-posta alacak.", - "looking-add": "<0>Kuruluşunuza kullanıcı eklemek istiyorsanız,<1>buraya tıklayın", - "add-user-to-org": "Kuruluşa Kullanıcı Ekleyin" - } -} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-password.json b/frontend/public/locales/tr/section-password.json deleted file mode 100644 index 07e26ba58..000000000 --- a/frontend/public/locales/tr/section-password.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "password": "Şifre", - "change": "Şifreyi değiştir", - "current": "Mevcut şifre", - "current-wrong": "Mevcut şifre yanlış olabilir", - "new": "Yeni şifre", - "validate-base": "Şifre en az şunları içermelidir:", - "validate-length": "14 karakter", - "validate-case": "1 küçük harf", - "validate-number": "1 rakam" -} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-token.json b/frontend/public/locales/tr/section-token.json deleted file mode 100644 index aceaba6dd..000000000 --- a/frontend/public/locales/tr/section-token.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "service-tokens": "Servis Belirteçleri", - "service-tokens-description": "Her servis belirteci size, belirli bir projeye ve o proje içindeki belirli bir ortama özeldir.", - "add-new": "Yeni Belirteç Ekle", - "add-dialog": { - "title": "{{target}} için bir servis belirteci ekleyin", - "description": "Adı, ortamı ve son kullanma süresini belirtin. Bir belirteç oluşturulduğunda, onu kaybolmadan önce yalnızca bir kez görebileceksiniz. Bir yere kaydettiğinizden emin olun.", - "name": "Servis Belirteci Adı", - "add": "Servis Belirteci Ekle", - "copy-service-token": "Service belirtecinizi kopyalayın", - "copy-service-token-description": "Bu açılır pencereyi kapattığınızda, servis belirtecinizi bir daha asla göremeyeceksiniz" - } -} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-members.json b/frontend/public/locales/tr/settings-members.json deleted file mode 100644 index c4a7441b7..000000000 --- a/frontend/public/locales/tr/settings-members.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Proje Üyeleri", - "description": "Bu sayfa seçilen projenin üyelerini gösterir." -} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-org.json b/frontend/public/locales/tr/settings-org.json deleted file mode 100644 index 3cc5c0d82..000000000 --- a/frontend/public/locales/tr/settings-org.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Kuruluş Ayarları", - "description": "Kuruluşunuzun üyelerini yönetin. Bu kullanıcılar daha sonra projelere yönlendirilebilir.." -} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-personal.json b/frontend/public/locales/tr/settings-personal.json deleted file mode 100644 index 31c858efb..000000000 --- a/frontend/public/locales/tr/settings-personal.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "title": "Kişisel Ayarlar", - "description": "Kişisel bilgilerinizi burada görüntüleyin ve yönetin.", - "emergency": { - "name": "Acil Durum Kiti", - "text1": "Acil Durum Kitiniz, Infisical hesabınızda oturum açmak için ihtiyaç duyacağınız bilgileri içerir.", - "text2": "Yalnızca en son yayınlanan Acil Durum Kiti geçerliliğini korur. Yeni bir Acil Durum Kiti almak için parolanızı doğrulayın.", - "download": "Acil Durum Kitini İndir" - }, - "change-language": "Dili Değiştir", - "api-keys": { - "title": "API Anahtarları", - "description": "Infisical API'ye erişmek için kişisel API Anahtarlarınızı yönetin", - "add-new": "Ekle yeni" - } -} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-project.json b/frontend/public/locales/tr/settings-project.json deleted file mode 100644 index 41f9f3001..000000000 --- a/frontend/public/locales/tr/settings-project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Proje Ayarları", - "description": "Bu ayarlar yalnızca mevcut seçili projeye uygulanacak.", - "danger-zone": "Tehlikeli Bölge", - "delete-project": "Projeyi Sil", - "project-to-delete": "Silinmek Üzere Olan Proje", - "danger-zone-note": "Bu projeyi sildiğiniz anda geri alamayacaksınız. Bu, tüm anahtarları hemen kaldıracaktır. Bunu hala yapmak istiyorsanız, lütfen aşağıya projenin adını girin.", - "delete-project-note": "Not: Yalnızca birden fazla projeniz olması durumunda, bir projeyi silebilirsiniz.", - "project-id-description": "Infisical'ı kod tabanınıza entegre etmek ve çevresel değişkenlerin otomatik enjeksiyonunu almak için aşağıdaki Proje Kimliğini kullanmalısınız.", - "project-id-description2": "Çeşitli diller ve çerçeveler için kod parçaları da dahil olmak üzere daha fazla rehberlik için bkz.", - "auto-generated": "Bu, projenizin otomatik olarak oluşturulan benzersiz tanımlayıcısıdır. Değiştirilemez..", - "docs": "Infisical Dokümanları" -} \ No newline at end of file diff --git a/frontend/public/locales/tr/signup.json b/frontend/public/locales/tr/signup.json deleted file mode 100644 index 663b6b72b..000000000 --- a/frontend/public/locales/tr/signup.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Kayıt olun", - "og-title": "Tek satır kodla .env dosyalarını değiştirin. 3 dakika içerinde Infisical'a kayıt olun.", - "og-description": "Infisical takımların API anahtarlarını ve ortam değişkenlerini yönetmelerini ve senkronize etmelerini sağlayan basit, uçtan uca şifrelenmiş bir platformdur. Node.js, Next.js, Gatsby, Nest.js ve daha fazlası ile çalışır.", - "signup": "Kayıt ol", - "already-have-account": "Hesabın var mı? Giriş yap", - "forgot-password": "Şifreni mi unuttun?", - "verify": "Doğrula", - "step1-start": "Hadi başlayalım", - "step1-privacy": "Hesap oluşturarak, Şartlarımızı ve Gizlilik Politikasını okuyup kabul etmiş olursunuz.", - "step1-submit": "Başla", - "step2-message": "Şu adrese bir doğrulama maili yolladık", - "step2-code-error": "Tüh. Kodun hatalı. Lütfen tekrar dene.", - "step2-resend-alert": "Kodu ulaşamadı mı?", - "step2-resend-submit": "Tekrar Yolla", - "step2-resend-progress": "Tekrar yollanıyor...", - "step2-spam-alert": "Spam kutunuzu kontrol ettiğinizden emin olun.", - "step3-message": "Çok az kaldı!", - "step4-message": "Acil Durum Kitinizi kayıt edin", - "step4-description1": "Eğer hesabınıza erişemezseniz, Acil Durum Kitiniz giriş yapmanın tek yoludur.", - "step4-description2": "Bunu indirmenizi ve güvenli bir ortamda saklamanızı öneriyoruz.", - "step4-description3": "Kaybetmeniz durumunda bizim dahi erişemeyeceğimiz veya kurtaramayacağımız Gizli Anahtarınızı barındırır.", - "step4-download": "PDF'yi indir", - "step5-send-invites": "Davetleri yolla", - "step5-invite-team": "Takımını davet et", - "step5-subtitle": "Infisical takım arkadaşlarınız ile kullanılmak üzere yapılmıştır. Birlikte test etmek için onları davet edin.", - "step5-skip": "Atla" -} \ No newline at end of file diff --git a/frontend/public/locales/tr/translations.json b/frontend/public/locales/tr/translations.json new file mode 100644 index 000000000..706998495 --- /dev/null +++ b/frontend/public/locales/tr/translations.json @@ -0,0 +1,317 @@ +{ + "activity": { + "title": "Aktivite Günlükleri", + "subtitle": "Bu Infisical projesi için Olay Geçmişi.", + "event": { + "readSecrets": "Sırlar Görüntülendi", + "updateSecrets": "Sırlar Güncellendi", + "addSecrets": "Sırlar Eklendi", + "deleteSecrets": "Sırlar Silindi" + }, + "ip-address": "IP Addresi" + }, + "billing": { + "title": "Planlar & Fiyatlandırma", + "description": "Kuruluşunuzun aboneliğini buradan görüntüleyin ve yönetin", + "subscription": "Abonelik", + "starter": { + "name": "Başlangıç", + "price-explanation": "5 takım üyesine kadar", + "text": "5 kişiyle herhangi bir projeyi ücretsiz yönet!", + "subtext": "Sonrasında aylık her üye başına 5$." + }, + "professional": { + "name": "Profesyonel", + "price-explanation": "/üye/ay", + "subtext": "Sınırsız miktarda üye ve proje dahildir.", + "text": "Anahtar yönetimine siz büyüdükçe ayak uydurun.." + }, + "enterprise": { + "name": "Kurumsal", + "text": "Anahtar yönetimine siz büyüdükçe ayak uydurun." + }, + "current-usage": "Mevcut Plan", + "free": "Ücretsiz", + "downgrade": "Düşürün", + "upgrade": "Yükseltin", + "learn-more": "Daha fazlasını öğrenim", + "custom-pricing": "Özel Fiyatlandırma", + "schedule-demo": "Bir Deneme Sürümü Planlayın " + }, + "common": { + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "Bu isimle bir proje zaten mevcut.", + "no-mobile": " Infisical'ı kullanmak için, lütfen daha büyük boyutlara sahip bir cihaz üzerinden giriş yapın. ", + "email": "Email", + "password": "Şifre", + "first-name": "Adınız", + "last-name": "Soyadınız", + "logout": "Çıkış Yap", + "validate-required": "Lütfen girin, sahip olduğunuz {{name}}", + "maintenance-alert": "Ufak teknik problemler yaşıyoruz. Sorunu çözmek üzere çalışıyoruz. Lütfen birkaç dakika içerisinde yeniden deneyin.", + "click-to-copy": "Kopyala", + "project-id": "Project ID", + "save-changes": "Değişiklikleri Kaydet", + "saved": "Kaydedildi", + "drop-zone": ".env yada .yaml dosyasını buraya sürükleyin", + "drop-zone-keys": "Daha çok anahatar eklemek için bir .env yada .yaml dosyasını sürükleyin.", + "role": "Rol", + "role_admin": "yönetici", + "display-name": "Ekran Adı", + "environment": "Environment", + "expired-in": "Süresi geçicek", + "language": "Dil", + "search": "Ara...", + "note": "Not", + "view-more": "Daha Fazla Göster", + "end-of-history": "Geçmişin Sonu", + "select-event": "Bir olay seçin", + "event": "Olay", + "user": "Kullanıcı", + "source": "Kaynak", + "time": "Zaman", + "timestamp": "Zaman Damgası" + }, + "dashboard": { + "title": "Sırlar", + "og-title": "Saniyeler içerisinde .env dosyalarınızı yönetin", + "og-description": "Infisical takımların .env dosyalarını senkronize etmelerini ve yönetmelerini sağlayan uçtan uca şifrelenmiş basit bir platformdur", + "search-keys": "Anahtarları ara...", + "add-key": "Anahtar Ekle", + "personal": "Kişisel", + "personal-description": "Kişisel anahtarlar sadece sana görünür", + "shared": "Paylaşılan", + "shared-description": "Paylaşılan anahatarlar tüm takımına görünür", + "make-shared": "Paylaşılan Yap", + "make-personal": "Kişisel Yap", + "add-secret": "Yeni bir sır ekle", + "check-docs": { + "button": "Dokümanları Kontrol Et", + "title": "İyi iş!", + "line1": "Tebrikler, yeni anahtarlar eklediniz.", + "line2": "Bunları kendi Codebase' inize nasıl bağlarsınız, işte böyle." + }, + "sidebar": { + "secret": "Sır", + "key": "Anahtar", + "value": "Değer", + "override": "Bu değerin üzerine bir kişisel değer yazın ", + "version-history": "Versiyon Geçmişi", + "comments": "Yorumlar & Notlar", + "personal-explanation": "Bu bir kişisel sır. Herhangi bir takım üyesi ile paylaşılmaz.", + "generate-random-hex": "Rastegele hex oluştur", + "digits": "basamak", + "delete-key-dialog": { + "title": "Anahtarı Sil", + "confirm-delete-message": "Bu sırrı silmek istediğinden emin misin? Bu işlem geri alınamaz." + } + } + }, + "integrations": { + "title": "Proje Entegrasyonları", + "description": "Infisical'ın üçüncü taraf hizmetlerle olan entegrasyonlarınızı yönetin.", + "no-integrations1": "Henüz ayarlanmış bir entegrasyonunuz yok. Oluşturduğunuz zaman, burada görünecekler.", + "no-integrations2": "Başlamak için aşağıdaki seçeneklerden herhangi birine tıklayın. Sadece 5 tıklama ile kurulumu halledin.", + "available": "Platform & Cloud Entegrasyonları", + "available-text1": "Bağlanmak istediğiniz entegrasyona tıklayın. Bu, ortam değişkenlerinizin seçilen üçüncü taraf hizmetlere otomatik olarak akmasını sağlar.", + "available-text2": "Not: Heroku ile entegrasyon sırasında güvenlik nedenleriyle uçtan uca şifrelemenin sürdürülmesi mümkün değildir. Teorik olarak bu, Infisical'ın ortam değişkenlerinin şifresini çözmesine izin verir. Pratikte biz bunun asla yapılmayacağının garantisini verebiliriz ve bu durum sırlarınızı çevrimiçi kötü niyetlilerden korumamıza olanak tanır. Çekirdek Infisical hizmeti her zaman uçtan uca şifreli kalacaktır. Sorularınız için support@infisical.com adresine ulaşın.", + "cloud-integrations": "Cloud Entegrasyonları", + "framework-integrations": "Framework Entegrasyonları", + "click-to-start": "Sırlarınızı senkronize etmeye başlamak için bir entegrasyona tıklayın.", + "click-to-setup": "Kurulum talimatlarını almak için bir frameworke tıklayın.", + "grant-access-to-secrets": "Infisical'a sırlarınıza erişim izni verin", + "why-infisical-needs-access": "Çoğu cloud entegrasyonu, Infisical'ın sırlarınızı aktarabilmek için sırlarınızı deşifre etmesini gerektirir.", + "grant-access-button": "Erişim izni ver" + }, + "login": { + "title": "Giriş Yap", + "og-title": "Infisical'a Giriş Yap", + "og-description": "Infisical ekiplerin .env dosyalarını senkronize etmelerini ve yönetmelerini sağlayan uçtan uca şifrelenmiş basit bir platformdur", + "login": "Giriş Yap", + "need-account": "Bir Infisical hesabına mı ihtiyacınız var?", + "create-account": "Hesap oluşturun", + "forgot-password": "Şifrenizi mi unuttunuz?", + "error-login": "Kimlik bilgileri yanlış." + }, + "mfa": { + "title": "Kayıt olun", + "og-title": "Tek satır kodla .env dosyalarını değiştirin. 3 dakika içerinde Infisical'a kayıt olun.", + "og-description": "Infisical takımların API anahtarlarını ve ortam değişkenlerini yönetmelerini ve senkronize etmelerini sağlayan basit, uçtan uca şifrelenmiş bir platformdur. Node.js, Next.js, Gatsby, Nest.js ve daha fazlası ile çalışır.", + "signup": "Kayıt ol", + "already-have-account": "Hesabın var mı? Giriş yap", + "forgot-password": "Şifreni mi unuttun?", + "verify": "Doğrula", + "step1-start": "Hadi başlayalım", + "step1-privacy": "Hesap oluşturarak, Şartlarımızı ve Gizlilik Politikasını okuyup kabul etmiş olursunuz.", + "step1-submit": "Başla", + "step2-message": "Şu adrese bir doğrulama maili yolladık", + "step2-code-error": "Tüh. Kodun hatalı. Kalan denemeler:", + "step2-resend-alert": "Kodu ulaşamadı mı?", + "step2-resend-submit": "Tekrar Yolla", + "step2-resend-progress": "Tekrar yollanıyor...", + "step2-spam-alert": "Spam kutunuzu kontrol ettiğinizden emin olun.", + "step3-message": "Çok az kaldı!", + "step4-message": "Acil Durum Kitinizi kayıt edin", + "step4-description1": "Eğer hesabınıza erişemezseniz, Acil Durum Kitiniz giriş yapmanın tek yoludur.", + "step4-description2": "Bunu indirmenizi ve güvenli bir ortamda saklamanızı öneriyoruz.", + "step4-description3": "Kaybetmeniz durumunda bizim dahi erişemeyeceğimiz veya kurtaramayacağımız Gizli Anahtarınızı barındırır.", + "step4-download": "PDF'yi indir", + "step5-send-invites": "Davetleri yolla", + "step5-invite-team": "Takımını davet et", + "step5-subtitle": "Infisical takım arkadaşlarınız ile kullanılmak üzere yapılmıştır. Birlikte test etmek için onları davet edin.", + "step5-skip": "Atla" + }, + "nav": { + "support": { + "slack": "[YENİ] Slack Foruma katılın", + "docs": "Dokümanları okuyun", + "issue": "Bir Github Issue açın", + "email": "Bize mail yollayın" + }, + "user": { + "signed-in-as": "ŞU HESABA GİRİŞ YAPILDI", + "current-organization": "MEVZUT ORGANİZASYON", + "usage-billing": "Plan & Fiyatlandırma", + "invite": "Üyeleri Davet Et", + "other-organizations": "DİĞER ORGANİZASYONLAR" + }, + "menu": { + "project": "PROJE", + "secrets": "Sırlar", + "members": "Üyeler", + "integrations": "Entegrasyonlar", + "project-settings": "Proje Ayarları" + } + }, + "section": { + "api-key": { + "api-keys": "Servis Belirteçleri", + "api-keys-description": "Her servis belirteci size, belirli bir projeye ve o proje içindeki belirli bir ortama özeldir.", + "add-new": "Yeni Belirteç Ekleyin", + "add-dialog": { + "title": "Bir API Anahtarı Ekleyin", + "description": "Adını ve son kullanma süresini belirleyin. Bir API anahtarı oluşturulduğunda, kaybolmadan önce yalnızca bir kez görebileceksiniz. Bir yere kaydettiğinizden emin olun.", + "name": "API Anahtarı Adı", + "add": "API Anahtarı Ekleyin", + "copy-service-token": "API Anahtarızı kopyalayın", + "copy-service-token-description": "Bu açılır pencereyi kapattığınızda, API anahtarınızı bir daha asla görmeyeceksiniz" + } + }, + "incident": { + "incident-contacts": "Özel Durum İletişim Adresleri", + "incident-contacts-description": "Bu adresler olası olmayan ciddi bir olay durumunda bilgilendirilecek.", + "no-incident-contacts": "Hiçbir Özel Durum İletişim Adresi bulunamadı.", + "add-contact": "İletişim Adresi Ekle", + "add-dialog": { + "title": "Bir Özel Durum İletişim Adresi Ekleyin", + "description": "Bu kişi, olası olmayan ciddi bir olay durumunda bilgilendirilecektir..", + "add-incident": "Özel Durum İletişim Adresi Ekle" + } + }, + "members": { + "add-member": "Üye Ekle", + "org-members": "Kuruluş Üyeleri", + "org-members-description": "Kuruluşunuzun üyelerini yönetin. Bu kullanıcılar daha sonra projelere yönlendirilebilir..", + "search-members": "Üyeleri arayın...", + "add-dialog": { + "add-member-to-project": "Projenize bir üye ekleyin", + "already-all-invited": "Kuruluşunuzdaki tüm kullanıcılar zaten davet edildi.", + "add-user-org-first": "Önce kuruluşa daha fazla kullanıcı ekleyin.", + "user-will-email": "Kullanıcı, talimatları içeren bir e-posta alacak.", + "looking-add": "<0>Kuruluşunuza kullanıcı eklemek istiyorsanız,<1>buraya tıklayın", + "add-user-to-org": "Kuruluşa Kullanıcı Ekleyin" + } + }, + "password": { + "password": "Şifre", + "change": "Şifreyi değiştir", + "current": "Mevcut şifre", + "current-wrong": "Mevcut şifre yanlış olabilir", + "new": "Yeni şifre", + "validate-base": "Şifre en az şunları içermelidir:", + "validate-length": "14 karakter", + "validate-case": "1 küçük harf", + "validate-number": "1 rakam" + }, + "token": { + "service-tokens": "Servis Belirteçleri", + "service-tokens-description": "Her servis belirteci size, belirli bir projeye ve o proje içindeki belirli bir ortama özeldir.", + "add-new": "Yeni Belirteç Ekle", + "add-dialog": { + "title": "{{target}} için bir servis belirteci ekleyin", + "description": "Adı, ortamı ve son kullanma süresini belirtin. Bir belirteç oluşturulduğunda, onu kaybolmadan önce yalnızca bir kez görebileceksiniz. Bir yere kaydettiğinizden emin olun.", + "name": "Servis Belirteci Adı", + "add": "Servis Belirteci Ekle", + "copy-service-token": "Service belirtecinizi kopyalayın", + "copy-service-token-description": "Bu açılır pencereyi kapattığınızda, servis belirtecinizi bir daha asla göremeyeceksiniz" + } + } + }, + "settings": { + "members": { + "title": "Proje Üyeleri", + "description": "Bu sayfa seçilen projenin üyelerini gösterir." + }, + "org": { + "title": "Kuruluş Ayarları", + "description": "Kuruluşunuzun üyelerini yönetin. Bu kullanıcılar daha sonra projelere yönlendirilebilir.." + }, + "personal": { + "title": "Kişisel Ayarlar", + "description": "Kişisel bilgilerinizi burada görüntüleyin ve yönetin.", + "emergency": { + "name": "Acil Durum Kiti", + "text1": "Acil Durum Kitiniz, Infisical hesabınızda oturum açmak için ihtiyaç duyacağınız bilgileri içerir.", + "text2": "Yalnızca en son yayınlanan Acil Durum Kiti geçerliliğini korur. Yeni bir Acil Durum Kiti almak için parolanızı doğrulayın.", + "download": "Acil Durum Kitini İndir" + }, + "change-language": "Dili Değiştir", + "api-keys": { + "title": "API Anahtarları", + "description": "Infisical API'ye erişmek için kişisel API Anahtarlarınızı yönetin", + "add-new": "Ekle yeni" + } + }, + "project": { + "title": "Proje Ayarları", + "description": "Bu ayarlar yalnızca mevcut seçili projeye uygulanacak.", + "danger-zone": "Tehlikeli Bölge", + "delete-project": "Projeyi Sil", + "project-to-delete": "Silinmek Üzere Olan Proje", + "danger-zone-note": "Bu projeyi sildiğiniz anda geri alamayacaksınız. Bu, tüm anahtarları hemen kaldıracaktır. Bunu hala yapmak istiyorsanız, lütfen aşağıya projenin adını girin.", + "delete-project-note": "Not: Yalnızca birden fazla projeniz olması durumunda, bir projeyi silebilirsiniz.", + "project-id-description": "Infisical'ı kod tabanınıza entegre etmek ve çevresel değişkenlerin otomatik enjeksiyonunu almak için aşağıdaki Proje Kimliğini kullanmalısınız.", + "project-id-description2": "Çeşitli diller ve çerçeveler için kod parçaları da dahil olmak üzere daha fazla rehberlik için bkz.", + "auto-generated": "Bu, projenizin otomatik olarak oluşturulan benzersiz tanımlayıcısıdır. Değiştirilemez..", + "docs": "Infisical Dokümanları" + } + }, + "signup": { + "title": "Kayıt olun", + "og-title": "Tek satır kodla .env dosyalarını değiştirin. 3 dakika içerinde Infisical'a kayıt olun.", + "og-description": "Infisical takımların API anahtarlarını ve ortam değişkenlerini yönetmelerini ve senkronize etmelerini sağlayan basit, uçtan uca şifrelenmiş bir platformdur. Node.js, Next.js, Gatsby, Nest.js ve daha fazlası ile çalışır.", + "signup": "Kayıt ol", + "already-have-account": "Hesabın var mı? Giriş yap", + "forgot-password": "Şifreni mi unuttun?", + "verify": "Doğrula", + "step1-start": "Hadi başlayalım", + "step1-privacy": "Hesap oluşturarak, Şartlarımızı ve Gizlilik Politikasını okuyup kabul etmiş olursunuz.", + "step1-submit": "Başla", + "step2-message": "Şu adrese bir doğrulama maili yolladık", + "step2-code-error": "Tüh. Kodun hatalı. Lütfen tekrar dene.", + "step2-resend-alert": "Kodu ulaşamadı mı?", + "step2-resend-submit": "Tekrar Yolla", + "step2-resend-progress": "Tekrar yollanıyor...", + "step2-spam-alert": "Spam kutunuzu kontrol ettiğinizden emin olun.", + "step3-message": "Çok az kaldı!", + "step4-message": "Acil Durum Kitinizi kayıt edin", + "step4-description1": "Eğer hesabınıza erişemezseniz, Acil Durum Kitiniz giriş yapmanın tek yoludur.", + "step4-description2": "Bunu indirmenizi ve güvenli bir ortamda saklamanızı öneriyoruz.", + "step4-description3": "Kaybetmeniz durumunda bizim dahi erişemeyeceğimiz veya kurtaramayacağımız Gizli Anahtarınızı barındırır.", + "step4-download": "PDF'yi indir", + "step5-send-invites": "Davetleri yolla", + "step5-invite-team": "Takımını davet et", + "step5-subtitle": "Infisical takım arkadaşlarınız ile kullanılmak üzere yapılmıştır. Birlikte test etmek için onları davet edin.", + "step5-skip": "Atla" + } +} diff --git a/frontend/src/components/basic/EventFilter.tsx b/frontend/src/components/basic/EventFilter.tsx index 02a6705c6..7c3a9dc25 100644 --- a/frontend/src/components/basic/EventFilter.tsx +++ b/frontend/src/components/basic/EventFilter.tsx @@ -1,5 +1,5 @@ import React, { Fragment } from 'react'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import { faAngleDown, faEye, @@ -45,16 +45,16 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => { const { t } = useTranslation(); return ( - +
- + {selected !== '' ? ( -

{t(`activity:event.${selected}`)}

+

{t(`activity.event.${selected}`)}

) : ( -

{String(t('common:select-event'))}

+

{String(t('common.select-event'))}

)} {selected !== '' ? ( - select('')} /> + select('')} /> ) : ( )} @@ -65,12 +65,12 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => { leaveFrom="opacity-100" leaveTo="opacity-0" > - + {eventOptions.map((event, id) => ( @@ -79,7 +79,7 @@ const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => { className={`block truncate ${isSelected ? 'font-semibold' : 'font-normal'}`} > {' '} - {t(`activity:event.${event.name}`)} + {t(`activity.event.${event.name}`)} )} diff --git a/frontend/src/components/basic/Layout.tsx b/frontend/src/components/basic/Layout.tsx index 4063df46b..bc97c27cc 100644 --- a/frontend/src/components/basic/Layout.tsx +++ b/frontend/src/components/basic/Layout.tsx @@ -4,9 +4,9 @@ import crypto from 'crypto'; import { useEffect, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import Link from 'next/link'; import { useRouter } from 'next/router'; -import { useTranslation } from 'next-i18next'; import { faBookOpen, faFileLines, @@ -147,17 +147,17 @@ const Layout = ({ children }: LayoutProps) => { () => [ { href: `/dashboard/${workspaceMapping[workspaceSelected as any]}`, - title: t('nav:menu.secrets'), + title: t('nav.menu.secrets'), emoji: }, { href: `/users/${workspaceMapping[workspaceSelected as any]}`, - title: t('nav:menu.members'), + title: t('nav.menu.members'), emoji: }, { href: `/integrations/${workspaceMapping[workspaceSelected as any]}`, - title: t('nav:menu.integrations'), + title: t('nav.menu.integrations'), emoji: }, { @@ -167,7 +167,7 @@ const Layout = ({ children }: LayoutProps) => { }, { href: `/settings/project/${workspaceMapping[workspaceSelected as any]}`, - title: t('nav:menu.project-settings'), + title: t('nav.menu.project-settings'), emoji: } ], @@ -256,7 +256,7 @@ const Layout = ({ children }: LayoutProps) => {
- {t('nav:menu.project')} + {t('nav.menu.project')}
{Object.keys(workspaceMapping).length > 0 ? ( {

- {` ${t('common:no-mobile')} `} + {` ${t('common.no-mobile')} `}

diff --git a/frontend/src/components/basic/dialog/ActivateBotDialog.tsx b/frontend/src/components/basic/dialog/ActivateBotDialog.tsx index 521053d92..4f69f5296 100644 --- a/frontend/src/components/basic/dialog/ActivateBotDialog.tsx +++ b/frontend/src/components/basic/dialog/ActivateBotDialog.tsx @@ -1,5 +1,5 @@ import { Fragment } from 'react'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import { Dialog, Transition } from '@headlessui/react'; import Button from '../buttons/Button'; @@ -34,10 +34,9 @@ const ActivateBotDialog = ({ try { // type check if (!selectedIntegrationOption) return; - + // start integration or probe for PAT integrationOptionPress(selectedIntegrationOption); - } catch (err) { console.log(err); } @@ -71,20 +70,20 @@ const ActivateBotDialog = ({ leaveFrom="opacity-100 scale-100" leaveTo="opacity-0 scale-95" > - + - {t('integrations:grant-access-to-secrets')} + {t('integrations.grant-access-to-secrets')}

- {t('integrations:why-infisical-needs-access')} + {t('integrations.why-infisical-needs-access')}

diff --git a/frontend/src/components/basic/dialog/AddApiKeyDialog.tsx b/frontend/src/components/basic/dialog/AddApiKeyDialog.tsx index 67f0c1f1f..5c2e26246 100644 --- a/frontend/src/components/basic/dialog/AddApiKeyDialog.tsx +++ b/frontend/src/components/basic/dialog/AddApiKeyDialog.tsx @@ -1,5 +1,5 @@ import { Fragment, useState } from 'react'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Dialog, Transition } from '@headlessui/react'; @@ -15,7 +15,7 @@ const expiryMapping = { '7 days': 604800, '1 month': 2592000, '6 months': 15552000, - '12 months': 31104000, + '12 months': 31104000 }; type Props = { @@ -27,12 +27,7 @@ type Props = { }; // TODO: convert to TS -const AddApiKeyDialog = ({ - isOpen, - closeModal, - apiKeys, - setApiKeys, -}: Props) => { +const AddApiKeyDialog = ({ isOpen, closeModal, apiKeys, setApiKeys }: Props) => { const [apiKey, setApiKey] = useState(''); const [apiKeyName, setApiKeyName] = useState(''); const [apiKeyExpiresIn, setApiKeyExpiresIn] = useState('1 day'); @@ -42,7 +37,7 @@ const AddApiKeyDialog = ({ const generateAPIKey = async () => { const newApiKey = await addAPIKey({ name: apiKeyName, - expiresIn: expiryMapping[apiKeyExpiresIn as keyof typeof expiryMapping], + expiresIn: expiryMapping[apiKeyExpiresIn as keyof typeof expiryMapping] }); setApiKeys([...apiKeys, newApiKey.apiKeyData]); @@ -73,143 +68,130 @@ const AddApiKeyDialog = ({ }; return ( -
+
- + -
+
-
-
+
+
{apiKey === '' ? ( - + - {t('section-api-key:add-dialog.title')} + {t('section.api-key.add-dialog.title')} -
-
-

- {t('section-api-key:add-dialog.description')} +

+
+

+ {t('section.api-key.add-dialog.description')}

-
+
-
+
-
-
+
+
) : ( - + - {t('section-api-key:add-dialog.copy-service-token')} + {t('section.api-key.add-dialog.copy-service-token')} -
-
-

- {t( - 'section-api-key:add-dialog.copy-service-token-description' - )} +

+
+

+ {t('section.api-key.add-dialog.copy-service-token-description')}

-
-
+
+
-
+ id="apiKey" + className="invisible w-full min-w-full bg-white/0 py-2 px-2 text-gray-400 outline-none" + /> +
{apiKey}
-
+
- - {t('common:click-to-copy')} + + {t('common.click-to-copy')}
-
+
diff --git a/frontend/src/components/basic/dialog/AddIncidentContactDialog.tsx b/frontend/src/components/basic/dialog/AddIncidentContactDialog.tsx index dddcfa30f..63535f2be 100644 --- a/frontend/src/components/basic/dialog/AddIncidentContactDialog.tsx +++ b/frontend/src/components/basic/dialog/AddIncidentContactDialog.tsx @@ -1,5 +1,5 @@ import { Fragment, useState } from 'react'; -import { useTranslation } from 'next-i18next'; +import { useTranslation } from 'react-i18next'; import { Dialog, Transition } from '@headlessui/react'; import addIncidentContact from '@app/pages/api/organization/addIncidentContact'; @@ -18,7 +18,7 @@ const AddIncidentContactDialog = ({ isOpen, closeModal, incidentContacts, - setIncidentContacts, + setIncidentContacts }: Props) => { const [incidentContactEmail, setIncidentContactEmail] = useState(''); const { t } = useTranslation(); @@ -29,69 +29,61 @@ const AddIncidentContactDialog = ({ ? incidentContacts.concat([incidentContactEmail]) : [incidentContactEmail] ); - addIncidentContact( - localStorage.getItem('orgData.id') as string, - incidentContactEmail - ); + addIncidentContact(localStorage.getItem('orgData.id') as string, incidentContactEmail); closeModal(); }; return (
- + -
+
-
-
+
+
- - - {t('section-incident:add-dialog.title')} + + + {t('section.incident.add-dialog.title')} -
-

- {t('section-incident:add-dialog.description')} +

+

+ {t('section.incident.add-dialog.description')}

-
+
-
+
diff --git a/frontend/src/components/basic/dialog/AddProjectMemberDialog.tsx b/frontend/src/components/basic/dialog/AddProjectMemberDialog.tsx index 43b55cd25..ec3f1a9f5 100644 --- a/frontend/src/components/basic/dialog/AddProjectMemberDialog.tsx +++ b/frontend/src/components/basic/dialog/AddProjectMemberDialog.tsx @@ -1,6 +1,6 @@ import { Fragment } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; import { useRouter } from 'next/router'; -import { Trans, useTranslation } from 'next-i18next'; import { Dialog, Transition } from '@headlessui/react'; import Button from '../buttons/Button'; @@ -21,7 +21,7 @@ const AddProjectMemberDialog = ({ submitModal, data, email, - setEmail, + setEmail }: Props) => { const router = useRouter(); const { t } = useTranslation(); @@ -53,31 +53,31 @@ const AddProjectMemberDialog = ({ leaveFrom="opacity-100 scale-100" leaveTo="opacity-0 scale-95" > - + {data?.length > 0 ? ( - {t('section-members:add-dialog.add-member-to-project')} + {t('section.members.add-dialog.add-member-to-project')} ) : ( - {t('section-members:add-dialog.already-all-invited')} + {t('section.members.add-dialog.already-all-invited')} )}
{data?.length > 0 ? (

- {t('section-members:add-dialog.user-will-email')} + {t('section.members.add-dialog.user-will-email')}

) : (

- {t('section-members:add-dialog.add-user-org-first')} + {t('section.members.add-dialog.add-user-org-first')}

)}
{data?.length > 0 && ( - + )}
{data?.length > 0 ? ( -
+
@@ -124,7 +129,7 @@ const AddProjectMemberDialog = ({
) : ( - + - {t('section-token:add-dialog.copy-service-token')} + {t('section.token.add-dialog.copy-service-token')} -
-
-

- {t( - 'section-token:add-dialog.copy-service-token-description' - )} +

+
+

+ {t('section.token.add-dialog.copy-service-token-description')}

-
-
+
+
-
+ id="serviceToken" + className="invisible w-full min-w-full bg-white/0 py-2 px-2 text-gray-400 outline-none" + /> +
{serviceToken}
-
+
- - {t('common:click-to-copy')} + + {t('common.click-to-copy')}
-
+
diff --git a/frontend/src/components/basic/table/ProjectUsersTable.tsx b/frontend/src/components/basic/table/ProjectUsersTable.tsx index aea49e8e0..c78a6f6c2 100644 --- a/frontend/src/components/basic/table/ProjectUsersTable.tsx +++ b/frontend/src/components/basic/table/ProjectUsersTable.tsx @@ -285,7 +285,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => { >